• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

system/corennnnn


Commit MetaInfo

修訂56efe020b74d12456e96db8bd1937e15a97403eb (tree)
時間2016-07-21 13:07:25
作者Thierry Strudel <tstrudel@goog...>
CommiterAndroid (Google) Code Review

Log Message

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

Change Summary

差異

--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -278,61 +278,59 @@ static void show_help(const char *cmd)
278278 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
279279
280280 fprintf(stderr, "options include:\n"
281- " -s Set default filter to silent.\n"
282- " Like specifying filterspec '*:S'\n"
283- " -f <filename> Log to file. Default is stdout\n"
284- " --file=<filename>\n"
285- " -r <kbytes> Rotate log every kbytes. Requires -f\n"
286- " --rotate-kbytes=<kbytes>\n"
287- " -n <count> Sets max number of rotated logs to <count>, default 4\n"
288- " --rotate-count=<count>\n"
289- " -v <format> Sets the log print format, where <format> is:\n"
290- " --format=<format>\n"
291- " brief color epoch long monotonic printable process raw\n"
292- " tag thread threadtime time uid usec UTC year zone\n\n"
293- " -D print dividers between each log buffer\n"
294- " --dividers\n"
295- " -c clear (flush) the entire log and exit\n"
296- " --clear\n"
297- " -d dump the log and then exit (don't block)\n"
298- " -e <expr> only print lines where the log message matches <expr>\n"
299- " --regex <expr> where <expr> is a regular expression\n"
300- " -m <count> quit after printing <count> lines. This is meant to be\n"
301- " --max-count=<count> paired with --regex, but will work on its own.\n"
302- " --print paired with --regex and --max-count to let content bypass\n"
281+ " -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
282+ " -f <file>, --file=<file> Log to file. Default is stdout\n"
283+ " -r <kbytes>, --rotate-kbytes=<kbytes>\n"
284+ " Rotate log every kbytes. Requires -f option\n"
285+ " -n <count>, --rotate-count=<count>\n"
286+ " Sets max number of rotated logs to <count>, default 4\n"
287+ " -v <format>, --format=<format>\n"
288+ " Sets the log print format, where <format> is:\n"
289+ " brief color epoch long monotonic printable process raw\n"
290+ " tag thread threadtime time uid usec UTC year zone\n"
291+ " -D, --dividers Print dividers between each log buffer\n"
292+ " -c, --clear Clear (flush) the entire log and exit\n"
293+ " if Log to File specified, clear fileset instead\n"
294+ " -d Dump the log and then exit (don't block)\n"
295+ " -e <expr>, --regex=<expr>\n"
296+ " Only print lines where the log message matches <expr>\n"
297+ " where <expr> is a regular expression\n"
298+ // Leave --head undocumented as alias for -m
299+ " -m <count>, --max-count=<count>\n"
300+ " Quit after printing <count> lines. This is meant to be\n"
301+ " paired with --regex, but will work on its own.\n"
302+ " --print Paired with --regex and --max-count to let content bypass\n"
303303 " regex filter but still stop at number of matches.\n"
304- " -t <count> print only the most recent <count> lines (implies -d)\n"
305- " -t '<time>' print most recent lines since specified time (implies -d)\n"
306- " -T <count> print only the most recent <count> lines (does not imply -d)\n"
307- " -T '<time>' print most recent lines since specified time (not imply -d)\n"
304+ // Leave --tail undocumented as alias for -t
305+ " -t <count> Print only the most recent <count> lines (implies -d)\n"
306+ " -t '<time>' Print most recent lines since specified time (implies -d)\n"
307+ " -T <count> Print only the most recent <count> lines (does not imply -d)\n"
308+ " -T '<time>' Print most recent lines since specified time (not imply -d)\n"
308309 " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
309310 " 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
310- " -g get the size of the log's ring buffer and exit\n"
311- " --buffer-size\n"
312- " -G <size> set size of log ring buffer, may suffix with K or M.\n"
313- " --buffer-size=<size>\n"
314- " -L dump logs from prior to last reboot\n"
315- " --last\n"
311+ " -g, --buffer-size Get the size of the ring buffer.\n"
312+ " -G <size>, --buffer-size=<size>\n"
313+ " Set size of log ring buffer, may suffix with K or M.\n"
314+ " -L, -last Dump logs from prior to last reboot\n"
316315 // Leave security (Device Owner only installations) and
317316 // kernel (userdebug and eng) buffers undocumented.
318- " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
319- " --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
320- " parameters are allowed and results are interleaved. The\n"
321- " default is -b main -b system -b crash.\n"
322- " -B output the log in binary.\n"
323- " --binary\n"
324- " -S output statistics.\n"
325- " --statistics\n"
326- " -p print prune white and ~black list. Service is specified as\n"
327- " --prune UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
317+ " -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
318+ " 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
319+ " Multiple -b parameters or comma separated list of buffers are\n"
320+ " allowed. Buffers interleaved. Default -b main,system,crash.\n"
321+ " -B, --binary Output the log in binary.\n"
322+ " -S, --statistics Output statistics.\n"
323+ " -p, --prune Print prune white and ~black list. Service is specified as\n"
324+ " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
328325 " with ~, otherwise weighed for longevity if unadorned. All\n"
329326 " other pruning activity is oldest first. Special case ~!\n"
330327 " represents an automatic quicker pruning for the noisiest\n"
331328 " UID as determined by the current statistics.\n"
332- " -P '<list> ...' set prune white and ~black list, using same format as\n"
333- " --prune='<list> ...' printed above. Must be quoted.\n"
329+ " -P '<list> ...', --prune='<list> ...'\n"
330+ " Set prune white and ~black list, using same format as\n"
331+ " listed above. Must be quoted.\n"
334332 " --pid=<pid> Only prints logs from the given pid.\n"
335- // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
333+ // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
336334 " --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
337335 " comes first. Improves efficiency of polling by providing\n"
338336 " an about-to-wrap wakeup.\n");
@@ -765,111 +763,63 @@ int main(int argc, char **argv)
765763 break;
766764
767765 case 'b': {
768- if (strcmp(optarg, "default") == 0) {
769- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
770- switch (i) {
771- case LOG_ID_SECURITY:
772- case LOG_ID_EVENTS:
773- continue;
774- case LOG_ID_MAIN:
775- case LOG_ID_SYSTEM:
776- case LOG_ID_CRASH:
777- break;
778- default:
779- continue;
780- }
781-
782- const char *name = android_log_id_to_name((log_id_t)i);
783- log_id_t log_id = android_name_to_log_id(name);
784-
785- if (log_id != (log_id_t)i) {
786- continue;
787- }
788-
789- bool found = false;
790- for (dev = devices; dev; dev = dev->next) {
791- if (!strcmp(optarg, dev->device)) {
792- found = true;
793- break;
794- }
795- if (!dev->next) {
796- break;
797- }
798- }
799- if (found) {
800- break;
801- }
802-
803- log_device_t* d = new log_device_t(name, false);
766+ unsigned idMask = 0;
767+ while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
768+ if (strcmp(optarg, "default") == 0) {
769+ idMask |= (1 << LOG_ID_MAIN) |
770+ (1 << LOG_ID_SYSTEM) |
771+ (1 << LOG_ID_CRASH);
772+ } else if (strcmp(optarg, "all") == 0) {
773+ idMask = (unsigned)-1;
774+ } else {
775+ log_id_t log_id = android_name_to_log_id(optarg);
776+ const char *name = android_log_id_to_name(log_id);
804777
805- if (dev) {
806- dev->next = d;
807- dev = d;
808- } else {
809- devices = dev = d;
778+ if (strcmp(name, optarg) != 0) {
779+ logcat_panic(true, "unknown buffer %s\n", optarg);
810780 }
811- g_devCount++;
781+ idMask |= (1 << log_id);
812782 }
813- break;
783+ optarg = NULL;
814784 }
815785
816- if (strcmp(optarg, "all") == 0) {
817- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
818- const char *name = android_log_id_to_name((log_id_t)i);
819- log_id_t log_id = android_name_to_log_id(name);
786+ for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
787+ const char *name = android_log_id_to_name((log_id_t)i);
788+ log_id_t log_id = android_name_to_log_id(name);
820789
821- if (log_id != (log_id_t)i) {
822- continue;
823- }
790+ if (log_id != (log_id_t)i) {
791+ continue;
792+ }
793+ if ((idMask & (1 << i)) == 0) {
794+ continue;
795+ }
824796
825- bool found = false;
826- for (dev = devices; dev; dev = dev->next) {
827- if (!strcmp(optarg, dev->device)) {
828- found = true;
829- break;
830- }
831- if (!dev->next) {
832- break;
833- }
834- }
835- if (found) {
797+ bool found = false;
798+ for (dev = devices; dev; dev = dev->next) {
799+ if (!strcmp(name, dev->device)) {
800+ found = true;
836801 break;
837802 }
838-
839- bool binary = !strcmp(name, "events") ||
840- !strcmp(name, "security");
841- log_device_t* d = new log_device_t(name, binary);
842-
843- if (dev) {
844- dev->next = d;
845- dev = d;
846- } else {
847- devices = dev = d;
803+ if (!dev->next) {
804+ break;
848805 }
849- g_devCount++;
850806 }
851- break;
852- }
807+ if (found) {
808+ continue;
809+ }
853810
854- bool binary = !(strcmp(optarg, "events") &&
855- strcmp(optarg, "security"));
811+ bool binary = !strcmp(name, "events") ||
812+ !strcmp(name, "security");
813+ log_device_t* d = new log_device_t(name, binary);
856814
857- if (devices) {
858- dev = devices;
859- while (dev->next) {
860- if (!strcmp(optarg, dev->device)) {
861- dev = NULL;
862- break;
863- }
864- dev = dev->next;
865- }
866815 if (dev) {
867- dev->next = new log_device_t(optarg, binary);
816+ dev->next = d;
817+ dev = d;
818+ } else {
819+ devices = dev = d;
868820 }
869- } else {
870- devices = new log_device_t(optarg, binary);
821+ g_devCount++;
871822 }
872- g_devCount++;
873823 }
874824 break;
875825
@@ -1084,7 +1034,35 @@ int main(int argc, char **argv)
10841034 }
10851035
10861036 if (clearLog) {
1087- if (android_logger_clear(dev->logger)) {
1037+ if (g_outputFileName) {
1038+ int maxRotationCountDigits =
1039+ (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
1040+
1041+ for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
1042+ char *file;
1043+
1044+ if (i == 0) {
1045+ asprintf(&file, "%s", g_outputFileName);
1046+ } else {
1047+ asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
1048+ }
1049+
1050+ if (!file) {
1051+ perror("while clearing log files");
1052+ clearFail = clearFail ?: dev->device;
1053+ break;
1054+ }
1055+
1056+ err = unlink(file);
1057+
1058+ if (err < 0 && errno != ENOENT && clearFail == NULL) {
1059+ perror("while clearing log files");
1060+ clearFail = dev->device;
1061+ }
1062+
1063+ free(file);
1064+ }
1065+ } else if (android_logger_clear(dev->logger)) {
10881066 clearFail = clearFail ?: dev->device;
10891067 }
10901068 }
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -1,11 +1,62 @@
1+#
2+# init scriptures for logcatd persistent logging.
3+#
4+# Make sure any property changes are only performed with /data mounted, after
5+# post-fs-data state because otherwise behavior is undefined. The exceptions
6+# are device adjustments for logcatd service properties (persist.* overrides
7+# notwithstanding) for logd.logpersistd.size and logd.logpersistd.buffer.
8+
9+# persist to non-persistent trampolines to permit device properties can be
10+# overridden when /data mounts, or during runtime.
11+on property:persist.logd.logpersistd.size=256
12+ setprop persist.logd.logpersistd.size ""
13+ setprop logd.logpersistd.size ""
14+
15+on property:persist.logd.logpersistd.size=*
16+ # expect /init to report failure if property empty (default)
17+ setprop logd.logpersistd.size ${persist.logd.logpersistd.size}
18+
19+on property:persist.logd.logpersistd.buffer=all
20+ setprop persist.logd.logpersistd.buffer ""
21+ setprop logd.logpersistd.buffer ""
22+
23+on property:persist.logd.logpersistd.buffer=*
24+ # expect /init to report failure if property empty (default)
25+ setprop logd.logpersistd.buffer ${persist.logd.logpersistd.buffer}
26+
127 on property:persist.logd.logpersistd=logcatd
28+ setprop logd.logpersistd logcatd
29+
30+# enable, prep and start logcatd service
31+on load_persist_props_action
32+ setprop logd.logpersistd.enable true
33+
34+on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd
235 # all exec/services are called with umask(077), so no gain beyond 0700
336 mkdir /data/misc/logd 0700 logd log
437 # logd for write to /data/misc/logd, log group for read from pstore (-L)
5- 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}
38+ 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}
639 start logcatd
740
8-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}
41+# stop logcatd service and clear data
42+on property:logd.logpersistd.enable=true && property:logd.logpersistd=clear
43+ setprop persist.logd.logpersistd ""
44+ stop logcatd
45+ # logd for clear of only our files in /data/misc/logd
46+ exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${logd.logpersistd.size:-256}
47+ setprop logd.logpersistd ""
48+
49+# stop logcatd service
50+on property:logd.logpersistd=stop
51+ setprop persist.logd.logpersistd ""
52+ stop logcatd
53+ setprop logd.logpersistd ""
54+
55+on property:logd.logpersistd.enable=false
56+ stop logcatd
57+
58+# logcatd service
59+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}
960 class late_start
1061 disabled
1162 # logd for write to /data/misc/logd, log group for read from log daemon
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -8,8 +8,16 @@ userdebug|eng) ;;
88 ;;
99 esac
1010
11-data=/data/misc/logd
1211 property=persist.logd.logpersistd
12+
13+case `getprop ${property#persist.}.enable` in
14+true) ;;
15+*) echo "${progname} - Disabled"
16+ exit 1
17+ ;;
18+esac
19+
20+data=/data/misc/logd
1321 service=logcatd
1422 size_default=256
1523 buffer_default=all
@@ -69,14 +77,11 @@ case ${progname} in
6977 su logd xargs cat
7078 ;;
7179 *.start)
72- current_buffer="`getprop ${property}.buffer`"
73- current_size="`getprop ${property}.size`"
74- if [ "${service}" = "`getprop ${property}`" ]; then
80+ current_buffer="`getprop ${property#persist.}.buffer`"
81+ current_size="`getprop ${property#persist.}.size`"
82+ if [ "${service}" = "`getprop ${property#persist.}`" ]; then
7583 if [ "true" = "${clear}" ]; then
76- su root stop ${service}
77- su root setprop ${property} ""
78- # 20ms done, guarantees content stop before rm
79- sleep 1
84+ setprop ${property#persist.} "clear"
8085 elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
8186 echo "ERROR: Changing existing collection parameters from" >&2
8287 if [ "${buffer}" != "${current_buffer}" ]; then
@@ -98,21 +103,31 @@ case ${progname} in
98103 echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
99104 exit 1
100105 fi
101- fi
102- if [ "true" = "${clear}" ]; then
103- su logd,misc rm -rf "${data}"
106+ elif [ "true" = "${clear}" ]; then
107+ setprop ${property#persist.} "clear"
104108 fi
105109 if [ -n "${buffer}${current_buffer}" ]; then
106- su root setprop ${property}.buffer "${buffer}"
110+ setprop ${property}.buffer "${buffer}"
111+ if [ -z "${buffer}" ]; then
112+ # deal with trampoline for empty properties
113+ setprop ${property#persist.}.buffer ""
114+ fi
107115 fi
108116 if [ -n "${size}${current_size}" ]; then
109- su root setprop ${property}.size "${size}"
117+ setprop ${property}.size "${size}"
118+ if [ -z "${size}" ]; then
119+ # deal with trampoline for empty properties
120+ setprop ${property#persist.}.size ""
121+ fi
110122 fi
123+ while [ "clear" = "`getprop ${property#persist.}`" ]; do
124+ continue
125+ done
111126 # ${service}.rc does the heavy lifting with the following trigger
112- su root setprop ${property} ${service}
113- getprop ${property}
127+ setprop ${property} ${service}
114128 # 20ms done, to permit process feedback check
115129 sleep 1
130+ getprop ${property#persist.}
116131 # also generate an error return code if not found running, bonus
117132 ps -t | grep "${data##*/}.*${service%d}"
118133 ;;
@@ -120,19 +135,24 @@ case ${progname} in
120135 if [ -n "${size}${buffer}" ]; then
121136 echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
122137 fi
123- su root stop ${service}
124- su root setprop ${property} ""
125- if [ -n "`getprop ${property}.buffer`" ]; then
126- su root setprop ${property}.buffer ""
138+ if [ "true" = "${clear}" ]; then
139+ setprop ${property} "clear"
140+ else
141+ setprop ${property} "stop"
127142 fi
128- if [ -n "`getprop ${property}.size`" ]; then
129- su root setprop ${property}.size ""
143+ if [ -n "`getprop ${property#persist.}.buffer`" ]; then
144+ setprop ${property}.buffer ""
145+ # deal with trampoline for empty properties
146+ setprop ${property#persist.}.buffer ""
130147 fi
131- if [ "true" = "${clear}" ]; then
132- # 20ms done, guarantees content stop before rm
133- sleep 1
134- su logd,misc rm -rf "${data}"
148+ if [ -n "`getprop ${property#persist.}.size`" ]; then
149+ setprop ${property}.size ""
150+ # deal with trampoline for empty properties
151+ setprop ${property#persist.}.size ""
135152 fi
153+ while [ "clear" = "`getprop ${property#persist.}`" ]; do
154+ continue
155+ done
136156 ;;
137157 *)
138158 echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -28,6 +28,8 @@
2828 #include <log/logger.h>
2929 #include <log/log_read.h>
3030
31+#define BIG_BUFFER (5 * 1024)
32+
3133 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
3234 // non-syscall libs. Since we are only using this in the emergency of
3335 // a signal to stuff a terminating code into the logs, we will spin rather
@@ -52,7 +54,7 @@ TEST(logcat, buckets) {
5254 "logcat -b radio -b events -b system -b main -d 2>/dev/null",
5355 "r")));
5456
55- char buffer[5120];
57+ char buffer[BIG_BUFFER];
5658
5759 int ids = 0;
5860 int count = 0;
@@ -100,7 +102,7 @@ TEST(logcat, year) {
100102 "logcat -v long -v year -b all -t 3 2>/dev/null",
101103 "r")));
102104
103- char buffer[5120];
105+ char buffer[BIG_BUFFER];
104106
105107 int count = 0;
106108
@@ -163,7 +165,7 @@ TEST(logcat, tz) {
163165 "logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
164166 "r")));
165167
166- char buffer[5120];
168+ char buffer[BIG_BUFFER];
167169
168170 count = 0;
169171
@@ -187,7 +189,7 @@ TEST(logcat, ntz) {
187189 "logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
188190 "r")));
189191
190- char buffer[5120];
192+ char buffer[BIG_BUFFER];
191193
192194 int count = 0;
193195
@@ -207,7 +209,7 @@ void do_tail(int num) {
207209 int count;
208210
209211 do {
210- char buffer[5120];
212+ char buffer[BIG_BUFFER];
211213
212214 snprintf(buffer, sizeof(buffer),
213215 "logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
@@ -250,7 +252,7 @@ TEST(logcat, tail_time) {
250252
251253 ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
252254
253- char buffer[5120];
255+ char buffer[BIG_BUFFER];
254256 char *last_timestamp = NULL;
255257 char *first_timestamp = NULL;
256258 int count = 0;
@@ -313,7 +315,7 @@ TEST(logcat, End_to_End) {
313315 "logcat -v brief -b events -t 100 2>/dev/null",
314316 "r")));
315317
316- char buffer[5120];
318+ char buffer[BIG_BUFFER];
317319
318320 int count = 0;
319321
@@ -337,15 +339,17 @@ TEST(logcat, End_to_End) {
337339 ASSERT_EQ(1, count);
338340 }
339341
340-TEST(logcat, get_size) {
342+int get_groups(const char *cmd) {
341343 FILE *fp;
342344
343345 // NB: crash log only available in user space
344- ASSERT_TRUE(NULL != (fp = popen(
345- "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null",
346- "r")));
346+ EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
347+
348+ if (fp == NULL) {
349+ return 0;
350+ }
347351
348- char buffer[5120];
352+ char buffer[BIG_BUFFER];
349353
350354 int count = 0;
351355
@@ -405,7 +409,23 @@ TEST(logcat, get_size) {
405409
406410 pclose(fp);
407411
408- ASSERT_EQ(4, count);
412+ return count;
413+}
414+
415+TEST(logcat, get_size) {
416+ ASSERT_EQ(4, get_groups(
417+ "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null"));
418+}
419+
420+// duplicate test for get_size, but use comma-separated list of buffers
421+TEST(logcat, multiple_buffer) {
422+ ASSERT_EQ(4, get_groups(
423+ "logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
424+}
425+
426+TEST(logcat, bad_buffer) {
427+ ASSERT_EQ(0, get_groups(
428+ "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
409429 }
410430
411431 static void caught_blocking(int /*signum*/)
@@ -434,7 +454,7 @@ TEST(logcat, blocking) {
434454 " logcat -v brief -b events 2>&1",
435455 "r")));
436456
437- char buffer[5120];
457+ char buffer[BIG_BUFFER];
438458
439459 int count = 0;
440460
@@ -503,7 +523,7 @@ TEST(logcat, blocking_tail) {
503523 " logcat -v brief -b events -T 5 2>&1",
504524 "r")));
505525
506- char buffer[5120];
526+ char buffer[BIG_BUFFER];
507527
508528 int count = 0;
509529
@@ -566,7 +586,7 @@ TEST(logcat, logrotate) {
566586 FILE *fp;
567587 EXPECT_TRUE(NULL != (fp = popen(command, "r")));
568588 if (fp) {
569- char buffer[5120];
589+ char buffer[BIG_BUFFER];
570590 int count = 0;
571591
572592 while (fgets(buffer, sizeof(buffer), fp)) {
@@ -609,7 +629,7 @@ TEST(logcat, logrotate_suffix) {
609629
610630 FILE *fp;
611631 EXPECT_TRUE(NULL != (fp = popen(command, "r")));
612- char buffer[5120];
632+ char buffer[BIG_BUFFER];
613633 int log_file_count = 0;
614634
615635 while (fgets(buffer, sizeof(buffer), fp)) {
@@ -751,6 +771,82 @@ TEST(logcat, logrotate_continue) {
751771 EXPECT_FALSE(system(command));
752772 }
753773
774+TEST(logcat, logrotate_clear) {
775+ static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
776+ char tmp_out_dir[sizeof(tmp_out_dir_form)];
777+ ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
778+
779+ static const char log_filename[] = "log.txt";
780+ static const unsigned num_val = 32;
781+ static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n %d -r 1";
782+ static const char clear_cmd[] = " -c";
783+ static const char cleanup_cmd[] = "rm -rf %s";
784+ char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename) + sizeof(clear_cmd) + 32];
785+
786+ // Run command with all data
787+ {
788+ snprintf(command, sizeof(command) - sizeof(clear_cmd),
789+ logcat_cmd, tmp_out_dir, log_filename, num_val);
790+
791+ int ret;
792+ EXPECT_FALSE((ret = system(command)));
793+ if (ret) {
794+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
795+ EXPECT_FALSE(system(command));
796+ return;
797+ }
798+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
799+ EXPECT_NE(nullptr, dir);
800+ if (!dir) {
801+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
802+ EXPECT_FALSE(system(command));
803+ return;
804+ }
805+ struct dirent *entry;
806+ unsigned count = 0;
807+ while ((entry = readdir(dir.get()))) {
808+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
809+ continue;
810+ }
811+ ++count;
812+ }
813+ EXPECT_EQ(count, num_val + 1);
814+ }
815+
816+ {
817+ // Now with -c option tacked onto the end
818+ strcat(command, clear_cmd);
819+
820+ int ret;
821+ EXPECT_FALSE((ret = system(command)));
822+ if (ret) {
823+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
824+ EXPECT_FALSE(system(command));
825+ return;
826+ }
827+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
828+ EXPECT_NE(nullptr, dir);
829+ if (!dir) {
830+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
831+ EXPECT_FALSE(system(command));
832+ return;
833+ }
834+ struct dirent *entry;
835+ unsigned count = 0;
836+ while ((entry = readdir(dir.get()))) {
837+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
838+ continue;
839+ }
840+ fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name);
841+ ++count;
842+ }
843+ EXPECT_EQ(count, 0U);
844+ }
845+
846+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
847+ EXPECT_FALSE(system(command));
848+}
849+
754850 TEST(logcat, logrotate_nodir) {
755851 // expect logcat to error out on writing content and exit(1) for nodir
756852 EXPECT_EQ(W_EXITCODE(1, 0),
@@ -783,7 +879,7 @@ TEST(logcat, blocking_clear) {
783879 " logcat -v brief -b events 2>&1",
784880 "r")));
785881
786- char buffer[5120];
882+ char buffer[BIG_BUFFER];
787883
788884 int count = 0;
789885
@@ -844,7 +940,7 @@ static bool get_white_black(char **list) {
844940 return false;
845941 }
846942
847- char buffer[5120];
943+ char buffer[BIG_BUFFER];
848944
849945 while (fgets(buffer, sizeof(buffer), fp)) {
850946 char *hold = *list;
@@ -873,7 +969,7 @@ static bool get_white_black(char **list) {
873969 static bool set_white_black(const char *list) {
874970 FILE *fp;
875971
876- char buffer[5120];
972+ char buffer[BIG_BUFFER];
877973
878974 snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
879975 fp = popen(buffer, "r");
@@ -935,7 +1031,7 @@ TEST(logcat, regex) {
9351031 FILE *fp;
9361032 int count = 0;
9371033
938- char buffer[5120];
1034+ char buffer[BIG_BUFFER];
9391035
9401036 snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid());
9411037
@@ -968,7 +1064,7 @@ TEST(logcat, maxcount) {
9681064 FILE *fp;
9691065 int count = 0;
9701066
971- char buffer[5120];
1067+ char buffer[BIG_BUFFER];
9721068
9731069 snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());
9741070
--- a/logd/README.property
+++ b/logd/README.property
@@ -1,4 +1,4 @@
1-The properties that logd responds to are:
1+The properties that logd and friends react to are:
22
33 name type default description
44 ro.logd.auditd bool true Enable selinux audit daemon
@@ -10,8 +10,16 @@ ro.logd.kernel bool+ svelte+ Enable klogd daemon
1010 ro.logd.statistics bool+ svelte+ Enable logcat -S statistics.
1111 ro.build.type string if user, logd.statistics &
1212 ro.logd.kernel default false.
13+logd.logpersistd.enable bool auto Safe to start logpersist daemon service
14+logd.logpersistd string persist Enable logpersist daemon, "logcatd"
15+ turns on logcat -f in logd context.
16+ Responds to logcatd, clear and stop.
17+logd.logpersistd.buffer persist logpersistd buffers to collect
18+logd.logpersistd.size persist logpersistd size in MB
1319 persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
14- turns on logcat -f in logd context
20+ turns on logcat -f in logd context.
21+persist.logd.logpersistd.buffer all logpersistd buffers to collect
22+persist.logd.logpersistd.size 256 logpersistd size in MB
1523 persist.logd.size number ro Global default size of the buffer for
1624 all log ids at initial startup, at
1725 runtime use: logcat -b all -G <value>
@@ -45,6 +53,7 @@ log.tag.<tag> string persist The <tag> specific logging level.
4553 persist.log.tag.<tag> string build default for log.tag.<tag>
4654
4755 NB:
56+- auto - managed by /init
4857 - bool+ - "true", "false" and comma separated list of "eng" (forced false if
4958 ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
5059 true).