[core] Module log using lspd logcat (#980)
This commit is contained in:
parent
1c73adf4dd
commit
05f8704576
|
|
@ -13,7 +13,5 @@ interface ILSPApplicationService {
|
||||||
|
|
||||||
String getPrefsPath(String packageName);
|
String getPrefsPath(String packageName);
|
||||||
|
|
||||||
ParcelFileDescriptor getModuleLogger();
|
|
||||||
|
|
||||||
Bundle requestRemotePreference(String packageName, int userId, IBinder callback);
|
Bundle requestRemotePreference(String packageName, int userId, IBinder callback);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <inttypes.h>
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "logcat.h"
|
#include "logcat.h"
|
||||||
|
|
||||||
constexpr size_t kMaxLogSize = 32 * 1024 * 1024;
|
constexpr size_t kMaxLogSize = 32 * 1024 * 1024;
|
||||||
|
|
@ -33,30 +32,41 @@ public:
|
||||||
|
|
||||||
class Logcat {
|
class Logcat {
|
||||||
public:
|
public:
|
||||||
explicit Logcat(JNIEnv *env, jobject thiz, jmethodID method, jlong tid) :
|
explicit Logcat(JNIEnv *env, jobject thiz, jmethodID method, jlong tid, jint fd,
|
||||||
env_(env), thiz_(thiz), refresh_fd_method_(method), tid_(tid) {};
|
jboolean verbose) :
|
||||||
|
env_(env), thiz_(thiz), refresh_fd_method_(method), tid_(tid), module_file_(fd, "w"),
|
||||||
|
verbose_(verbose),
|
||||||
|
stop_verbose_inst_("!!stop_verbose!!" + std::to_string(tid_)),
|
||||||
|
start_verbose_inst_("!!start_verbose!!" + std::to_string(tid_)) {}
|
||||||
|
|
||||||
void Run();
|
[[noreturn]] void Run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void RefreshFd();
|
inline void RefreshFd();
|
||||||
|
|
||||||
bool ProcessBuffer(struct log_msg *buf);
|
void ProcessBuffer(struct log_msg *buf);
|
||||||
|
|
||||||
void PrintLogLine(const AndroidLogEntry &entry);
|
static int PrintLogLine(const AndroidLogEntry &entry, FILE *out);
|
||||||
|
|
||||||
JNIEnv *env_;
|
JNIEnv *env_;
|
||||||
jobject thiz_;
|
jobject thiz_;
|
||||||
jmethodID refresh_fd_method_;
|
jmethodID refresh_fd_method_;
|
||||||
jlong tid_;
|
jlong tid_;
|
||||||
|
UniqueFile module_file_{};
|
||||||
|
size_t module_count_ = 0;
|
||||||
|
|
||||||
UniqueFile out_file_{};
|
UniqueFile out_file_{};
|
||||||
size_t print_count_ = 0;
|
size_t print_count_ = 0;
|
||||||
size_t file_count_ = 1;
|
size_t file_count_ = 1;
|
||||||
|
|
||||||
|
bool verbose_ = true;
|
||||||
|
|
||||||
|
const std::string stop_verbose_inst_;
|
||||||
|
const std::string start_verbose_inst_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Logcat::PrintLogLine(const AndroidLogEntry &entry) {
|
int Logcat::PrintLogLine(const AndroidLogEntry &entry, FILE *out) {
|
||||||
if (!out_file_) return;
|
if (!out) return 0;
|
||||||
constexpr static size_t kMaxTimeBuff = 64;
|
constexpr static size_t kMaxTimeBuff = 64;
|
||||||
struct tm tm{};
|
struct tm tm{};
|
||||||
std::array<char, kMaxTimeBuff> time_buff;
|
std::array<char, kMaxTimeBuff> time_buff;
|
||||||
|
|
@ -73,13 +83,12 @@ void Logcat::PrintLogLine(const AndroidLogEntry &entry) {
|
||||||
}
|
}
|
||||||
localtime_r(&now, &tm);
|
localtime_r(&now, &tm);
|
||||||
strftime(time_buff.data(), time_buff.size(), "%Y-%m-%dT%H:%M:%S", &tm);
|
strftime(time_buff.data(), time_buff.size(), "%Y-%m-%dT%H:%M:%S", &tm);
|
||||||
print_count_ +=
|
return fprintf(out, "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
|
||||||
fprintf(out_file_.get(), "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
|
time_buff.data(),
|
||||||
time_buff.data(),
|
nsec / MS_PER_NSEC,
|
||||||
nsec / MS_PER_NSEC,
|
entry.uid, entry.pid, entry.tid,
|
||||||
entry.uid, entry.pid, entry.tid,
|
kLogChar[entry.priority], static_cast<int>(entry.tagLen),
|
||||||
kLogChar[entry.priority], static_cast<int>(entry.tagLen),
|
entry.tag, static_cast<int>(message_len), message);
|
||||||
entry.tag, static_cast<int>(message_len), message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logcat::RefreshFd() {
|
void Logcat::RefreshFd() {
|
||||||
|
|
@ -89,21 +98,26 @@ void Logcat::RefreshFd() {
|
||||||
file_count_++;
|
file_count_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logcat::ProcessBuffer(struct log_msg *buf) {
|
void Logcat::ProcessBuffer(struct log_msg *buf) {
|
||||||
AndroidLogEntry entry;
|
AndroidLogEntry entry;
|
||||||
if (android_log_processLogBuffer(&buf->entry, &entry) < 0) return false;
|
if (android_log_processLogBuffer(&buf->entry, &entry) < 0) return;
|
||||||
|
|
||||||
std::string_view tag(entry.tag);
|
std::string_view tag(entry.tag);
|
||||||
if (buf->id() == log_id::LOG_ID_CRASH ||
|
bool skip = false;
|
||||||
tag == "Magisk" ||
|
if (tag == "LSPosed-Bridge" || tag == "XSharedPreferences") [[unlikely]] {
|
||||||
tag.starts_with("Riru") ||
|
module_count_ += PrintLogLine(entry, module_file_.get());
|
||||||
tag.starts_with("LSPosed") ||
|
skip = true;
|
||||||
tag == "XSharedPreferences") {
|
}
|
||||||
PrintLogLine(entry);
|
if (verbose_ && (skip || buf->id() == log_id::LOG_ID_CRASH ||
|
||||||
|
tag == "Magisk" ||
|
||||||
|
tag.starts_with("Riru") ||
|
||||||
|
tag.starts_with("LSPosed"))) [[unlikely]] {
|
||||||
|
print_count_ += PrintLogLine(entry, out_file_.get());
|
||||||
|
}
|
||||||
|
if (entry.pid == getpid() && tag == "LSPosedLogcat") [[unlikely]] {
|
||||||
|
if (std::string_view(entry.message) == stop_verbose_inst_) verbose_ = false;
|
||||||
|
if (std::string_view(entry.message) == start_verbose_inst_) verbose_ = true;
|
||||||
}
|
}
|
||||||
return entry.pid == getpid() &&
|
|
||||||
tag == "LSPosedLogcat" &&
|
|
||||||
std::string_view(entry.message) == "!!stop!!" + std::to_string(tid_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logcat::Run() {
|
void Logcat::Run() {
|
||||||
|
|
@ -128,13 +142,19 @@ void Logcat::Run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (android_logger_list_read(logger_list.get(), &msg) <= 0) [[unlikely]] break;
|
if (android_logger_list_read(logger_list.get(), &msg) <= 0) [[unlikely]] break;
|
||||||
|
|
||||||
if (ProcessBuffer(&msg)) [[unlikely]] return;
|
ProcessBuffer(&msg);
|
||||||
|
|
||||||
fflush(out_file_.get());
|
fflush(out_file_.get());
|
||||||
|
fflush(module_file_.get());
|
||||||
|
|
||||||
if (print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd();
|
if (print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd();
|
||||||
|
if (module_count_ >= kMaxLogSize) [[unlikely]] {
|
||||||
|
ftruncate(fileno(module_file_.get()), 0);
|
||||||
|
module_count_ = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fprintf(out_file_.get(), "\nLogd maybe crashed, retrying in %" PRId64 "-%zu file after 1s\n",
|
fprintf(out_file_.get(),
|
||||||
|
"\nLogd maybe crashed, retrying in %" PRId64 "-%zu file after 1s\n",
|
||||||
tid_, file_count_ + 1);
|
tid_, file_count_ + 1);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
@ -143,9 +163,10 @@ void Logcat::Run() {
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
Java_org_lsposed_lspd_service_LogcatService_runLogcat(JNIEnv *env, jobject thiz, jlong tid) {
|
Java_org_lsposed_lspd_service_LogcatService_runLogcat(JNIEnv *env, jobject thiz, jlong tid,
|
||||||
|
jint fd, jboolean verbose) {
|
||||||
jclass clazz = env->GetObjectClass(thiz);
|
jclass clazz = env->GetObjectClass(thiz);
|
||||||
jmethodID method = env->GetMethodID(clazz, "refreshFd", "()I");
|
jmethodID method = env->GetMethodID(clazz, "refreshFd", "()I");
|
||||||
Logcat logcat(env, thiz, method, tid);
|
Logcat logcat(env, thiz, method, tid, fd, verbose);
|
||||||
logcat.Run();
|
logcat.Run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import android.util.Log;
|
||||||
|
|
||||||
import org.lsposed.lspd.BuildConfig;
|
import org.lsposed.lspd.BuildConfig;
|
||||||
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
import org.lsposed.lspd.nativebridge.ResourcesHook;
|
||||||
import org.lsposed.lspd.util.ModuleLogger;
|
|
||||||
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
||||||
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
|
|
@ -133,7 +132,6 @@ public final class XposedBridge {
|
||||||
*/
|
*/
|
||||||
public synchronized static void log(String text) {
|
public synchronized static void log(String text) {
|
||||||
Log.i(TAG, text);
|
Log.i(TAG, text);
|
||||||
ModuleLogger.log(text, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,7 +145,6 @@ public final class XposedBridge {
|
||||||
public synchronized static void log(Throwable t) {
|
public synchronized static void log(Throwable t) {
|
||||||
String logStr = Log.getStackTraceString(t);
|
String logStr = Log.getStackTraceString(t);
|
||||||
Log.e(TAG, logStr);
|
Log.e(TAG, logStr);
|
||||||
ModuleLogger.log(logStr, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,4 @@ abstract public class ApplicationServiceClient implements ILSPApplicationService
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
abstract public String getPrefsPath(String packageName);
|
abstract public String getPrefsPath(String packageName);
|
||||||
|
|
||||||
@Override
|
|
||||||
abstract public ParcelFileDescriptor getModuleLogger();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,15 +109,6 @@ public class LSPApplicationServiceClient extends ApplicationServiceClient {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParcelFileDescriptor getModuleLogger() {
|
|
||||||
try {
|
|
||||||
return service.getModuleLogger();
|
|
||||||
} catch (RemoteException | NullPointerException ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle requestRemotePreference(String packageName, int userId, IBinder callback) throws RemoteException {
|
public Bundle requestRemotePreference(String packageName, int userId, IBinder callback) throws RemoteException {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ import org.lsposed.lspd.hooker.HandleBindAppHooker;
|
||||||
import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
|
import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
|
||||||
import org.lsposed.lspd.hooker.SystemMainHooker;
|
import org.lsposed.lspd.hooker.SystemMainHooker;
|
||||||
import org.lsposed.lspd.service.ServiceManager;
|
import org.lsposed.lspd.service.ServiceManager;
|
||||||
import org.lsposed.lspd.util.ModuleLogger;
|
|
||||||
import org.lsposed.lspd.util.Utils;
|
import org.lsposed.lspd.util.Utils;
|
||||||
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
||||||
|
|
||||||
|
|
@ -79,7 +78,6 @@ public class Main {
|
||||||
public static void forkPostCommon(boolean isSystem, String appDataDir, String niceName) {
|
public static void forkPostCommon(boolean isSystem, String appDataDir, String niceName) {
|
||||||
// init logger
|
// init logger
|
||||||
YahfaHooker.init();
|
YahfaHooker.init();
|
||||||
ModuleLogger.initLogger(serviceClient.getModuleLogger());
|
|
||||||
XposedBridge.initXResources();
|
XposedBridge.initXResources();
|
||||||
XposedInit.startsSystemServer = isSystem;
|
XposedInit.startsSystemServer = isSystem;
|
||||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import static org.lsposed.lspd.service.PackageService.MATCH_ALL_FLAGS;
|
||||||
import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE;
|
import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE;
|
||||||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
import static org.lsposed.lspd.service.ServiceManager.existsInGlobalNamespace;
|
import static org.lsposed.lspd.service.ServiceManager.existsInGlobalNamespace;
|
||||||
|
import static org.lsposed.lspd.service.ServiceManager.getLogcatService;
|
||||||
import static org.lsposed.lspd.service.ServiceManager.toGlobalNamespace;
|
import static org.lsposed.lspd.service.ServiceManager.toGlobalNamespace;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
|
@ -106,8 +107,6 @@ public class ConfigManager {
|
||||||
private String miscPath = null;
|
private String miscPath = null;
|
||||||
|
|
||||||
private static final File logPath = new File(basePath, "log");
|
private static final File logPath = new File(basePath, "log");
|
||||||
private static final File modulesLog = new File(logPath, "modules.txt");
|
|
||||||
private static final File oldModulesLog = new File(logPath, "modules.old.txt");
|
|
||||||
|
|
||||||
static class FileLocker {
|
static class FileLocker {
|
||||||
private final FileChannel lockChannel;
|
private final FileChannel lockChannel;
|
||||||
|
|
@ -890,12 +889,9 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParcelFileDescriptor getModulesLog(int mode) {
|
public ParcelFileDescriptor getModulesLog(int mode) {
|
||||||
|
var modulesLog = getLogcatService().getModulesLog();
|
||||||
try {
|
try {
|
||||||
if (modulesLog.length() > 16 * 1024 * 1024) {
|
return ParcelFileDescriptor.open(modulesLog, mode);
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
modulesLog.renameTo(oldModulesLog);
|
|
||||||
}
|
|
||||||
return ParcelFileDescriptor.open(modulesLog, mode | ParcelFileDescriptor.MODE_CREATE);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -916,8 +912,9 @@ public class ConfigManager {
|
||||||
public boolean clearLogs(boolean verbose) {
|
public boolean clearLogs(boolean verbose) {
|
||||||
try {
|
try {
|
||||||
var logcat = ServiceManager.getLogcatService().getLog();
|
var logcat = ServiceManager.getLogcatService().getLog();
|
||||||
|
var moduleLog = ServiceManager.getLogcatService().getModulesLog();
|
||||||
if (verbose && logcat == null) return true;
|
if (verbose && logcat == null) return true;
|
||||||
OutputStream os = new FileOutputStream(verbose ? logcat : modulesLog);
|
OutputStream os = new FileOutputStream(verbose ? logcat : moduleLog);
|
||||||
os.close();
|
os.close();
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,6 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
return ConfigManager.getInstance().getPrefsPath(packageName, getCallingUid());
|
return ConfigManager.getInstance().getPrefsPath(packageName, getCallingUid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParcelFileDescriptor getModuleLogger() throws RemoteException {
|
|
||||||
ensureRegistered();
|
|
||||||
return ConfigManager.getInstance().getModulesLog(ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle requestRemotePreference(String packageName, int userId, IBinder callback) throws RemoteException {
|
public Bundle requestRemotePreference(String packageName, int userId, IBinder callback) throws RemoteException {
|
||||||
ensureRegistered();
|
ensureRegistered();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.lsposed.lspd.util.Utils;
|
import org.lsposed.lspd.util.Utils;
|
||||||
|
|
@ -15,34 +16,43 @@ import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
public class LogcatService implements Runnable {
|
public class LogcatService implements Runnable {
|
||||||
private static final String TAG = "LSPosedLogcat";
|
private static final String TAG = "LSPosedLogcat";
|
||||||
|
private static final int mode = ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE |
|
||||||
|
ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_APPEND;
|
||||||
|
public final File modulesLog;
|
||||||
private final File logPath;
|
private final File logPath;
|
||||||
private final DateTimeFormatter logTimeFormat;
|
private final DateTimeFormatter logTimeFormat;
|
||||||
private File log = null;
|
private File log = null;
|
||||||
private Thread thread = null;
|
private Thread thread = null;
|
||||||
|
boolean verboseLog = true;
|
||||||
|
|
||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
public LogcatService(File logPath) {
|
public LogcatService(File logPath) {
|
||||||
String libraryPath = System.getProperty("lsp.library.path");
|
String libraryPath = System.getProperty("lsp.library.path");
|
||||||
System.load(libraryPath + "/" + System.mapLibraryName("daemon"));
|
System.load(libraryPath + "/" + System.mapLibraryName("daemon"));
|
||||||
this.logPath = logPath;
|
this.logPath = logPath;
|
||||||
|
modulesLog = new File(logPath, "module.log");
|
||||||
logTimeFormat = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(Utils.getZoneId());
|
logTimeFormat = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(Utils.getZoneId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.i(TAG, "start running");
|
Log.i(TAG, "start running");
|
||||||
runLogcat(thread.getId());
|
int moduleFd = -1;
|
||||||
|
try (var fd = ParcelFileDescriptor.open(modulesLog, mode)) {
|
||||||
|
moduleFd = fd.detachFd();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "someone chattr +i ?", e);
|
||||||
|
}
|
||||||
|
runLogcat(thread.getId(), moduleFd, verboseLog);
|
||||||
Log.i(TAG, "stoped");
|
Log.i(TAG, "stoped");
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void runLogcat(long tid);
|
private native void runLogcat(long tid, int fd, boolean verboseLog);
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private int refreshFd() {
|
private int refreshFd() {
|
||||||
log = new File(logPath, logTimeFormat.format(Instant.now()) + ".log");
|
log = new File(logPath, logTimeFormat.format(Instant.now()) + ".log");
|
||||||
|
|
||||||
var mode = ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE |
|
|
||||||
ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_APPEND;
|
|
||||||
try (var fd = ParcelFileDescriptor.open(log, mode)) {
|
try (var fd = ParcelFileDescriptor.open(log, mode)) {
|
||||||
return fd.detachFd();
|
return fd.detachFd();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -52,19 +62,21 @@ public class LogcatService implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
|
if (thread != null) Log.i(TAG, "!!start_verbose!!" + thread.getId());
|
||||||
if (isRunning()) return;
|
if (isRunning()) return;
|
||||||
thread = new Thread(this);
|
thread = new Thread(this);
|
||||||
thread.setName("logcat");
|
thread.setName("logcat");
|
||||||
thread.setUncaughtExceptionHandler((t, e) -> {
|
thread.setUncaughtExceptionHandler((t, e) -> {
|
||||||
Log.e(TAG, "Crash unexpectedly: ", e);
|
Log.e(TAG, "Crash unexpectedly: ", e);
|
||||||
thread = null;
|
thread = null;
|
||||||
|
start();
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
// logcat thread is listening for this keyword
|
// logcat thread is listening for this keyword
|
||||||
Log.i(TAG, "!!stop!!" + thread.getId());
|
Log.i(TAG, "!!stop_verbose!!" + thread.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
|
|
@ -75,4 +87,9 @@ public class LogcatService implements Runnable {
|
||||||
public File getLog() {
|
public File getLog() {
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public File getModulesLog() {
|
||||||
|
return modulesLog;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.lspd.util;
|
|
||||||
|
|
||||||
import android.app.ActivityThread;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.os.Process;
|
|
||||||
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class ModuleLogger {
|
|
||||||
private static DateTimeFormatter logDateFormat;
|
|
||||||
private static ParcelFileDescriptor fd = null;
|
|
||||||
|
|
||||||
public static void initLogger(ParcelFileDescriptor fileDescriptor) {
|
|
||||||
if (fd == null && fileDescriptor != null) {
|
|
||||||
fd = fileDescriptor;
|
|
||||||
var zone = Utils.getZoneId();
|
|
||||||
var pattern = "uuuu-MM-dd'T'HH:mm:ss.SSS"; // DateTimeFormatter.ISO_LOCAL_DATE_TIME
|
|
||||||
logDateFormat = DateTimeFormatter.ofPattern(pattern, Locale.ROOT).withZone(zone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(String str, boolean isThrowable) {
|
|
||||||
if (fd == null) {
|
|
||||||
Utils.logE("Logger is not initialized");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String processName = ActivityThread.currentProcessName();
|
|
||||||
var log = String.format(Locale.ROOT, "[ %s %5d:%5d:%5d %c/%s ] %s\n",
|
|
||||||
logDateFormat.format(Instant.now()),
|
|
||||||
Process.myUid(),
|
|
||||||
Process.myPid(),
|
|
||||||
Process.myTid(),
|
|
||||||
isThrowable ? 'E' : 'I',
|
|
||||||
processName == null ? "android" : processName,
|
|
||||||
str);
|
|
||||||
try {
|
|
||||||
var writer = new FileWriter(fd.getFileDescriptor());
|
|
||||||
writer.write(log, 0, log.length());
|
|
||||||
writer.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Utils.logE("Unable to write to module log file", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue