diff options
Diffstat (limited to 'logd/main.cpp')
-rw-r--r-- | logd/main.cpp | 218 |
1 files changed, 199 insertions, 19 deletions
diff --git a/logd/main.cpp b/logd/main.cpp index 54da7e3..eb29596 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -17,24 +17,37 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <poll.h> #include <sched.h> +#include <semaphore.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/capability.h> +#include <sys/klog.h> #include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> +#include <syslog.h> #include <unistd.h> #include <cutils/properties.h> +#include <cutils/sched_policy.h> +#include <cutils/sockets.h> +#include <private/android_filesystem_config.h> -#include "private/android_filesystem_config.h" #include "CommandListener.h" #include "LogBuffer.h" #include "LogListener.h" #include "LogAudit.h" +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \ + '>' + // // The service is designed to be run by init, it does not respond well // to starting up manually. When starting up manually the sockets will @@ -68,6 +81,10 @@ static int drop_privs() { struct sched_param param; memset(¶m, 0, sizeof(param)); + if (set_sched_policy(0, SP_BACKGROUND) < 0) { + return -1; + } + if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) { return -1; } @@ -121,17 +138,161 @@ static bool property_get_bool(const char *key, bool def) { return def; } -// Foreground waits for exit of the three main persistent threads that -// are started here. The three threads are created to manage UNIX -// domain client sockets for writing, reading and controlling the user -// space logger. Additional transitory per-client threads are created -// for each reader once they register. -int main() { - bool auditd = property_get_bool("logd.auditd", true); +// Remove the static, and use this variable +// globally for debugging if necessary. eg: +// write(fdDmesg, "I am here\n", 10); +static int fdDmesg = -1; + +static sem_t uidName; +static uid_t uid; +static char *name; + +static sem_t reinit; +static bool reinit_running = false; +static LogBuffer *logBuf = NULL; + +static void *reinit_thread_start(void * /*obj*/) { + prctl(PR_SET_NAME, "logd.daemon"); + set_sched_policy(0, SP_BACKGROUND); + + setgid(AID_SYSTEM); + setuid(AID_SYSTEM); + + while (reinit_running && !sem_wait(&reinit) && reinit_running) { + + // uidToName Privileged Worker + if (uid) { + name = NULL; + + FILE *fp = fopen("/data/system/packages.list", "r"); + if (fp) { + // This simple parser is sensitive to format changes in + // frameworks/base/services/core/java/com/android/server/pm/Settings.java + // A dependency note has been added to that file to correct + // this parser. + + char *buffer = NULL; + size_t len; + while (getline(&buffer, &len, fp) > 0) { + char *userId = strchr(buffer, ' '); + if (!userId) { + continue; + } + *userId = '\0'; + unsigned long value = strtoul(userId + 1, NULL, 10); + if (value != uid) { + continue; + } + name = strdup(buffer); + break; + } + free(buffer); + fclose(fp); + } + uid = 0; + sem_post(&uidName); + continue; + } - int fdDmesg = -1; - if (auditd && property_get_bool("logd.auditd.dmesg", true)) { - fdDmesg = open("/dev/kmsg", O_WRONLY); + if (fdDmesg >= 0) { + static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':', + ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' }; + write(fdDmesg, reinit_message, sizeof(reinit_message)); + } + + // Anything that reads persist.<property> + if (logBuf) { + logBuf->init(); + } + } + + return NULL; +} + +char *android::uidToName(uid_t u) { + if (!u || !reinit_running) { + return NULL; + } + + // Not multi-thread safe, we know there is only one caller + uid = u; + + name = NULL; + sem_post(&reinit); + sem_wait(&uidName); + return name; +} + +// Serves as a global method to trigger reinitialization +// and as a function that can be provided to signal(). +void reinit_signal_handler(int /*signal*/) { + sem_post(&reinit); +} + +// Foreground waits for exit of the main persistent threads +// that are started here. The threads are created to manage +// UNIX domain client sockets for writing, reading and +// controlling the user space logger, and for any additional +// logging plugins like auditd and restart control. Additional +// transitory per-client threads are created for each reader. +int main(int argc, char *argv[]) { + fdDmesg = open("/dev/kmsg", O_WRONLY); + + // issue reinit command. KISS argument parsing. + if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) { + int sock = TEMP_FAILURE_RETRY( + socket_local_client("logd", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)); + if (sock < 0) { + return -errno; + } + static const char reinit[] = "reinit"; + ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit))); + if (ret < 0) { + return -errno; + } + struct pollfd p; + memset(&p, 0, sizeof(p)); + p.fd = sock; + p.events = POLLIN; + ret = TEMP_FAILURE_RETRY(poll(&p, 1, 100)); + if (ret < 0) { + return -errno; + } + if ((ret == 0) || !(p.revents & POLLIN)) { + return -ETIME; + } + static const char success[] = "success"; + char buffer[sizeof(success) - 1]; + memset(buffer, 0, sizeof(buffer)); + ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); + if (ret < 0) { + return -errno; + } + return strncmp(buffer, success, sizeof(success) - 1) != 0; + } + + // Reinit Thread + sem_init(&reinit, 0, 0); + sem_init(&uidName, 0, 0); + pthread_attr_t attr; + if (!pthread_attr_init(&attr)) { + struct sched_param param; + + memset(¶m, 0, sizeof(param)); + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setschedpolicy(&attr, SCHED_BATCH); + if (!pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED)) { + pthread_t thread; + reinit_running = true; + if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) { + reinit_running = false; + } + } + pthread_attr_destroy(&attr); } if (drop_privs() != 0) { @@ -147,11 +308,10 @@ int main() { // LogBuffer is the object which is responsible for holding all // log entries. - LogBuffer *logBuf = new LogBuffer(times); + logBuf = new LogBuffer(times); + + signal(SIGHUP, reinit_signal_handler); - if (property_get_bool("logd.statistics.dgram_qlen", false)) { - logBuf->enableDgramQlenStatistics(); - } { char property[PROPERTY_VALUE_MAX]; property_get("ro.build.type", property, ""); @@ -192,16 +352,36 @@ int main() { // initiated log messages. New log entries are added to LogBuffer // and LogReader is notified to send updates to connected clients. + bool auditd = property_get_bool("logd.auditd", true); + if (auditd) { + bool dmesg = property_get_bool("logd.auditd.dmesg", true); + // failure is an option ... messages are in dmesg (required by standard) - LogAudit *al = new LogAudit(logBuf, reader, fdDmesg); + LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1); + + int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0); + if (len > 0) { + len++; + char buf[len]; + + int rc = klogctl(KLOG_READ_ALL, buf, len); + + if (rc >= 0) { + buf[len - 1] = '\0'; + + for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) { + al->log(tok); + } + } + } + if (al->startListener()) { delete al; - close(fdDmesg); } } - pause(); + TEMP_FAILURE_RETRY(pause()); + exit(0); } - |