Magisk/native/jni/core/log_monitor.c

213 lines
4.8 KiB
C
Raw Normal View History

2017-04-04 21:44:13 +02:00
/* log_monitor.c - New thread to monitor logcat
*
* A universal logcat monitor for many usages. Add listeners to the list,
* and the pointer of the new log line will be sent through pipes to trigger
* asynchronous events without polling
2017-04-04 21:44:13 +02:00
*/
#include <stdio.h>
#include <pthread.h>
2017-05-07 21:11:14 +02:00
#include <unistd.h>
2017-06-02 22:31:01 +02:00
#include <sys/wait.h>
2017-04-04 21:44:13 +02:00
2017-04-06 00:12:29 +02:00
#include "magisk.h"
2017-04-04 21:44:13 +02:00
#include "utils.h"
2018-02-11 19:48:15 +01:00
#include "resetprop.h"
2017-11-27 21:43:46 +01:00
extern int is_daemon_init;
2018-04-07 20:12:40 +02:00
int loggable = 1;
static int am_proc_start_filter(const char *log) {
return strstr(log, "am_proc_start") != NULL;
}
static int magisk_log_filter(const char *log) {
char *ss;
return (ss = strstr(log, " Magisk")) && (ss[-1] != 'D') && (ss[-1] != 'V');
}
static int magisk_debug_log_filter(const char *log) {
return strstr(log, "Magisk") != NULL;
}
struct log_listener log_events[] = {
{ /* HIDE_EVENT */
.fd = -1,
.filter = am_proc_start_filter
},
{ /* LOG_EVENT */
.fd = -1,
.filter = magisk_log_filter
},
{ /* DEBUG_EVENT */
.fd = -1,
.filter = magisk_debug_log_filter
}
};
#ifdef MAGISK_DEBUG
2018-02-11 19:48:15 +01:00
static int debug_log_pid = -1, debug_log_fd = -1;
#endif
2017-04-04 21:44:13 +02:00
2018-04-07 20:12:40 +02:00
static void test_logcat() {
int log_fd = -1, log_pid;
char buf[1];
log_pid = exec_command(0, &log_fd, NULL, "logcat", NULL);
if (read(log_fd, buf, sizeof(buf)) != sizeof(buf)) {
loggable = 0;
LOGD("log_monitor: cannot read from logcat, disable logging");
2018-02-11 19:48:15 +01:00
}
2018-04-07 20:12:40 +02:00
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
2018-02-11 19:48:15 +01:00
}
2017-04-04 21:44:13 +02:00
static void *logger_thread(void *args) {
int log_fd = -1, log_pid;
char line[4096];
2017-06-02 22:31:01 +02:00
2017-10-14 15:09:32 +02:00
LOGD("log_monitor: logger start");
2017-06-02 22:31:01 +02:00
while (1) {
2018-04-07 20:12:40 +02:00
if (!loggable) {
2018-02-11 19:48:15 +01:00
// Disable all services
for (int i = 0; i < (sizeof(log_events) / sizeof(struct log_listener)); ++i) {
close(log_events[i].fd);
log_events[i].fd = -1;
}
return NULL;
}
2017-06-02 22:31:01 +02:00
// Start logcat
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "events", "-b", "main", "-v", "threadtime", "-s", "am_proc_start", "-s", "Magisk", NULL);
while (fdgets(line, sizeof(line), log_fd)) {
for (int i = 0; i < (sizeof(log_events) / sizeof(struct log_listener)); ++i) {
if (log_events[i].fd > 0 && log_events[i].filter(line)) {
char *s = strdup(line);
xwrite(log_events[i].fd, &s, sizeof(s));
}
}
if (kill(log_pid, 0))
break;
}
// Cleanup
close(log_fd);
log_fd = -1;
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
// Clear buffer before restart
exec_command_sync("logcat", "-b", "events", "-b", "main", "-c", NULL);
2018-02-11 19:48:15 +01:00
2018-04-07 20:12:40 +02:00
test_logcat();
2017-04-04 21:44:13 +02:00
}
2017-06-02 22:31:01 +02:00
2017-05-07 21:11:14 +02:00
// Should never be here, but well...
2017-04-04 21:44:13 +02:00
return NULL;
}
static void *magisk_log_thread(void *args) {
2017-12-07 16:25:43 +01:00
// Buffer logs before we have data access
struct vector logs;
vec_init(&logs);
int pipefd[2];
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return NULL;
// Register our listener
log_events[LOG_EVENT].fd = pipefd[1];
2017-10-14 15:09:32 +02:00
LOGD("log_monitor: magisk log dumper start");
2017-12-22 21:58:51 +01:00
FILE *log = NULL;
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
2017-12-22 21:58:51 +01:00
if (!is_daemon_init) {
vec_push_back(&logs, strdup(line));
} else {
if (log == NULL) {
// Dump buffered logs to file
log = xfopen(LOGFILE, "w");
setbuf(log, NULL);
char *tmp;
vec_for_each(&logs, tmp) {
fprintf(log, "%s", tmp);
free(tmp);
}
vec_destroy(&logs);
}
fprintf(log, "%s", line);
2017-12-22 21:58:51 +01:00
}
}
return NULL;
}
static void *debug_magisk_log_thread(void *args) {
FILE *log = xfopen(DEBUG_LOG, "a");
setbuf(log, NULL);
int pipefd[2];
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return NULL;
2017-10-14 15:09:32 +02:00
LOGD("log_monitor: debug log dumper start");
// Register our listener
log_events[DEBUG_EVENT].fd = pipefd[1];
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line))
fprintf(log, "%s", line);
return NULL;
}
/* Start new threads to monitor logcat and dump to logfile */
2017-04-04 21:44:13 +02:00
void monitor_logs() {
2017-06-07 21:20:49 +02:00
pthread_t thread;
2018-04-07 20:12:40 +02:00
test_logcat();
2018-04-07 20:12:40 +02:00
if (loggable) {
2018-02-11 19:48:15 +01:00
// Start log file dumper before monitor
xpthread_create(&thread, NULL, magisk_log_thread, NULL);
pthread_detach(thread);
2018-02-11 19:48:15 +01:00
// Start logcat monitor
xpthread_create(&thread, NULL, logger_thread, NULL);
pthread_detach(thread);
}
}
void start_debug_full_log() {
#ifdef MAGISK_DEBUG
2018-04-07 20:12:40 +02:00
if (loggable) {
2018-02-11 19:48:15 +01:00
// Log everything initially
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "threadtime", NULL);
close(debug_log_fd);
}
#endif
}
void stop_debug_full_log() {
#ifdef MAGISK_DEBUG
// Stop recording the boot logcat after every boot task is done
2018-02-11 19:48:15 +01:00
if (debug_log_pid > 0) {
kill(debug_log_pid, SIGTERM);
waitpid(debug_log_pid, NULL, 0);
// Start debug thread
start_debug_log();
}
2017-10-10 13:49:15 +02:00
#endif
}
void start_debug_log() {
#ifdef MAGISK_DEBUG
2018-04-07 20:12:40 +02:00
if (loggable) {
2018-02-11 19:48:15 +01:00
pthread_t thread;
// Start debug thread
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);
pthread_detach(thread);
}
#endif
2017-04-17 10:36:49 +02:00
}