am 0bda352f: Merge changes from topic \'logcatd\'

* commit '0bda352f7f2b4453aa7b65feb935938205f1285e':
  init.rc: logd: Add logpersistd (nee logcatd)
  init: change exec parsing to make SECLABEL optional
  logcat: -f run in background
  logcat: -f flag to continue
This commit is contained in:
Mark Salyzyn 2015-06-02 22:28:43 +00:00 committed by Android Git Automerger
commit e0e565635a
10 changed files with 182 additions and 18 deletions

View file

@ -380,7 +380,8 @@ void service_start(struct service *svc, const char *dynamic_args)
if ((svc->flags & SVC_EXEC) != 0) { if ((svc->flags & SVC_EXEC) != 0) {
INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n", INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel); svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,
svc->seclabel ? : "default");
waiting_for_exec = true; waiting_for_exec = true;
} }

View file

@ -664,6 +664,7 @@ int action_queue_empty()
service* make_exec_oneshot_service(int nargs, char** args) { service* make_exec_oneshot_service(int nargs, char** args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default
int command_arg = 1; int command_arg = 1;
for (int i = 1; i < nargs; ++i) { for (int i = 1; i < nargs; ++i) {
if (strcmp(args[i], "--") == 0) { if (strcmp(args[i], "--") == 0) {
@ -689,7 +690,7 @@ service* make_exec_oneshot_service(int nargs, char** args) {
return NULL; return NULL;
} }
if (command_arg > 2) { if ((command_arg > 2) && strcmp(args[1], "-")) {
svc->seclabel = args[1]; svc->seclabel = args[1];
} }
if (command_arg > 3) { if (command_arg > 3) {

View file

@ -180,7 +180,7 @@ exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
Fork and execute command with the given arguments. The command starts Fork and execute command with the given arguments. The command starts
after "--" so that an optional security context, user, and supplementary after "--" so that an optional security context, user, and supplementary
groups can be provided. No other commands will be run until this one groups can be provided. No other commands will be run until this one
finishes. finishes. <seclabel> can be a - to denote default.
export <name> <value> export <name> <value>
Set the environment variable <name> equal to <value> in the Set the environment variable <name> equal to <value> in the

View file

@ -22,7 +22,7 @@
#include <log/log_read.h> #include <log/log_read.h>
const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q"; const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
const timespec log_time::EPOCH = { 0, 0 }; const timespec log_time::EPOCH = { 0, 0 };
// Add %#q for fractional seconds to standard strptime function // Add %#q for fractional seconds to standard strptime function

View file

@ -5,7 +5,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= logcat.cpp event.logtags LOCAL_SRC_FILES:= logcat.cpp event.logtags
LOCAL_SHARED_LIBRARIES := liblog LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
LOCAL_MODULE := logcat LOCAL_MODULE := logcat

View file

@ -1,29 +1,38 @@
// Copyright 2006-2015 The Android Open Source Project // Copyright 2006-2015 The Android Open Source Project
#include <arpa/inet.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <math.h> #include <math.h>
#include <sched.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <arpa/inet.h> #include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <base/file.h>
#include <base/strings.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h> #include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <log/log.h> #include <log/log.h>
#include <log/log_read.h> #include <log/log_read.h>
#include <log/logger.h>
#include <log/logd.h> #include <log/logd.h>
#include <log/logger.h>
#include <log/logprint.h> #include <log/logprint.h>
#include <log/event_tag_map.h>
#define DEFAULT_MAX_ROTATED_LOGS 4 #define DEFAULT_MAX_ROTATED_LOGS 4
@ -202,7 +211,15 @@ static void setupOutput()
g_outFD = STDOUT_FILENO; g_outFD = STDOUT_FILENO;
} else { } else {
struct stat statbuf; if (set_sched_policy(0, SP_BACKGROUND) < 0) {
fprintf(stderr, "failed to set background scheduling policy\n");
}
struct sched_param param;
memset(&param, 0, sizeof(param));
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
fprintf(stderr, "failed to set to batch scheduler\n");
}
g_outFD = openLogFile (g_outputFileName); g_outFD = openLogFile (g_outputFileName);
@ -210,6 +227,7 @@ static void setupOutput()
logcat_panic(false, "couldn't open output file"); logcat_panic(false, "couldn't open output file");
} }
struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) { if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD); close(g_outFD);
logcat_panic(false, "couldn't get output file stat\n"); logcat_panic(false, "couldn't get output file stat\n");
@ -231,7 +249,7 @@ static void show_help(const char *cmd)
fprintf(stderr, "options include:\n" fprintf(stderr, "options include:\n"
" -s Set default filter to silent.\n" " -s Set default filter to silent.\n"
" Like specifying filterspec '*:S'\n" " Like specifying filterspec '*:S'\n"
" -f <filename> Log to file. Default to stdout\n" " -f <filename> Log to file. Default is stdout\n"
" -r <kbytes> Rotate log every kbytes. Requires -f\n" " -r <kbytes> Rotate log every kbytes. Requires -f\n"
" -n <count> Sets max number of rotated logs to <count>, default 4\n" " -n <count> Sets max number of rotated logs to <count>, default 4\n"
" -v <format> Sets the log print format, where <format> is:\n\n" " -v <format> Sets the log print format, where <format> is:\n\n"
@ -352,6 +370,86 @@ static void logcat_panic(bool showHelp, const char *fmt, ...)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static const char g_defaultTimeFormat[] = "%m-%d %H:%M:%S.%q";
// Find last logged line in gestalt of all matching existing output files
static log_time lastLogTime(char *outputFileName) {
log_time retval(log_time::EPOCH);
if (!outputFileName) {
return retval;
}
log_time now(CLOCK_REALTIME);
std::string directory;
char *file = strrchr(outputFileName, '/');
if (!file) {
directory = ".";
file = outputFileName;
} else {
*file = '\0';
directory = outputFileName;
*file = '/';
++file;
}
size_t len = strlen(file);
log_time modulo(0, NS_PER_SEC);
std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if ((dp->d_type != DT_REG)
|| strncmp(dp->d_name, file, len)
|| (dp->d_name[len]
&& ((dp->d_name[len] != '.')
|| !isdigit(dp->d_name[len+1])))) {
continue;
}
std::string file_name = directory;
file_name += "/";
file_name += dp->d_name;
std::string file;
if (!android::base::ReadFileToString(file_name, &file)) {
continue;
}
bool found = false;
for (const auto& line : android::base::Split(file, "\n")) {
log_time t(log_time::EPOCH);
char *ep = t.strptime(line.c_str(), g_defaultTimeFormat);
if (!ep || (*ep != ' ')) {
continue;
}
// determine the time precision of the logs (eg: msec or usec)
for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
if (t.tv_nsec % (mod * 10)) {
modulo.tv_nsec = mod;
break;
}
}
// We filter any times later than current as we may not have the
// year stored with each log entry. Also, since it is possible for
// entries to be recorded out of order (very rare) we select the
// maximum we find just in case.
if ((t < now) && (t > retval)) {
retval = t;
found = true;
}
}
// We count on the basename file to be the definitive end, so stop here.
if (!dp->d_name[len] && found) {
break;
}
}
if (retval == log_time::EPOCH) {
return retval;
}
// tail_time prints matching or higher, round up by the modulo to prevent
// a replay of the last entry we have just checked.
retval += modulo;
return retval;
}
} /* namespace android */ } /* namespace android */
@ -417,12 +515,11 @@ int main(int argc, char **argv)
/* FALLTHRU */ /* FALLTHRU */
case 'T': case 'T':
if (strspn(optarg, "0123456789") != strlen(optarg)) { if (strspn(optarg, "0123456789") != strlen(optarg)) {
char *cp = tail_time.strptime(optarg, char *cp = tail_time.strptime(optarg, g_defaultTimeFormat);
log_time::default_format);
if (!cp) { if (!cp) {
logcat_panic(false, logcat_panic(false,
"-%c \"%s\" not in \"%s\" time format\n", "-%c \"%s\" not in \"%s\" time format\n",
ret, optarg, log_time::default_format); ret, optarg, g_defaultTimeFormat);
} }
if (*cp) { if (*cp) {
char c = *cp; char c = *cp;
@ -545,9 +642,11 @@ int main(int argc, char **argv)
break; break;
case 'f': case 'f':
if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
tail_time = lastLogTime(optarg);
}
// redirect output to a file // redirect output to a file
g_outputFileName = optarg; g_outputFileName = optarg;
break; break;
case 'r': case 'r':

View file

@ -41,4 +41,15 @@ LOCAL_CFLAGS := -Werror $(event_flag)
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := logpersist.start
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(bin_dir)
LOCAL_SRC_FILES := logpersist
ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
include $(BUILD_PREBUILT)
include $(call first-makefiles-under,$(LOCAL_PATH)) include $(call first-makefiles-under,$(LOCAL_PATH))

View file

@ -10,6 +10,8 @@ ro.config.low_ram bool false if true, logd.statistics & logd.klogd
default false default false
ro.build.type string if user, logd.statistics & logd.klogd ro.build.type string if user, logd.statistics & logd.klogd
default false default false
persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
turns on logcat -f in logd context
persist.logd.size number 256K default size of the buffer for all persist.logd.size number 256K default size of the buffer for all
log ids at initial startup, at runtime log ids at initial startup, at runtime
use: logcat -b all -G <value> use: logcat -b all -G <value>

36
logd/logpersist Executable file
View file

@ -0,0 +1,36 @@
#! /system/bin/sh
# logpersist cat start and stop handlers
data=/data/misc/logd
property=persist.logd.logpersistd
service=logcatd
progname="${0##*/}"
if [ X"${1}" = "-h" -o X"${1}" = X"--help" ]; then
echo "${progname%.*}.cat - dump current ${service%d} logs"
echo "${progname%.*}.start - start ${service} service"
echo "${progname%.*}.stop [--clear] - stop ${service} service"
exit 0
fi
case ${progname} in
*.cat)
su 1036 ls "${data}" |
tr -d '\r' |
sort -ru |
sed "s#^#${data}/#" |
su 1036 xargs cat
;;
*.start)
su 0 setprop ${property} ${service}
getprop ${property}
sleep 1
ps -t | grep "${data##*/}.*${service%d}"
;;
*.stop)
su 0 stop ${service}
su 0 setprop ${property} ""
[ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
( sleep 1 ; su 1036,9998 rm -rf "${data}" )
;;
*)
echo "Unexpected command ${0##*/} ${@}" >&2
exit 1
esac

View file

@ -649,3 +649,17 @@ service perfprofd /system/xbin/perfprofd
class late_start class late_start
user root user root
oneshot oneshot
on property:persist.logd.logpersistd=logcatd
# all exec/services are called with umask(077), so no gain beyond 0700
mkdir /data/misc/logd 0700 logd log
# logd for write to /data/misc/logd, log group for read from pstore (-L)
exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
start logcatd
service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
class late_start
disabled
# logd for write to /data/misc/logd, log group for read from log daemon
user logd
group log