Merge changes from topic 'enable_persist_kernel_log' into nyc-mr1-dev
* changes: logcatd: trampoline persist.logd.logpersistd to logd.logpersistd logcatd: add stop and clear actions logcatd: Do not su for setprop logcat: allow comma-separate list of buffers logcat: clear when specifying file output logcat: Adjust help to make it more meaningful
This commit is contained in:
commit
56efe020b7
5 changed files with 342 additions and 188 deletions
|
@ -278,61 +278,59 @@ static void show_help(const char *cmd)
|
|||
fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
|
||||
|
||||
fprintf(stderr, "options include:\n"
|
||||
" -s Set default filter to silent.\n"
|
||||
" Like specifying filterspec '*:S'\n"
|
||||
" -f <filename> Log to file. Default is stdout\n"
|
||||
" --file=<filename>\n"
|
||||
" -r <kbytes> Rotate log every kbytes. Requires -f\n"
|
||||
" --rotate-kbytes=<kbytes>\n"
|
||||
" -n <count> Sets max number of rotated logs to <count>, default 4\n"
|
||||
" --rotate-count=<count>\n"
|
||||
" -v <format> Sets the log print format, where <format> is:\n"
|
||||
" --format=<format>\n"
|
||||
" brief color epoch long monotonic printable process raw\n"
|
||||
" tag thread threadtime time uid usec UTC year zone\n\n"
|
||||
" -D print dividers between each log buffer\n"
|
||||
" --dividers\n"
|
||||
" -c clear (flush) the entire log and exit\n"
|
||||
" --clear\n"
|
||||
" -d dump the log and then exit (don't block)\n"
|
||||
" -e <expr> only print lines where the log message matches <expr>\n"
|
||||
" --regex <expr> where <expr> is a regular expression\n"
|
||||
" -m <count> quit after printing <count> lines. This is meant to be\n"
|
||||
" --max-count=<count> paired with --regex, but will work on its own.\n"
|
||||
" --print paired with --regex and --max-count to let content bypass\n"
|
||||
" -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
|
||||
" -f <file>, --file=<file> Log to file. Default is stdout\n"
|
||||
" -r <kbytes>, --rotate-kbytes=<kbytes>\n"
|
||||
" Rotate log every kbytes. Requires -f option\n"
|
||||
" -n <count>, --rotate-count=<count>\n"
|
||||
" Sets max number of rotated logs to <count>, default 4\n"
|
||||
" -v <format>, --format=<format>\n"
|
||||
" Sets the log print format, where <format> is:\n"
|
||||
" brief color epoch long monotonic printable process raw\n"
|
||||
" tag thread threadtime time uid usec UTC year zone\n"
|
||||
" -D, --dividers Print dividers between each log buffer\n"
|
||||
" -c, --clear Clear (flush) the entire log and exit\n"
|
||||
" if Log to File specified, clear fileset instead\n"
|
||||
" -d Dump the log and then exit (don't block)\n"
|
||||
" -e <expr>, --regex=<expr>\n"
|
||||
" Only print lines where the log message matches <expr>\n"
|
||||
" where <expr> is a regular expression\n"
|
||||
// Leave --head undocumented as alias for -m
|
||||
" -m <count>, --max-count=<count>\n"
|
||||
" Quit after printing <count> lines. This is meant to be\n"
|
||||
" paired with --regex, but will work on its own.\n"
|
||||
" --print Paired with --regex and --max-count to let content bypass\n"
|
||||
" regex filter but still stop at number of matches.\n"
|
||||
" -t <count> print only the most recent <count> lines (implies -d)\n"
|
||||
" -t '<time>' print most recent lines since specified time (implies -d)\n"
|
||||
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
|
||||
" -T '<time>' print most recent lines since specified time (not imply -d)\n"
|
||||
// Leave --tail undocumented as alias for -t
|
||||
" -t <count> Print only the most recent <count> lines (implies -d)\n"
|
||||
" -t '<time>' Print most recent lines since specified time (implies -d)\n"
|
||||
" -T <count> Print only the most recent <count> lines (does not imply -d)\n"
|
||||
" -T '<time>' Print most recent lines since specified time (not imply -d)\n"
|
||||
" count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
|
||||
" 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
|
||||
" -g get the size of the log's ring buffer and exit\n"
|
||||
" --buffer-size\n"
|
||||
" -G <size> set size of log ring buffer, may suffix with K or M.\n"
|
||||
" --buffer-size=<size>\n"
|
||||
" -L dump logs from prior to last reboot\n"
|
||||
" --last\n"
|
||||
" -g, --buffer-size Get the size of the ring buffer.\n"
|
||||
" -G <size>, --buffer-size=<size>\n"
|
||||
" Set size of log ring buffer, may suffix with K or M.\n"
|
||||
" -L, -last Dump logs from prior to last reboot\n"
|
||||
// Leave security (Device Owner only installations) and
|
||||
// kernel (userdebug and eng) buffers undocumented.
|
||||
" -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
|
||||
" --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
|
||||
" parameters are allowed and results are interleaved. The\n"
|
||||
" default is -b main -b system -b crash.\n"
|
||||
" -B output the log in binary.\n"
|
||||
" --binary\n"
|
||||
" -S output statistics.\n"
|
||||
" --statistics\n"
|
||||
" -p print prune white and ~black list. Service is specified as\n"
|
||||
" --prune UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
|
||||
" -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
|
||||
" 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
|
||||
" Multiple -b parameters or comma separated list of buffers are\n"
|
||||
" allowed. Buffers interleaved. Default -b main,system,crash.\n"
|
||||
" -B, --binary Output the log in binary.\n"
|
||||
" -S, --statistics Output statistics.\n"
|
||||
" -p, --prune Print prune white and ~black list. Service is specified as\n"
|
||||
" UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
|
||||
" with ~, otherwise weighed for longevity if unadorned. All\n"
|
||||
" other pruning activity is oldest first. Special case ~!\n"
|
||||
" represents an automatic quicker pruning for the noisiest\n"
|
||||
" UID as determined by the current statistics.\n"
|
||||
" -P '<list> ...' set prune white and ~black list, using same format as\n"
|
||||
" --prune='<list> ...' printed above. Must be quoted.\n"
|
||||
" -P '<list> ...', --prune='<list> ...'\n"
|
||||
" Set prune white and ~black list, using same format as\n"
|
||||
" listed above. Must be quoted.\n"
|
||||
" --pid=<pid> Only prints logs from the given pid.\n"
|
||||
// Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
|
||||
// Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
|
||||
" --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
|
||||
" comes first. Improves efficiency of polling by providing\n"
|
||||
" an about-to-wrap wakeup.\n");
|
||||
|
@ -765,111 +763,63 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
|
||||
case 'b': {
|
||||
if (strcmp(optarg, "default") == 0) {
|
||||
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
|
||||
switch (i) {
|
||||
case LOG_ID_SECURITY:
|
||||
case LOG_ID_EVENTS:
|
||||
continue;
|
||||
case LOG_ID_MAIN:
|
||||
case LOG_ID_SYSTEM:
|
||||
case LOG_ID_CRASH:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
unsigned idMask = 0;
|
||||
while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
|
||||
if (strcmp(optarg, "default") == 0) {
|
||||
idMask |= (1 << LOG_ID_MAIN) |
|
||||
(1 << LOG_ID_SYSTEM) |
|
||||
(1 << LOG_ID_CRASH);
|
||||
} else if (strcmp(optarg, "all") == 0) {
|
||||
idMask = (unsigned)-1;
|
||||
} else {
|
||||
log_id_t log_id = android_name_to_log_id(optarg);
|
||||
const char *name = android_log_id_to_name(log_id);
|
||||
|
||||
const char *name = android_log_id_to_name((log_id_t)i);
|
||||
log_id_t log_id = android_name_to_log_id(name);
|
||||
|
||||
if (log_id != (log_id_t)i) {
|
||||
continue;
|
||||
if (strcmp(name, optarg) != 0) {
|
||||
logcat_panic(true, "unknown buffer %s\n", optarg);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (dev = devices; dev; dev = dev->next) {
|
||||
if (!strcmp(optarg, dev->device)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!dev->next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
|
||||
log_device_t* d = new log_device_t(name, false);
|
||||
|
||||
if (dev) {
|
||||
dev->next = d;
|
||||
dev = d;
|
||||
} else {
|
||||
devices = dev = d;
|
||||
}
|
||||
g_devCount++;
|
||||
idMask |= (1 << log_id);
|
||||
}
|
||||
break;
|
||||
optarg = NULL;
|
||||
}
|
||||
|
||||
if (strcmp(optarg, "all") == 0) {
|
||||
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
|
||||
const char *name = android_log_id_to_name((log_id_t)i);
|
||||
log_id_t log_id = android_name_to_log_id(name);
|
||||
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
|
||||
const char *name = android_log_id_to_name((log_id_t)i);
|
||||
log_id_t log_id = android_name_to_log_id(name);
|
||||
|
||||
if (log_id != (log_id_t)i) {
|
||||
continue;
|
||||
}
|
||||
if (log_id != (log_id_t)i) {
|
||||
continue;
|
||||
}
|
||||
if ((idMask & (1 << i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (dev = devices; dev; dev = dev->next) {
|
||||
if (!strcmp(optarg, dev->device)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!dev->next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
bool found = false;
|
||||
for (dev = devices; dev; dev = dev->next) {
|
||||
if (!strcmp(name, dev->device)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
bool binary = !strcmp(name, "events") ||
|
||||
!strcmp(name, "security");
|
||||
log_device_t* d = new log_device_t(name, binary);
|
||||
|
||||
if (dev) {
|
||||
dev->next = d;
|
||||
dev = d;
|
||||
} else {
|
||||
devices = dev = d;
|
||||
}
|
||||
g_devCount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bool binary = !(strcmp(optarg, "events") &&
|
||||
strcmp(optarg, "security"));
|
||||
|
||||
if (devices) {
|
||||
dev = devices;
|
||||
while (dev->next) {
|
||||
if (!strcmp(optarg, dev->device)) {
|
||||
dev = NULL;
|
||||
if (!dev->next) {
|
||||
break;
|
||||
}
|
||||
dev = dev->next;
|
||||
}
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool binary = !strcmp(name, "events") ||
|
||||
!strcmp(name, "security");
|
||||
log_device_t* d = new log_device_t(name, binary);
|
||||
|
||||
if (dev) {
|
||||
dev->next = new log_device_t(optarg, binary);
|
||||
dev->next = d;
|
||||
dev = d;
|
||||
} else {
|
||||
devices = dev = d;
|
||||
}
|
||||
} else {
|
||||
devices = new log_device_t(optarg, binary);
|
||||
g_devCount++;
|
||||
}
|
||||
g_devCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1084,7 +1034,35 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (clearLog) {
|
||||
if (android_logger_clear(dev->logger)) {
|
||||
if (g_outputFileName) {
|
||||
int maxRotationCountDigits =
|
||||
(g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
|
||||
|
||||
for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
|
||||
char *file;
|
||||
|
||||
if (i == 0) {
|
||||
asprintf(&file, "%s", g_outputFileName);
|
||||
} else {
|
||||
asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
perror("while clearing log files");
|
||||
clearFail = clearFail ?: dev->device;
|
||||
break;
|
||||
}
|
||||
|
||||
err = unlink(file);
|
||||
|
||||
if (err < 0 && errno != ENOENT && clearFail == NULL) {
|
||||
perror("while clearing log files");
|
||||
clearFail = dev->device;
|
||||
}
|
||||
|
||||
free(file);
|
||||
}
|
||||
} else if (android_logger_clear(dev->logger)) {
|
||||
clearFail = clearFail ?: dev->device;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,62 @@
|
|||
#
|
||||
# init scriptures for logcatd persistent logging.
|
||||
#
|
||||
# Make sure any property changes are only performed with /data mounted, after
|
||||
# post-fs-data state because otherwise behavior is undefined. The exceptions
|
||||
# are device adjustments for logcatd service properties (persist.* overrides
|
||||
# notwithstanding) for logd.logpersistd.size and logd.logpersistd.buffer.
|
||||
|
||||
# persist to non-persistent trampolines to permit device properties can be
|
||||
# overridden when /data mounts, or during runtime.
|
||||
on property:persist.logd.logpersistd.size=256
|
||||
setprop persist.logd.logpersistd.size ""
|
||||
setprop logd.logpersistd.size ""
|
||||
|
||||
on property:persist.logd.logpersistd.size=*
|
||||
# expect /init to report failure if property empty (default)
|
||||
setprop logd.logpersistd.size ${persist.logd.logpersistd.size}
|
||||
|
||||
on property:persist.logd.logpersistd.buffer=all
|
||||
setprop persist.logd.logpersistd.buffer ""
|
||||
setprop logd.logpersistd.buffer ""
|
||||
|
||||
on property:persist.logd.logpersistd.buffer=*
|
||||
# expect /init to report failure if property empty (default)
|
||||
setprop logd.logpersistd.buffer ${persist.logd.logpersistd.buffer}
|
||||
|
||||
on property:persist.logd.logpersistd=logcatd
|
||||
setprop logd.logpersistd logcatd
|
||||
|
||||
# enable, prep and start logcatd service
|
||||
on load_persist_props_action
|
||||
setprop logd.logpersistd.enable true
|
||||
|
||||
on property:logd.logpersistd.enable=true && property: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 ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
|
||||
exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
|
||||
start logcatd
|
||||
|
||||
service logcatd /system/bin/logcat -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
|
||||
# stop logcatd service and clear data
|
||||
on property:logd.logpersistd.enable=true && property:logd.logpersistd=clear
|
||||
setprop persist.logd.logpersistd ""
|
||||
stop logcatd
|
||||
# logd for clear of only our files in /data/misc/logd
|
||||
exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${logd.logpersistd.size:-256}
|
||||
setprop logd.logpersistd ""
|
||||
|
||||
# stop logcatd service
|
||||
on property:logd.logpersistd=stop
|
||||
setprop persist.logd.logpersistd ""
|
||||
stop logcatd
|
||||
setprop logd.logpersistd ""
|
||||
|
||||
on property:logd.logpersistd.enable=false
|
||||
stop logcatd
|
||||
|
||||
# logcatd service
|
||||
service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
|
||||
class late_start
|
||||
disabled
|
||||
# logd for write to /data/misc/logd, log group for read from log daemon
|
||||
|
|
|
@ -8,8 +8,16 @@ userdebug|eng) ;;
|
|||
;;
|
||||
esac
|
||||
|
||||
data=/data/misc/logd
|
||||
property=persist.logd.logpersistd
|
||||
|
||||
case `getprop ${property#persist.}.enable` in
|
||||
true) ;;
|
||||
*) echo "${progname} - Disabled"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
data=/data/misc/logd
|
||||
service=logcatd
|
||||
size_default=256
|
||||
buffer_default=all
|
||||
|
@ -69,14 +77,11 @@ case ${progname} in
|
|||
su logd xargs cat
|
||||
;;
|
||||
*.start)
|
||||
current_buffer="`getprop ${property}.buffer`"
|
||||
current_size="`getprop ${property}.size`"
|
||||
if [ "${service}" = "`getprop ${property}`" ]; then
|
||||
current_buffer="`getprop ${property#persist.}.buffer`"
|
||||
current_size="`getprop ${property#persist.}.size`"
|
||||
if [ "${service}" = "`getprop ${property#persist.}`" ]; then
|
||||
if [ "true" = "${clear}" ]; then
|
||||
su root stop ${service}
|
||||
su root setprop ${property} ""
|
||||
# 20ms done, guarantees content stop before rm
|
||||
sleep 1
|
||||
setprop ${property#persist.} "clear"
|
||||
elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
|
||||
echo "ERROR: Changing existing collection parameters from" >&2
|
||||
if [ "${buffer}" != "${current_buffer}" ]; then
|
||||
|
@ -98,21 +103,31 @@ case ${progname} in
|
|||
echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ "true" = "${clear}" ]; then
|
||||
su logd,misc rm -rf "${data}"
|
||||
elif [ "true" = "${clear}" ]; then
|
||||
setprop ${property#persist.} "clear"
|
||||
fi
|
||||
if [ -n "${buffer}${current_buffer}" ]; then
|
||||
su root setprop ${property}.buffer "${buffer}"
|
||||
setprop ${property}.buffer "${buffer}"
|
||||
if [ -z "${buffer}" ]; then
|
||||
# deal with trampoline for empty properties
|
||||
setprop ${property#persist.}.buffer ""
|
||||
fi
|
||||
fi
|
||||
if [ -n "${size}${current_size}" ]; then
|
||||
su root setprop ${property}.size "${size}"
|
||||
setprop ${property}.size "${size}"
|
||||
if [ -z "${size}" ]; then
|
||||
# deal with trampoline for empty properties
|
||||
setprop ${property#persist.}.size ""
|
||||
fi
|
||||
fi
|
||||
while [ "clear" = "`getprop ${property#persist.}`" ]; do
|
||||
continue
|
||||
done
|
||||
# ${service}.rc does the heavy lifting with the following trigger
|
||||
su root setprop ${property} ${service}
|
||||
getprop ${property}
|
||||
setprop ${property} ${service}
|
||||
# 20ms done, to permit process feedback check
|
||||
sleep 1
|
||||
getprop ${property#persist.}
|
||||
# also generate an error return code if not found running, bonus
|
||||
ps -t | grep "${data##*/}.*${service%d}"
|
||||
;;
|
||||
|
@ -120,19 +135,24 @@ case ${progname} in
|
|||
if [ -n "${size}${buffer}" ]; then
|
||||
echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
|
||||
fi
|
||||
su root stop ${service}
|
||||
su root setprop ${property} ""
|
||||
if [ -n "`getprop ${property}.buffer`" ]; then
|
||||
su root setprop ${property}.buffer ""
|
||||
fi
|
||||
if [ -n "`getprop ${property}.size`" ]; then
|
||||
su root setprop ${property}.size ""
|
||||
fi
|
||||
if [ "true" = "${clear}" ]; then
|
||||
# 20ms done, guarantees content stop before rm
|
||||
sleep 1
|
||||
su logd,misc rm -rf "${data}"
|
||||
setprop ${property} "clear"
|
||||
else
|
||||
setprop ${property} "stop"
|
||||
fi
|
||||
if [ -n "`getprop ${property#persist.}.buffer`" ]; then
|
||||
setprop ${property}.buffer ""
|
||||
# deal with trampoline for empty properties
|
||||
setprop ${property#persist.}.buffer ""
|
||||
fi
|
||||
if [ -n "`getprop ${property#persist.}.size`" ]; then
|
||||
setprop ${property}.size ""
|
||||
# deal with trampoline for empty properties
|
||||
setprop ${property#persist.}.size ""
|
||||
fi
|
||||
while [ "clear" = "`getprop ${property#persist.}`" ]; do
|
||||
continue
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <log/logger.h>
|
||||
#include <log/log_read.h>
|
||||
|
||||
#define BIG_BUFFER (5 * 1024)
|
||||
|
||||
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
|
||||
// non-syscall libs. Since we are only using this in the emergency of
|
||||
// a signal to stuff a terminating code into the logs, we will spin rather
|
||||
|
@ -52,7 +54,7 @@ TEST(logcat, buckets) {
|
|||
"logcat -b radio -b events -b system -b main -d 2>/dev/null",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int ids = 0;
|
||||
int count = 0;
|
||||
|
@ -100,7 +102,7 @@ TEST(logcat, year) {
|
|||
"logcat -v long -v year -b all -t 3 2>/dev/null",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -163,7 +165,7 @@ TEST(logcat, tz) {
|
|||
"logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
count = 0;
|
||||
|
||||
|
@ -187,7 +189,7 @@ TEST(logcat, ntz) {
|
|||
"logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -207,7 +209,7 @@ void do_tail(int num) {
|
|||
int count;
|
||||
|
||||
do {
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
|
||||
|
@ -250,7 +252,7 @@ TEST(logcat, tail_time) {
|
|||
|
||||
ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
char *last_timestamp = NULL;
|
||||
char *first_timestamp = NULL;
|
||||
int count = 0;
|
||||
|
@ -313,7 +315,7 @@ TEST(logcat, End_to_End) {
|
|||
"logcat -v brief -b events -t 100 2>/dev/null",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -337,15 +339,17 @@ TEST(logcat, End_to_End) {
|
|||
ASSERT_EQ(1, count);
|
||||
}
|
||||
|
||||
TEST(logcat, get_size) {
|
||||
int get_groups(const char *cmd) {
|
||||
FILE *fp;
|
||||
|
||||
// NB: crash log only available in user space
|
||||
ASSERT_TRUE(NULL != (fp = popen(
|
||||
"logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null",
|
||||
"r")));
|
||||
EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
|
||||
|
||||
char buffer[5120];
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -405,7 +409,23 @@ TEST(logcat, get_size) {
|
|||
|
||||
pclose(fp);
|
||||
|
||||
ASSERT_EQ(4, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
TEST(logcat, get_size) {
|
||||
ASSERT_EQ(4, get_groups(
|
||||
"logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null"));
|
||||
}
|
||||
|
||||
// duplicate test for get_size, but use comma-separated list of buffers
|
||||
TEST(logcat, multiple_buffer) {
|
||||
ASSERT_EQ(4, get_groups(
|
||||
"logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
|
||||
}
|
||||
|
||||
TEST(logcat, bad_buffer) {
|
||||
ASSERT_EQ(0, get_groups(
|
||||
"logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
|
||||
}
|
||||
|
||||
static void caught_blocking(int /*signum*/)
|
||||
|
@ -434,7 +454,7 @@ TEST(logcat, blocking) {
|
|||
" logcat -v brief -b events 2>&1",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -503,7 +523,7 @@ TEST(logcat, blocking_tail) {
|
|||
" logcat -v brief -b events -T 5 2>&1",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -566,7 +586,7 @@ TEST(logcat, logrotate) {
|
|||
FILE *fp;
|
||||
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
|
||||
if (fp) {
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
int count = 0;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
|
@ -609,7 +629,7 @@ TEST(logcat, logrotate_suffix) {
|
|||
|
||||
FILE *fp;
|
||||
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
int log_file_count = 0;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
|
@ -751,6 +771,82 @@ TEST(logcat, logrotate_continue) {
|
|||
EXPECT_FALSE(system(command));
|
||||
}
|
||||
|
||||
TEST(logcat, logrotate_clear) {
|
||||
static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
|
||||
char tmp_out_dir[sizeof(tmp_out_dir_form)];
|
||||
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
|
||||
|
||||
static const char log_filename[] = "log.txt";
|
||||
static const unsigned num_val = 32;
|
||||
static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n %d -r 1";
|
||||
static const char clear_cmd[] = " -c";
|
||||
static const char cleanup_cmd[] = "rm -rf %s";
|
||||
char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename) + sizeof(clear_cmd) + 32];
|
||||
|
||||
// Run command with all data
|
||||
{
|
||||
snprintf(command, sizeof(command) - sizeof(clear_cmd),
|
||||
logcat_cmd, tmp_out_dir, log_filename, num_val);
|
||||
|
||||
int ret;
|
||||
EXPECT_FALSE((ret = system(command)));
|
||||
if (ret) {
|
||||
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
|
||||
EXPECT_FALSE(system(command));
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
|
||||
EXPECT_NE(nullptr, dir);
|
||||
if (!dir) {
|
||||
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
|
||||
EXPECT_FALSE(system(command));
|
||||
return;
|
||||
}
|
||||
struct dirent *entry;
|
||||
unsigned count = 0;
|
||||
while ((entry = readdir(dir.get()))) {
|
||||
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
|
||||
continue;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, num_val + 1);
|
||||
}
|
||||
|
||||
{
|
||||
// Now with -c option tacked onto the end
|
||||
strcat(command, clear_cmd);
|
||||
|
||||
int ret;
|
||||
EXPECT_FALSE((ret = system(command)));
|
||||
if (ret) {
|
||||
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
|
||||
EXPECT_FALSE(system(command));
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
|
||||
EXPECT_NE(nullptr, dir);
|
||||
if (!dir) {
|
||||
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
|
||||
EXPECT_FALSE(system(command));
|
||||
return;
|
||||
}
|
||||
struct dirent *entry;
|
||||
unsigned count = 0;
|
||||
while ((entry = readdir(dir.get()))) {
|
||||
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0U);
|
||||
}
|
||||
|
||||
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
|
||||
EXPECT_FALSE(system(command));
|
||||
}
|
||||
|
||||
TEST(logcat, logrotate_nodir) {
|
||||
// expect logcat to error out on writing content and exit(1) for nodir
|
||||
EXPECT_EQ(W_EXITCODE(1, 0),
|
||||
|
@ -783,7 +879,7 @@ TEST(logcat, blocking_clear) {
|
|||
" logcat -v brief -b events 2>&1",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
int count = 0;
|
||||
|
||||
|
@ -844,7 +940,7 @@ static bool get_white_black(char **list) {
|
|||
return false;
|
||||
}
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
char *hold = *list;
|
||||
|
@ -873,7 +969,7 @@ static bool get_white_black(char **list) {
|
|||
static bool set_white_black(const char *list) {
|
||||
FILE *fp;
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
|
||||
fp = popen(buffer, "r");
|
||||
|
@ -935,7 +1031,7 @@ TEST(logcat, regex) {
|
|||
FILE *fp;
|
||||
int count = 0;
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid());
|
||||
|
||||
|
@ -968,7 +1064,7 @@ TEST(logcat, maxcount) {
|
|||
FILE *fp;
|
||||
int count = 0;
|
||||
|
||||
char buffer[5120];
|
||||
char buffer[BIG_BUFFER];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
The properties that logd responds to are:
|
||||
The properties that logd and friends react to are:
|
||||
|
||||
name type default description
|
||||
ro.logd.auditd bool true Enable selinux audit daemon
|
||||
|
@ -10,8 +10,16 @@ ro.logd.kernel bool+ svelte+ Enable klogd daemon
|
|||
ro.logd.statistics bool+ svelte+ Enable logcat -S statistics.
|
||||
ro.build.type string if user, logd.statistics &
|
||||
ro.logd.kernel default false.
|
||||
logd.logpersistd.enable bool auto Safe to start logpersist daemon service
|
||||
logd.logpersistd string persist Enable logpersist daemon, "logcatd"
|
||||
turns on logcat -f in logd context.
|
||||
Responds to logcatd, clear and stop.
|
||||
logd.logpersistd.buffer persist logpersistd buffers to collect
|
||||
logd.logpersistd.size persist logpersistd size in MB
|
||||
persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
|
||||
turns on logcat -f in logd context
|
||||
turns on logcat -f in logd context.
|
||||
persist.logd.logpersistd.buffer all logpersistd buffers to collect
|
||||
persist.logd.logpersistd.size 256 logpersistd size in MB
|
||||
persist.logd.size number ro Global default size of the buffer for
|
||||
all log ids at initial startup, at
|
||||
runtime use: logcat -b all -G <value>
|
||||
|
@ -45,6 +53,7 @@ log.tag.<tag> string persist The <tag> specific logging level.
|
|||
persist.log.tag.<tag> string build default for log.tag.<tag>
|
||||
|
||||
NB:
|
||||
- auto - managed by /init
|
||||
- bool+ - "true", "false" and comma separated list of "eng" (forced false if
|
||||
ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
|
||||
true).
|
||||
|
|
Loading…
Reference in a new issue