341 lines
9.5 KiB
C++
341 lines
9.5 KiB
C++
|
|
#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/resource.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <syslog.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
|
||
|
|
#include <cstdbool>
|
||
|
|
#include <memory>
|
||
|
|
|
||
|
|
#include <android-base/macros.h>
|
||
|
|
#include <android-base/logging.h>
|
||
|
|
|
||
|
|
#include <cutils/android_get_control_file.h>
|
||
|
|
#include <cutils/properties.h>
|
||
|
|
#include <cutils/sched_policy.h>
|
||
|
|
#include <cutils/sockets.h>
|
||
|
|
#include <log/event_tag_map.h>
|
||
|
|
#include <packagelistparser/packagelistparser.h>
|
||
|
|
#include <private/android_filesystem_config.h>
|
||
|
|
#include <private/android_logger.h>
|
||
|
|
#include <utils/threads.h>
|
||
|
|
|
||
|
|
#include "CommandListener.h"
|
||
|
|
#include "LogAudit.h"
|
||
|
|
#include "LogBuffer.h"
|
||
|
|
#include "LogKlog.h"
|
||
|
|
#include "LogListener.h"
|
||
|
|
#include "LogUtils.h"
|
||
|
|
|
||
|
|
#ifdef MTK_LOGD_ENHANCE
|
||
|
|
#ifdef __cplusplus
|
||
|
|
extern "C" {
|
||
|
|
#endif
|
||
|
|
#define INTERVAL 5LL
|
||
|
|
#define MAX_COUNT 25
|
||
|
|
void prdebug_ratelimit(const char* fmt, ...) {
|
||
|
|
static int cnt = 0;
|
||
|
|
static int miss_cnt = 0;
|
||
|
|
static struct timespec ts_0 = {0, 0};
|
||
|
|
struct timespec ts_1;
|
||
|
|
int64_t differ = 0;
|
||
|
|
|
||
|
|
if (cnt == 0) {
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_0);
|
||
|
|
}
|
||
|
|
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_1);
|
||
|
|
|
||
|
|
differ = ts_1.tv_sec - ts_0.tv_sec;
|
||
|
|
|
||
|
|
// if more than MAX_COUNT entry msg during (INTERVAL - 1, INTERVAL + 1), then drop
|
||
|
|
if (cnt >= MAX_COUNT && differ < INTERVAL) {
|
||
|
|
miss_cnt++;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
char buffer[192];
|
||
|
|
va_list ap;
|
||
|
|
va_start(ap, fmt);
|
||
|
|
int n = vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||
|
|
va_end(ap);
|
||
|
|
if (n > 0) {
|
||
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
||
|
|
|
||
|
|
if (cnt < MAX_COUNT) {
|
||
|
|
LOG(DEBUG) << buffer;
|
||
|
|
cnt++;
|
||
|
|
} else if(differ >= INTERVAL) {
|
||
|
|
// write dropped statistic info
|
||
|
|
if (miss_cnt != 0)
|
||
|
|
LOG(DEBUG) << "dropped " << miss_cnt << "its own logs by limitation.\n";
|
||
|
|
// write normal log
|
||
|
|
LOG(DEBUG) << buffer;
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_0); // update ts_0
|
||
|
|
cnt = 1; // cnt = 1
|
||
|
|
miss_cnt = 0; // reset to Zero
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef __cplusplus
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// logd related info need to be adjusted.
|
||
|
|
int logd_adjust(const char* cmdStr) {
|
||
|
|
cap_t caps = cap_init();
|
||
|
|
(void)cap_clear(caps);
|
||
|
|
(void)cap_set_proc(caps);
|
||
|
|
(void)cap_free(caps);
|
||
|
|
|
||
|
|
int sock = TEMP_FAILURE_RETRY(socket_local_client(
|
||
|
|
"logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
|
||
|
|
if (sock < 0) return -errno;
|
||
|
|
|
||
|
|
//static const char logmuchStr[] = "logmuch";
|
||
|
|
char command[32] = {0};
|
||
|
|
strncpy(command, cmdStr, sizeof(command));
|
||
|
|
command[sizeof(command) - 1] = '\0';
|
||
|
|
ssize_t ret = TEMP_FAILURE_RETRY(write(sock, command, strlen(command) + 1));
|
||
|
|
if (ret < 0) {
|
||
|
|
close(sock);
|
||
|
|
return -errno;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct pollfd p;
|
||
|
|
memset(&p, 0, sizeof(p));
|
||
|
|
p.fd = sock;
|
||
|
|
p.events = POLLIN;
|
||
|
|
ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
|
||
|
|
if (ret < 0) {
|
||
|
|
close(sock);
|
||
|
|
p.fd = -1;
|
||
|
|
return -errno;
|
||
|
|
}
|
||
|
|
if ((ret == 0) || !(p.revents & POLLIN)) {
|
||
|
|
close(sock);
|
||
|
|
p.fd = -1;
|
||
|
|
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) {
|
||
|
|
close(sock);
|
||
|
|
p.fd = -1;
|
||
|
|
return -errno;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (close(sock) == -1) {
|
||
|
|
LOG(WARNING) << "close socket failed!";
|
||
|
|
}
|
||
|
|
return strncmp(buffer, success, sizeof(success) - 1) != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined(MTK_LOGD_FILTER)
|
||
|
|
int log_reader_count = 0;
|
||
|
|
void logd_reader_del(void) {
|
||
|
|
if (log_reader_count == 1) {
|
||
|
|
property_set("log.tag", "I");
|
||
|
|
prdebug_ratelimit("logd no log reader, set log level to I!\n");
|
||
|
|
}
|
||
|
|
log_reader_count--;
|
||
|
|
prdebug_ratelimit("Del, log_reader_count: %d \n", log_reader_count);
|
||
|
|
}
|
||
|
|
|
||
|
|
void logd_reader_add(void) {
|
||
|
|
if (log_reader_count == 0) {
|
||
|
|
property_set("log.tag", "M");
|
||
|
|
prdebug_ratelimit("logd first log reader, set log level to M!\n");
|
||
|
|
}
|
||
|
|
log_reader_count++;
|
||
|
|
prdebug_ratelimit("Add, log_reader_count: %d \n", log_reader_count);
|
||
|
|
}
|
||
|
|
|
||
|
|
static sem_t loglevel_sem;
|
||
|
|
static void* loglevel_adjust_thread_start(void* /*obj*/) {
|
||
|
|
prctl(PR_SET_NAME, "logd.loglevel");
|
||
|
|
|
||
|
|
set_sched_policy(0, SP_FOREGROUND);
|
||
|
|
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
|
||
|
|
|
||
|
|
cap_t caps = cap_init();
|
||
|
|
(void)cap_clear(caps);
|
||
|
|
(void)cap_set_proc(caps);
|
||
|
|
(void)cap_free(caps);
|
||
|
|
|
||
|
|
while (!sem_wait(&loglevel_sem)) {
|
||
|
|
LOG(DEBUG) << "loglevel adjust thread wakeup";
|
||
|
|
if (log_reader_count == 0) {
|
||
|
|
property_set("log.tag", "I");
|
||
|
|
LOG(DEBUG) << "logd no log reader, set loglevel to INFO!\n";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void loglevel_control_init() {
|
||
|
|
sem_init(&loglevel_sem, 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;
|
||
|
|
pthread_create(&thread, &attr, loglevel_adjust_thread_start, nullptr);
|
||
|
|
}
|
||
|
|
pthread_attr_destroy(&attr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void trigger_loglevel_adjust() {
|
||
|
|
sem_post(&loglevel_sem);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined(MSSI_HAVE_AEE_FEATURE) && defined(ANDROID_LOG_MUCH_COUNT)
|
||
|
|
|
||
|
|
static sem_t logmuch_sem;
|
||
|
|
|
||
|
|
int log_detect_value;
|
||
|
|
int log_much_delay_detect = 0; // log much detect pause, may use double detect value
|
||
|
|
int build_type; // eng:0, userdebug:1 user:2
|
||
|
|
int detect_time = 1;
|
||
|
|
|
||
|
|
// adjust logmuch feature
|
||
|
|
static void* logmuch_adjust_thread_start(void* /*obj*/) {
|
||
|
|
prctl(PR_SET_NAME, "logd.logmuch.D");
|
||
|
|
|
||
|
|
set_sched_policy(0, SP_FOREGROUND);
|
||
|
|
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
|
||
|
|
|
||
|
|
cap_t caps = cap_init();
|
||
|
|
(void)cap_clear(caps);
|
||
|
|
(void)cap_set_proc(caps);
|
||
|
|
(void)cap_free(caps);
|
||
|
|
|
||
|
|
char property[PROPERTY_VALUE_MAX];
|
||
|
|
bool value;
|
||
|
|
int count;
|
||
|
|
static int delay_old;
|
||
|
|
int delay;
|
||
|
|
|
||
|
|
while (!sem_wait(&logmuch_sem)) {
|
||
|
|
LOG(DEBUG) << "logmuch adjust thread wakeup";
|
||
|
|
property_get("ro.vendor.aee.build.info", property, "");
|
||
|
|
value = !strcmp(property, "mtk");
|
||
|
|
if (value != true) {
|
||
|
|
log_detect_value = 0;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
value = property_get_bool("persist.vendor.logmuch", true);
|
||
|
|
if (value == true) {
|
||
|
|
property_get("ro.build.type", property, "");
|
||
|
|
if (!strcmp(property, "eng")) {
|
||
|
|
build_type = 0;
|
||
|
|
} else if (!strcmp(property, "userdebug")) {
|
||
|
|
build_type = 1;
|
||
|
|
} else {
|
||
|
|
build_type = 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (log_detect_value == 0) {
|
||
|
|
log_detect_value = ANDROID_LOG_MUCH_COUNT;
|
||
|
|
}
|
||
|
|
|
||
|
|
property_get("vendor.logmuch.value", property, "-1");
|
||
|
|
count = strtol(property, nullptr, 10);
|
||
|
|
if (count == 0) {
|
||
|
|
count = ANDROID_LOG_MUCH_COUNT;
|
||
|
|
}
|
||
|
|
LOG(DEBUG) << android::base::StringPrintf("logmuch detect, build type %d, detect value %d:%d.\n",
|
||
|
|
build_type, count, log_detect_value);
|
||
|
|
if (count > 0 && count != log_detect_value) { // set new log level
|
||
|
|
log_detect_value = count;
|
||
|
|
log_much_delay_detect = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
detect_time = (log_detect_value > 1000) ? 1 : 6;
|
||
|
|
|
||
|
|
property_get("vendor.logmuch.delay", property, "");
|
||
|
|
delay = strtol(property, nullptr, 10);
|
||
|
|
|
||
|
|
if (delay > 0 && delay != delay_old) {
|
||
|
|
log_much_delay_detect = 3*60;
|
||
|
|
delay_old = delay;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
log_detect_value = 0;
|
||
|
|
LOG(DEBUG) << "logmuch detect disable.";
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
/* logmuch control init */
|
||
|
|
void logmuch_control_init() {
|
||
|
|
sem_init(&logmuch_sem, 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;
|
||
|
|
pthread_create(&thread, &attr, logmuch_adjust_thread_start, nullptr);
|
||
|
|
}
|
||
|
|
pthread_attr_destroy(&attr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void trigger_logmuch_adjust() {
|
||
|
|
sem_post(&logmuch_sem);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined(LOGD_FORCE_DIRECTCOREDUMP)
|
||
|
|
#define SIGNUM 7
|
||
|
|
|
||
|
|
// need sync with vendor\mediatek\proprietary\external\aee\direct-coredump\direct-coredump.c
|
||
|
|
void directcoredump_init() {
|
||
|
|
int sigtype[SIGNUM] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP, SIGSYS};
|
||
|
|
char value[PROPERTY_VALUE_MAX] = {'\0'};
|
||
|
|
|
||
|
|
// eng&userdebug load direct-coredump default enable
|
||
|
|
// user load direct-coredump default disable due to libdirect-coredump.so will not be preloaded
|
||
|
|
property_get("persist.vendor.aeev.core.direct", value, "default");
|
||
|
|
if (strncmp(value, "disable", sizeof("disable"))) {
|
||
|
|
int loop;
|
||
|
|
for (loop = 0; loop < SIGNUM; loop++) {
|
||
|
|
if (SIG_ERR == signal(sigtype[loop], SIG_DFL))
|
||
|
|
LOG(DEBUG) << "init siginal error\n";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
LOG(DEBUG) << "init directcoredump done!\n";
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|