2018-07-06 07:57:18 +08:00
|
|
|
/* log_daemon.c - A dedicated daemon to monitor logcat
|
2017-04-05 03:44:13 +08:00
|
|
|
*
|
2017-10-09 05:05:52 +08:00
|
|
|
* A universal logcat monitor for many usages. Add listeners to the list,
|
2018-07-06 07:57:18 +08:00
|
|
|
* and the new log line will be sent through sockets to trigger
|
2017-10-09 05:05:52 +08:00
|
|
|
* asynchronous events without polling
|
2017-04-05 03:44:13 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <pthread.h>
|
2017-05-08 03:11:14 +08:00
|
|
|
#include <unistd.h>
|
2018-09-27 03:11:10 -04:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2017-06-03 04:31:01 +08:00
|
|
|
#include <sys/wait.h>
|
2018-07-01 18:18:12 +08:00
|
|
|
#include <fcntl.h>
|
2019-01-19 23:59:37 -05:00
|
|
|
#include <vector>
|
2017-04-05 03:44:13 +08:00
|
|
|
|
2017-04-06 06:12:29 +08:00
|
|
|
#include "magisk.h"
|
2017-04-05 03:44:13 +08:00
|
|
|
#include "utils.h"
|
2018-07-02 22:11:28 +08:00
|
|
|
#include "daemon.h"
|
2018-09-27 03:56:56 -04:00
|
|
|
#include "flags.h"
|
2017-10-09 05:05:52 +08:00
|
|
|
|
2019-01-19 23:59:37 -05:00
|
|
|
using namespace std;
|
|
|
|
|
2018-11-04 17:23:08 -05:00
|
|
|
bool log_daemon_started = false;
|
2019-01-19 23:59:37 -05:00
|
|
|
static vector<const char *> log_cmd, clear_cmd;
|
2018-07-02 22:11:28 +08:00
|
|
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
HIDE_EVENT,
|
2018-07-02 22:48:26 +08:00
|
|
|
LOG_EVENT
|
2018-07-02 22:11:28 +08:00
|
|
|
};
|
|
|
|
|
2018-11-04 17:23:08 -05:00
|
|
|
#define EVENT_NUM 2
|
|
|
|
|
2018-07-02 22:11:28 +08:00
|
|
|
struct log_listener {
|
|
|
|
int fd;
|
2018-11-04 17:23:08 -05:00
|
|
|
bool (*filter)(const char *);
|
2018-07-02 22:11:28 +08:00
|
|
|
};
|
2017-10-09 05:05:52 +08:00
|
|
|
|
2018-11-04 17:23:08 -05:00
|
|
|
static bool am_proc_start_filter(const char *log) {
|
2018-11-04 03:38:06 -05:00
|
|
|
return strstr(log, "am_proc_start") != nullptr;
|
2017-12-18 18:17:37 +08:00
|
|
|
}
|
|
|
|
|
2018-11-04 17:23:08 -05:00
|
|
|
static bool magisk_log_filter(const char *log) {
|
2018-07-02 22:48:26 +08:00
|
|
|
return !am_proc_start_filter(log);
|
2017-12-18 18:17:37 +08:00
|
|
|
}
|
|
|
|
|
2018-07-03 22:25:39 +08:00
|
|
|
static struct log_listener events[] = {
|
2017-12-18 18:17:37 +08:00
|
|
|
{ /* HIDE_EVENT */
|
|
|
|
.fd = -1,
|
|
|
|
.filter = am_proc_start_filter
|
|
|
|
},
|
|
|
|
{ /* LOG_EVENT */
|
|
|
|
.fd = -1,
|
|
|
|
.filter = magisk_log_filter
|
|
|
|
}
|
|
|
|
};
|
2017-04-05 03:44:13 +08:00
|
|
|
|
2018-11-04 03:38:06 -05:00
|
|
|
static void sigpipe_handler(int) {
|
2018-07-03 22:25:39 +08:00
|
|
|
close(events[HIDE_EVENT].fd);
|
|
|
|
events[HIDE_EVENT].fd = -1;
|
2018-07-02 22:11:28 +08:00
|
|
|
}
|
|
|
|
|
2018-11-04 03:38:06 -05:00
|
|
|
static void *monitor_thread(void *) {
|
2018-07-03 01:38:19 +08:00
|
|
|
// Block SIGPIPE to prevent interruption
|
|
|
|
sigset_t block_set;
|
|
|
|
sigemptyset(&block_set);
|
|
|
|
sigaddset(&block_set, SIGPIPE);
|
2018-11-04 03:38:06 -05:00
|
|
|
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
2018-07-03 01:38:19 +08:00
|
|
|
// Give the main daemon some time before we monitor it
|
|
|
|
sleep(5);
|
|
|
|
int fd;
|
2018-07-06 07:32:16 +08:00
|
|
|
char b;
|
2019-01-19 23:59:37 -05:00
|
|
|
while (true) {
|
2018-07-03 01:38:19 +08:00
|
|
|
fd = connect_daemon();
|
2018-07-06 07:51:17 +08:00
|
|
|
write_int(fd, HANDSHAKE);
|
2018-07-03 01:38:19 +08:00
|
|
|
// This should hold unless the daemon is killed
|
2018-07-06 07:32:16 +08:00
|
|
|
read(fd, &b, sizeof(b));
|
2018-07-03 01:38:19 +08:00
|
|
|
// The main daemon crashed, spawn a new one
|
|
|
|
close(fd);
|
2018-07-06 07:51:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-04 03:38:06 -05:00
|
|
|
static void *logcat_thread(void *) {
|
2019-01-26 13:00:19 -05:00
|
|
|
int log_pid;
|
2018-07-06 07:51:17 +08:00
|
|
|
char line[4096];
|
2019-01-26 13:00:19 -05:00
|
|
|
while (true) {
|
2018-07-06 07:51:17 +08:00
|
|
|
// Start logcat
|
2019-01-26 13:00:19 -05:00
|
|
|
exec_t exec {
|
|
|
|
.fd = -1,
|
|
|
|
.argv = log_cmd.data()
|
|
|
|
};
|
|
|
|
log_pid = exec_command(exec);
|
|
|
|
FILE *logs = fdopen(exec.fd, "r");
|
2018-07-06 07:51:17 +08:00
|
|
|
while (fgets(line, sizeof(line), logs)) {
|
|
|
|
if (line[0] == '-')
|
|
|
|
continue;
|
|
|
|
size_t len = strlen(line);
|
|
|
|
pthread_mutex_lock(&lock);
|
2019-01-26 13:00:19 -05:00
|
|
|
for (auto &event : events) {
|
|
|
|
if (event.fd > 0 && event.filter(line))
|
|
|
|
write(event.fd, line, len);
|
2018-07-06 07:51:17 +08:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(logs);
|
|
|
|
kill(log_pid, SIGTERM);
|
2018-11-04 03:38:06 -05:00
|
|
|
waitpid(log_pid, nullptr, 0);
|
2018-07-06 07:51:17 +08:00
|
|
|
|
|
|
|
LOGI("magisklogd: logcat output EOF");
|
|
|
|
// Clear buffer
|
2019-01-26 13:00:19 -05:00
|
|
|
exec_command_sync(clear_cmd.data());
|
2018-07-06 07:51:17 +08:00
|
|
|
}
|
2018-07-03 01:38:19 +08:00
|
|
|
}
|
|
|
|
|
2018-10-12 00:50:47 -04:00
|
|
|
static void log_daemon() {
|
2018-07-02 22:11:28 +08:00
|
|
|
setsid();
|
|
|
|
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n");
|
2018-07-03 22:25:39 +08:00
|
|
|
strcpy(argv0, "magisklogd");
|
2018-07-02 22:11:28 +08:00
|
|
|
|
2018-07-03 01:38:19 +08:00
|
|
|
// Set SIGPIPE handler
|
2018-07-02 22:11:28 +08:00
|
|
|
struct sigaction act;
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
act.sa_handler = sigpipe_handler;
|
2018-11-04 03:38:06 -05:00
|
|
|
sigaction(SIGPIPE, &act, nullptr);
|
2018-07-02 22:11:28 +08:00
|
|
|
|
|
|
|
// Setup log dumps
|
|
|
|
rename(LOGFILE, LOGFILE ".bak");
|
2018-07-04 23:46:40 +08:00
|
|
|
events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC | O_APPEND, 0644);
|
2018-07-02 22:11:28 +08:00
|
|
|
|
2018-07-06 07:32:16 +08:00
|
|
|
// Construct cmdline
|
2018-11-04 03:38:06 -05:00
|
|
|
log_cmd.push_back(MIRRDIR "/system/bin/logcat");
|
2018-07-06 07:32:16 +08:00
|
|
|
// Test whether these buffers actually works
|
2018-11-04 17:23:08 -05:00
|
|
|
const char *b[] = { "main", "events", "crash" };
|
2019-01-26 13:00:19 -05:00
|
|
|
for (auto &buffer : b) {
|
2019-01-26 13:39:24 -05:00
|
|
|
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", buffer, "-d", "-f", "/dev/null") == 0) {
|
2018-11-04 03:38:06 -05:00
|
|
|
log_cmd.push_back("-b");
|
2019-01-26 13:00:19 -05:00
|
|
|
log_cmd.push_back(buffer);
|
2018-11-04 03:38:06 -05:00
|
|
|
}
|
2018-07-06 07:32:16 +08:00
|
|
|
}
|
2018-07-16 06:42:36 +08:00
|
|
|
chmod("/dev/null", 0666);
|
2018-11-04 03:38:06 -05:00
|
|
|
clear_cmd = log_cmd;
|
2019-01-19 23:59:37 -05:00
|
|
|
log_cmd.insert(log_cmd.end(), { "-v", "threadtime", "-s", "am_proc_start", "Magisk" });
|
2018-07-18 03:25:36 +08:00
|
|
|
#ifdef MAGISK_DEBUG
|
2018-11-04 03:38:06 -05:00
|
|
|
log_cmd.push_back("*:F");
|
2018-07-18 03:25:36 +08:00
|
|
|
#endif
|
2018-11-04 03:38:06 -05:00
|
|
|
log_cmd.push_back(nullptr);
|
|
|
|
|
|
|
|
clear_cmd.push_back("-c");
|
|
|
|
clear_cmd.push_back(nullptr);
|
2018-07-06 07:32:16 +08:00
|
|
|
|
2018-07-06 07:51:17 +08:00
|
|
|
// Start worker threads
|
|
|
|
pthread_t thread;
|
2018-11-04 03:38:06 -05:00
|
|
|
pthread_create(&thread, nullptr, monitor_thread, nullptr);
|
2018-07-06 07:51:17 +08:00
|
|
|
pthread_detach(thread);
|
2018-11-04 03:38:06 -05:00
|
|
|
xpthread_create(&thread, nullptr, logcat_thread, nullptr);
|
2018-07-06 07:51:17 +08:00
|
|
|
pthread_detach(thread);
|
2017-06-03 04:31:01 +08:00
|
|
|
|
2018-10-28 04:24:53 -04:00
|
|
|
// Handle socket requests
|
|
|
|
struct sockaddr_un sun;
|
|
|
|
socklen_t len = setup_sockaddr(&sun, LOG_SOCKET);
|
|
|
|
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
if (xbind(sockfd, (struct sockaddr*) &sun, len))
|
|
|
|
exit(1);
|
|
|
|
xlisten(sockfd, 10);
|
2019-01-19 23:59:37 -05:00
|
|
|
while(true) {
|
2018-11-04 03:38:06 -05:00
|
|
|
int fd = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
2019-02-09 15:02:46 -05:00
|
|
|
struct ucred credential;
|
|
|
|
get_client_cred(fd, &credential);
|
|
|
|
if (credential.uid != 0) {
|
|
|
|
// Do not allow non root clients
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
2018-07-06 07:51:17 +08:00
|
|
|
switch(read_int(fd)) {
|
|
|
|
case HIDE_CONNECT:
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
close(events[HIDE_EVENT].fd);
|
|
|
|
events[HIDE_EVENT].fd = fd;
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
break;
|
2018-10-28 04:24:53 -04:00
|
|
|
case HANDSHAKE:
|
|
|
|
write_int(fd, HANDSHAKE);
|
2018-07-06 07:51:17 +08:00
|
|
|
default:
|
|
|
|
close(fd);
|
2017-10-09 05:05:52 +08:00
|
|
|
}
|
2018-02-12 02:48:15 +08:00
|
|
|
}
|
2017-04-17 16:36:49 +08:00
|
|
|
}
|
2018-10-12 00:50:47 -04:00
|
|
|
|
2018-11-04 17:23:08 -05:00
|
|
|
bool start_log_daemon() {
|
2018-10-12 00:50:47 -04:00
|
|
|
if (!log_daemon_started) {
|
2019-01-26 13:39:24 -05:00
|
|
|
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null") == 0) {
|
2018-10-12 00:50:47 -04:00
|
|
|
if (fork_dont_care() == 0)
|
|
|
|
log_daemon();
|
2018-11-04 17:23:08 -05:00
|
|
|
log_daemon_started = true;
|
2018-10-28 04:24:53 -04:00
|
|
|
// Wait till we can connect to log_daemon and receive ack
|
2018-10-12 00:50:47 -04:00
|
|
|
int fd = connect_log_daemon();
|
|
|
|
write_int(fd, HANDSHAKE);
|
2018-10-28 04:24:53 -04:00
|
|
|
read_int(fd);
|
2018-10-12 00:50:47 -04:00
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
chmod("/dev/null", 0666);
|
|
|
|
}
|
|
|
|
return log_daemon_started;
|
|
|
|
}
|
|
|
|
|
|
|
|
int connect_log_daemon() {
|
|
|
|
if (!log_daemon_started)
|
|
|
|
return -1;
|
|
|
|
struct sockaddr_un sun;
|
|
|
|
socklen_t len = setup_sockaddr(&sun, LOG_SOCKET);
|
|
|
|
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
while (connect(fd, (struct sockaddr*) &sun, len))
|
|
|
|
usleep(10000);
|
|
|
|
return fd;
|
|
|
|
}
|