summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/log/logger.h13
-rw-r--r--liblog/Android.mk6
-rw-r--r--liblog/log_read.c61
-rw-r--r--liblog/log_read_kern.c35
-rw-r--r--logcat/Android.mk4
-rw-r--r--logcat/logcat.cpp130
-rw-r--r--logd/Android.mk7
-rw-r--r--logd/CommandListener.cpp123
-rw-r--r--logd/CommandListener.h7
-rw-r--r--logd/LogBuffer.cpp159
-rw-r--r--logd/LogBuffer.h18
-rw-r--r--logd/LogStatistics.cpp21
-rw-r--r--logd/LogStatistics.h2
-rw-r--r--logd/LogWhiteBlackList.cpp243
-rw-r--r--logd/LogWhiteBlackList.h71
15 files changed, 832 insertions, 68 deletions
diff --git a/include/log/logger.h b/include/log/logger.h
index 8537c1df4..8dab234df 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -140,14 +140,23 @@ struct logger;
140log_id_t android_logger_get_id(struct logger *logger); 140log_id_t android_logger_get_id(struct logger *logger);
141 141
142int android_logger_clear(struct logger *logger); 142int android_logger_clear(struct logger *logger);
143int android_logger_get_log_size(struct logger *logger); 143long android_logger_get_log_size(struct logger *logger);
144int android_logger_get_log_readable_size(struct logger *logger); 144#ifdef USERDEBUG_BUILD
145int android_logger_set_log_size(struct logger *logger, unsigned long size);
146#endif
147long android_logger_get_log_readable_size(struct logger *logger);
145int android_logger_get_log_version(struct logger *logger); 148int android_logger_get_log_version(struct logger *logger);
146 149
147struct logger_list; 150struct logger_list;
148 151
149ssize_t android_logger_get_statistics(struct logger_list *logger_list, 152ssize_t android_logger_get_statistics(struct logger_list *logger_list,
150 char *buf, size_t len); 153 char *buf, size_t len);
154#ifdef USERDEBUG_BUILD
155ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
156 char *buf, size_t len);
157int android_logger_set_prune_list(struct logger_list *logger_list,
158 char *buf, size_t len);
159#endif
151 160
152struct logger_list *android_logger_list_alloc(int mode, 161struct logger_list *android_logger_list_alloc(int mode,
153 unsigned int tail, 162 unsigned int tail,
diff --git a/liblog/Android.mk b/liblog/Android.mk
index c18dc48c1..4fe20db2f 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -22,6 +22,10 @@ else
22liblog_sources := logd_write_kern.c 22liblog_sources := logd_write_kern.c
23endif 23endif
24 24
25ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
26liblog_cflags := -DUSERDEBUG_BUILD=1
27endif
28
25# some files must not be compiled when building against Mingw 29# some files must not be compiled when building against Mingw
26# they correspond to features not used by our host development tools 30# they correspond to features not used by our host development tools
27# which are also hard or even impossible to port to native Win32 31# which are also hard or even impossible to port to native Win32
@@ -80,11 +84,13 @@ include $(BUILD_HOST_STATIC_LIBRARY)
80include $(CLEAR_VARS) 84include $(CLEAR_VARS)
81LOCAL_MODULE := liblog 85LOCAL_MODULE := liblog
82LOCAL_SRC_FILES := $(liblog_target_sources) 86LOCAL_SRC_FILES := $(liblog_target_sources)
87LOCAL_CFLAGS := $(liblog_cflags)
83include $(BUILD_STATIC_LIBRARY) 88include $(BUILD_STATIC_LIBRARY)
84 89
85include $(CLEAR_VARS) 90include $(CLEAR_VARS)
86LOCAL_MODULE := liblog 91LOCAL_MODULE := liblog
87LOCAL_WHOLE_STATIC_LIBRARIES := liblog 92LOCAL_WHOLE_STATIC_LIBRARIES := liblog
93LOCAL_CFLAGS := $(liblog_cflags)
88include $(BUILD_SHARED_LIBRARY) 94include $(BUILD_SHARED_LIBRARY)
89 95
90include $(call first-makefiles-under,$(LOCAL_PATH)) 96include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 6f6fe5f2c..e4acac2af 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -296,11 +296,8 @@ done:
296 return ret; 296 return ret;
297} 297}
298 298
299int android_logger_clear(struct logger *logger) 299static int check_log_success(char *buf, ssize_t ret)
300{ 300{
301 char buf[512];
302
303 ssize_t ret = send_log_msg(logger, "clear %d", buf, sizeof(buf));
304 if (ret < 0) { 301 if (ret < 0) {
305 return ret; 302 return ret;
306 } 303 }
@@ -312,8 +309,16 @@ int android_logger_clear(struct logger *logger)
312 return 0; 309 return 0;
313} 310}
314 311
312int android_logger_clear(struct logger *logger)
313{
314 char buf[512];
315
316 return check_log_success(buf,
317 send_log_msg(logger, "clear %d", buf, sizeof(buf)));
318}
319
315/* returns the total size of the log's ring buffer */ 320/* returns the total size of the log's ring buffer */
316int android_logger_get_log_size(struct logger *logger) 321long android_logger_get_log_size(struct logger *logger)
317{ 322{
318 char buf[512]; 323 char buf[512];
319 324
@@ -326,14 +331,28 @@ int android_logger_get_log_size(struct logger *logger)
326 return -1; 331 return -1;
327 } 332 }
328 333
329 return atoi(buf); 334 return atol(buf);
330} 335}
331 336
337#ifdef USERDEBUG_BUILD
338
339int android_logger_set_log_size(struct logger *logger, unsigned long size)
340{
341 char buf[512];
342
343 snprintf(buf, sizeof(buf), "setLogSize %d %lu",
344 logger ? logger->id : (unsigned) -1, size);
345
346 return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
347}
348
349#endif /* USERDEBUG_BUILD */
350
332/* 351/*
333 * returns the readable size of the log's ring buffer (that is, amount of the 352 * returns the readable size of the log's ring buffer (that is, amount of the
334 * log consumed) 353 * log consumed)
335 */ 354 */
336int android_logger_get_log_readable_size(struct logger *logger) 355long android_logger_get_log_readable_size(struct logger *logger)
337{ 356{
338 char buf[512]; 357 char buf[512];
339 358
@@ -346,7 +365,7 @@ int android_logger_get_log_readable_size(struct logger *logger)
346 return -1; 365 return -1;
347 } 366 }
348 367
349 return atoi(buf); 368 return atol(buf);
350} 369}
351 370
352/* 371/*
@@ -383,6 +402,32 @@ ssize_t android_logger_get_statistics(struct logger_list *logger_list,
383 return send_log_msg(NULL, NULL, buf, len); 402 return send_log_msg(NULL, NULL, buf, len);
384} 403}
385 404
405#ifdef USERDEBUG_BUILD
406
407ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
408 char *buf, size_t len)
409{
410 return send_log_msg(NULL, "getPruneList", buf, len);
411}
412
413int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
414 char *buf, size_t len)
415{
416 const char cmd[] = "setPruneList ";
417 const size_t cmdlen = sizeof(cmd) - 1;
418
419 if (strlen(buf) > (len - cmdlen)) {
420 return -ENOMEM; /* KISS */
421 }
422 memmove(buf + cmdlen, buf, len - cmdlen);
423 buf[len - 1] = '\0';
424 memcpy(buf, cmd, cmdlen);
425
426 return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
427}
428
429#endif /* USERDEBUG_BUILD */
430
386struct logger_list *android_logger_list_alloc(int mode, 431struct logger_list *android_logger_list_alloc(int mode,
387 unsigned int tail, 432 unsigned int tail,
388 pid_t pid) 433 pid_t pid)
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 59a7a0b19..483b6b6d8 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -227,16 +227,26 @@ int android_logger_clear(struct logger *logger)
227} 227}
228 228
229/* returns the total size of the log's ring buffer */ 229/* returns the total size of the log's ring buffer */
230int android_logger_get_log_size(struct logger *logger) 230long android_logger_get_log_size(struct logger *logger)
231{ 231{
232 return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR); 232 return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
233} 233}
234 234
235#ifdef USERDEBUG_BUILD
236
237int android_logger_set_log_size(struct logger *logger UNUSED,
238 unsigned long size UNUSED)
239{
240 return -ENOTSUP;
241}
242
243#endif /* USERDEBUG_BUILD */
244
235/* 245/*
236 * returns the readable size of the log's ring buffer (that is, amount of the 246 * returns the readable size of the log's ring buffer (that is, amount of the
237 * log consumed) 247 * log consumed)
238 */ 248 */
239int android_logger_get_log_readable_size(struct logger *logger) 249long android_logger_get_log_readable_size(struct logger *logger)
240{ 250{
241 return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY); 251 return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
242} 252}
@@ -253,15 +263,34 @@ int android_logger_get_log_version(struct logger *logger)
253/* 263/*
254 * returns statistics 264 * returns statistics
255 */ 265 */
266static const char unsupported[] = "18\nNot Supported\n\f";
256 267
257ssize_t android_logger_get_statistics(struct logger_list *logger_list UNUSED, 268ssize_t android_logger_get_statistics(struct logger_list *logger_list UNUSED,
258 char *buf, size_t len) 269 char *buf, size_t len)
259{ 270{
260 static const char unsupported[] = "18\nNot Supported\n\f";
261 strncpy(buf, unsupported, len); 271 strncpy(buf, unsupported, len);
262 return -ENOTSUP; 272 return -ENOTSUP;
263} 273}
264 274
275#ifdef USERDEBUG_BUILD
276
277ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
278 char *buf, size_t len)
279{
280 strncpy(buf, unsupported, len);
281 return -ENOTSUP;
282}
283
284int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
285 char *buf, size_t len)
286{
287 static const char unsupported_error[] = "Unsupported";
288 strncpy(buf, unsupported, len);
289 return -ENOTSUP;
290}
291
292#endif /* USERDEBUG_BUILD */
293
265struct logger_list *android_logger_list_alloc(int mode, 294struct logger_list *android_logger_list_alloc(int mode,
266 unsigned int tail, 295 unsigned int tail,
267 pid_t pid) 296 pid_t pid)
diff --git a/logcat/Android.mk b/logcat/Android.mk
index b5e27eb45..dd15cb3aa 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -3,6 +3,10 @@
3LOCAL_PATH:= $(call my-dir) 3LOCAL_PATH:= $(call my-dir)
4include $(CLEAR_VARS) 4include $(CLEAR_VARS)
5 5
6ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
7LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
8endif
9
6LOCAL_SRC_FILES:= logcat.cpp event.logtags 10LOCAL_SRC_FILES:= logcat.cpp event.logtags
7 11
8LOCAL_SHARED_LIBRARIES := liblog 12LOCAL_SHARED_LIBRARIES := liblog
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 812e2e08d..00b5ba94b 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -229,8 +229,19 @@ static void show_help(const char *cmd)
229 " 'events' or 'all'. Multiple -b parameters are allowed and\n" 229 " 'events' or 'all'. Multiple -b parameters are allowed and\n"
230 " results are interleaved. The default is -b main -b system.\n" 230 " results are interleaved. The default is -b main -b system.\n"
231 " -B output the log in binary.\n" 231 " -B output the log in binary.\n"
232 " -S output statistics"); 232 " -S output statistics.\n");
233 233
234#ifdef USERDEBUG_BUILD
235
236 fprintf(stderr, "--------------------- eng & userdebug builds only ---------------------------\n"
237 " -G <count> set size of log's ring buffer and exit\n"
238 " -p output prune white and ~black list\n"
239 " -P '<list> ...' set prune white and ~black list; UID, /PID or !(worst UID)\n"
240 " default is ~!, prune worst UID.\n"
241 "-----------------------------------------------------------------------------\n"
242 );
243
244#endif
234 245
235 fprintf(stderr,"\nfilterspecs are a series of \n" 246 fprintf(stderr,"\nfilterspecs are a series of \n"
236 " <tag>[:priority]\n\n" 247 " <tag>[:priority]\n\n"
@@ -279,6 +290,11 @@ int main(int argc, char **argv)
279 int hasSetLogFormat = 0; 290 int hasSetLogFormat = 0;
280 int clearLog = 0; 291 int clearLog = 0;
281 int getLogSize = 0; 292 int getLogSize = 0;
293#ifdef USERDEBUG_BUILD
294 unsigned long setLogSize = 0;
295 int getPruneList = 0;
296 char *setPruneList = NULL;
297#endif
282 int printStatistics = 0; 298 int printStatistics = 0;
283 int mode = O_RDONLY; 299 int mode = O_RDONLY;
284 const char *forceFilters = NULL; 300 const char *forceFilters = NULL;
@@ -305,7 +321,13 @@ int main(int argc, char **argv)
305 for (;;) { 321 for (;;) {
306 int ret; 322 int ret;
307 323
308 ret = getopt(argc, argv, "cdt:T:gsQf:r::n:v:b:BS"); 324 ret = getopt(argc, argv,
325#ifdef USERDEBUG_BUILD
326 "cdt:T:gG:sQf:r::n:v:b:BSpP:"
327#else
328 "cdt:T:gsQf:r::n:v:b:BS"
329#endif
330 );
309 331
310 if (ret < 0) { 332 if (ret < 0) {
311 break; 333 break;
@@ -337,6 +359,55 @@ int main(int argc, char **argv)
337 getLogSize = 1; 359 getLogSize = 1;
338 break; 360 break;
339 361
362#ifdef USERDEBUG_BUILD
363
364 case 'G': {
365 // would use atol if not for the multiplier
366 char *cp = optarg;
367 setLogSize = 0;
368 while (('0' <= *cp) && (*cp <= '9')) {
369 setLogSize *= 10;
370 setLogSize += *cp - '0';
371 ++cp;
372 }
373
374 switch(*cp) {
375 case 'g':
376 case 'G':
377 setLogSize *= 1024;
378 /* FALLTHRU */
379 case 'm':
380 case 'M':
381 setLogSize *= 1024;
382 /* FALLTHRU */
383 case 'k':
384 case 'K':
385 setLogSize *= 1024;
386 /* FALLTHRU */
387 case '\0':
388 break;
389
390 default:
391 setLogSize = 0;
392 }
393
394 if (!setLogSize) {
395 fprintf(stderr, "ERROR: -G <num><multiplier>\n");
396 exit(1);
397 }
398 }
399 break;
400
401 case 'p':
402 getPruneList = 1;
403 break;
404
405 case 'P':
406 setPruneList = optarg;
407 break;
408
409#endif
410
340 case 'b': { 411 case 'b': {
341 if (strcmp(optarg, "all") == 0) { 412 if (strcmp(optarg, "all") == 0) {
342 while (devices) { 413 while (devices) {
@@ -602,8 +673,17 @@ int main(int argc, char **argv)
602 } 673 }
603 } 674 }
604 675
676#ifdef USERDEBUG_BUILD
677
678 if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
679 perror("setLogSize");
680 exit(EXIT_FAILURE);
681 }
682
683#endif
684
605 if (getLogSize) { 685 if (getLogSize) {
606 int size, readable; 686 long size, readable;
607 687
608 size = android_logger_get_log_size(dev->logger); 688 size = android_logger_get_log_size(dev->logger);
609 if (size < 0) { 689 if (size < 0) {
@@ -617,7 +697,7 @@ int main(int argc, char **argv)
617 exit(EXIT_FAILURE); 697 exit(EXIT_FAILURE);
618 } 698 }
619 699
620 printf("%s: ring buffer is %dKb (%dKb consumed), " 700 printf("%s: ring buffer is %ldKb (%ldKb consumed), "
621 "max entry is %db, max payload is %db\n", dev->device, 701 "max entry is %db, max payload is %db\n", dev->device,
622 size / 1024, readable / 1024, 702 size / 1024, readable / 1024,
623 (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD); 703 (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
@@ -626,15 +706,46 @@ int main(int argc, char **argv)
626 dev = dev->next; 706 dev = dev->next;
627 } 707 }
628 708
629 if (printStatistics) { 709#ifdef USERDEBUG_BUILD
710
711 if (setPruneList) {
712 size_t len = strlen(setPruneList) + 32; // margin to allow rc
713 char *buf = (char *) malloc(len);
714
715 strcpy(buf, setPruneList);
716 int ret = android_logger_set_prune_list(logger_list, buf, len);
717 free(buf);
718
719 if (ret) {
720 perror("setPruneList");
721 exit(EXIT_FAILURE);
722 }
723 }
724
725#endif
726
727 if (
728#ifdef USERDEBUG_BUILD
729 printStatistics || getPruneList
730#else
731 printStatistics
732#endif
733 ) {
630 size_t len = 8192; 734 size_t len = 8192;
631 char *buf; 735 char *buf;
632 736
633 for(int retry = 32; 737 for(int retry = 32;
634 (retry >= 0) && ((buf = new char [len])); 738 (retry >= 0) && ((buf = new char [len]));
635 delete [] buf, --retry) { 739 delete [] buf, --retry) {
740#ifdef USERDEBUG_BUILD
741 if (getPruneList) {
742 android_logger_get_prune_list(logger_list, buf, len);
743 } else {
744 android_logger_get_statistics(logger_list, buf, len);
745 }
746#else
636 android_logger_get_statistics(logger_list, buf, len); 747 android_logger_get_statistics(logger_list, buf, len);
637 748#endif
638 buf[len-1] = '\0'; 749 buf[len-1] = '\0';
639 size_t ret = atol(buf) + 1; 750 size_t ret = atol(buf) + 1;
640 if (ret < 4) { 751 if (ret < 4) {
@@ -650,7 +761,7 @@ int main(int argc, char **argv)
650 } 761 }
651 762
652 if (!buf) { 763 if (!buf) {
653 perror("statistics read"); 764 perror("response read");
654 exit(EXIT_FAILURE); 765 exit(EXIT_FAILURE);
655 } 766 }
656 767
@@ -679,6 +790,11 @@ int main(int argc, char **argv)
679 if (getLogSize) { 790 if (getLogSize) {
680 exit(0); 791 exit(0);
681 } 792 }
793#ifdef USERDEBUG_BUILD
794 if (setLogSize || setPruneList) {
795 exit(0);
796 }
797#endif
682 if (clearLog) { 798 if (clearLog) {
683 exit(0); 799 exit(0);
684 } 800 }
diff --git a/logd/Android.mk b/logd/Android.mk
index 3dd8e0f8c..b0bc746c9 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -4,6 +4,10 @@ include $(CLEAR_VARS)
4 4
5LOCAL_MODULE:= logd 5LOCAL_MODULE:= logd
6 6
7ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
8LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
9endif
10
7LOCAL_SRC_FILES := \ 11LOCAL_SRC_FILES := \
8 main.cpp \ 12 main.cpp \
9 LogCommand.cpp \ 13 LogCommand.cpp \
@@ -14,7 +18,8 @@ LOCAL_SRC_FILES := \
14 LogBuffer.cpp \ 18 LogBuffer.cpp \
15 LogBufferElement.cpp \ 19 LogBufferElement.cpp \
16 LogTimes.cpp \ 20 LogTimes.cpp \
17 LogStatistics.cpp 21 LogStatistics.cpp \
22 LogWhiteBlackList.cpp
18 23
19LOCAL_SHARED_LIBRARIES := \ 24LOCAL_SHARED_LIBRARIES := \
20 libsysutils \ 25 libsysutils \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 43a283c10..12b10ca50 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -37,8 +37,15 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
37 // registerCmd(new ShutdownCmd(buf, writer, swl)); 37 // registerCmd(new ShutdownCmd(buf, writer, swl));
38 registerCmd(new ClearCmd(buf)); 38 registerCmd(new ClearCmd(buf));
39 registerCmd(new GetBufSizeCmd(buf)); 39 registerCmd(new GetBufSizeCmd(buf));
40#ifdef USERDEBUG_BUILD
41 registerCmd(new SetBufSizeCmd(buf));
42#endif
40 registerCmd(new GetBufSizeUsedCmd(buf)); 43 registerCmd(new GetBufSizeUsedCmd(buf));
41 registerCmd(new GetStatisticsCmd(buf)); 44 registerCmd(new GetStatisticsCmd(buf));
45#ifdef USERDEBUG_BUILD
46 registerCmd(new SetPruneListCmd(buf));
47 registerCmd(new GetPruneListCmd(buf));
48#endif
42} 49}
43 50
44CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader, 51CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
@@ -110,6 +117,43 @@ int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
110 return 0; 117 return 0;
111} 118}
112 119
120#ifdef USERDEBUG_BUILD
121
122CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
123 : LogCommand("setLogSize")
124 , mBuf(*buf)
125{ }
126
127int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
128 int argc, char **argv) {
129 if (!clientHasLogCredentials(cli)) {
130 cli->sendMsg("Permission Denied");
131 return 0;
132 }
133
134 if (argc < 3) {
135 cli->sendMsg("Missing Argument");
136 return 0;
137 }
138
139 int id = atoi(argv[1]);
140 if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
141 cli->sendMsg("Range Error");
142 return 0;
143 }
144
145 unsigned long size = atol(argv[2]);
146 if (mBuf.setSize((log_id_t) id, size)) {
147 cli->sendMsg("Range Error");
148 return 0;
149 }
150
151 cli->sendMsg("success");
152 return 0;
153}
154
155#endif // USERDEBUG_BUILD
156
113CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) 157CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
114 : LogCommand("getLogSizeUsed") 158 : LogCommand("getLogSizeUsed")
115 , mBuf(*buf) 159 , mBuf(*buf)
@@ -140,6 +184,24 @@ CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
140 , mBuf(*buf) 184 , mBuf(*buf)
141{ } 185{ }
142 186
187static void package_string(char **strp) {
188 const char *a = *strp;
189 if (!a) {
190 a = "";
191 }
192
193 // Calculate total buffer size prefix, count is the string length w/o nul
194 char fmt[32];
195 for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
196 snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
197 }
198
199 char *b = *strp;
200 *strp = NULL;
201 asprintf(strp, fmt, a);
202 free(b);
203}
204
143int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli, 205int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
144 int argc, char **argv) { 206 int argc, char **argv) {
145 uid_t uid = cli->getUid(); 207 uid_t uid = cli->getUid();
@@ -167,8 +229,69 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
167 if (!buf) { 229 if (!buf) {
168 cli->sendMsg("Failed"); 230 cli->sendMsg("Failed");
169 } else { 231 } else {
232 package_string(&buf);
170 cli->sendMsg(buf); 233 cli->sendMsg(buf);
171 free(buf); 234 free(buf);
172 } 235 }
173 return 0; 236 return 0;
174} 237}
238
239#ifdef USERDEBUG_BUILD
240
241CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
242 : LogCommand("getPruneList")
243 , mBuf(*buf)
244{ }
245
246int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
247 int /*argc*/, char ** /*argv*/) {
248 char *buf = NULL;
249 mBuf.formatPrune(&buf);
250 if (!buf) {
251 cli->sendMsg("Failed");
252 } else {
253 package_string(&buf);
254 cli->sendMsg(buf);
255 free(buf);
256 }
257 return 0;
258}
259
260CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
261 : LogCommand("setPruneList")
262 , mBuf(*buf)
263{ }
264
265int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
266 int argc, char **argv) {
267 if (!clientHasLogCredentials(cli)) {
268 cli->sendMsg("Permission Denied");
269 return 0;
270 }
271
272 char *cp = NULL;
273 for (int i = 1; i < argc; ++i) {
274 char *p = cp;
275 if (p) {
276 cp = NULL;
277 asprintf(&cp, "%s %s", p, argv[i]);
278 free(p);
279 } else {
280 asprintf(&cp, "%s", argv[i]);
281 }
282 }
283
284 int ret = mBuf.initPrune(cp);
285 free(cp);
286
287 if (ret) {
288 cli->sendMsg("Invalid");
289 return 0;
290 }
291
292 cli->sendMsg("success");
293
294 return 0;
295}
296
297#endif // USERDEBUG_BUILD
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index a84161089..de1dcb90f 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -53,8 +53,15 @@ private:
53 53
54 LogBufferCmd(Clear) 54 LogBufferCmd(Clear)
55 LogBufferCmd(GetBufSize) 55 LogBufferCmd(GetBufSize)
56#ifdef USERDEBUG_BUILD
57 LogBufferCmd(SetBufSize)
58#endif
56 LogBufferCmd(GetBufSizeUsed) 59 LogBufferCmd(GetBufSizeUsed)
57 LogBufferCmd(GetStatistics) 60 LogBufferCmd(GetStatistics)
61#ifdef USERDEBUG_BUILD
62 LogBufferCmd(GetPruneList)
63 LogBufferCmd(SetPruneList)
64#endif
58}; 65};
59 66
60#endif 67#endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index cf172d107..197b7e8b3 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -23,13 +23,25 @@
23 23
24#include "LogBuffer.h" 24#include "LogBuffer.h"
25#include "LogStatistics.h" 25#include "LogStatistics.h"
26#include "LogWhiteBlackList.h"
26#include "LogReader.h" 27#include "LogReader.h"
27 28
29// Default
28#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here? 30#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
31#ifdef USERDEBUG_BUILD
32#define log_buffer_size(id) mMaxSize[id]
33#else
34#define log_buffer_size(id) LOG_BUFFER_SIZE
35#endif
29 36
30LogBuffer::LogBuffer(LastLogTimes *times) 37LogBuffer::LogBuffer(LastLogTimes *times)
31 : mTimes(*times) { 38 : mTimes(*times) {
32 pthread_mutex_init(&mLogElementsLock, NULL); 39 pthread_mutex_init(&mLogElementsLock, NULL);
40#ifdef USERDEBUG_BUILD
41 log_id_for_each(i) {
42 mMaxSize[i] = LOG_BUFFER_SIZE;
43 }
44#endif
33} 45}
34 46
35void LogBuffer::log(log_id_t log_id, log_time realtime, 47void LogBuffer::log(log_id_t log_id, log_time realtime,
@@ -100,8 +112,8 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
100// mLogElementsLock must be held when this function is called. 112// mLogElementsLock must be held when this function is called.
101void LogBuffer::maybePrune(log_id_t id) { 113void LogBuffer::maybePrune(log_id_t id) {
102 size_t sizes = stats.sizes(id); 114 size_t sizes = stats.sizes(id);
103 if (sizes > LOG_BUFFER_SIZE) { 115 if (sizes > log_buffer_size(id)) {
104 size_t sizeOver90Percent = sizes - ((LOG_BUFFER_SIZE * 9) / 10); 116 size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
105 size_t elements = stats.elements(id); 117 size_t elements = stats.elements(id);
106 unsigned long pruneRows = elements * sizeOver90Percent / sizes; 118 unsigned long pruneRows = elements * sizeOver90Percent / sizes;
107 elements /= 10; 119 elements /= 10;
@@ -140,18 +152,23 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
140 size_t worst_sizes = 0; 152 size_t worst_sizes = 0;
141 size_t second_worst_sizes = 0; 153 size_t second_worst_sizes = 0;
142 154
143 LidStatistics &l = stats.id(id); 155#ifdef USERDEBUG_BUILD
144 UidStatisticsCollection::iterator iu; 156 if (mPrune.worstUidEnabled())
145 for (iu = l.begin(); iu != l.end(); ++iu) { 157#endif
146 UidStatistics *u = (*iu); 158 {
147 size_t sizes = u->sizes(); 159 LidStatistics &l = stats.id(id);
148 if (worst_sizes < sizes) { 160 UidStatisticsCollection::iterator iu;
149 second_worst_sizes = worst_sizes; 161 for (iu = l.begin(); iu != l.end(); ++iu) {
150 worst_sizes = sizes; 162 UidStatistics *u = (*iu);
151 worst = u->getUid(); 163 size_t sizes = u->sizes();
152 } 164 if (worst_sizes < sizes) {
153 if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) { 165 second_worst_sizes = worst_sizes;
154 second_worst_sizes = sizes; 166 worst_sizes = sizes;
167 worst = u->getUid();
168 }
169 if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
170 second_worst_sizes = sizes;
171 }
155 } 172 }
156 } 173 }
157 174
@@ -163,7 +180,14 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
163 break; 180 break;
164 } 181 }
165 182
166 if ((e->getLogId() == id) && (e->getUid() == worst)) { 183 if (e->getLogId() != id) {
184 ++it;
185 continue;
186 }
187
188 uid_t uid = e->getUid();
189
190 if (uid == worst) {
167 it = mLogElements.erase(it); 191 it = mLogElements.erase(it);
168 unsigned short len = e->getMsgLen(); 192 unsigned short len = e->getMsgLen();
169 stats.subtract(len, id, worst, e->getPid()); 193 stats.subtract(len, id, worst, e->getPid());
@@ -174,29 +198,60 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
174 break; 198 break;
175 } 199 }
176 worst_sizes -= len; 200 worst_sizes -= len;
177 } else { 201 }
202#ifdef USERDEBUG_BUILD
203 else if (mPrune.naughty(e)) { // BlackListed
204 it = mLogElements.erase(it);
205 stats.subtract(e->getMsgLen(), id, uid, e->getPid());
206 delete e;
207 pruneRows--;
208 if (pruneRows == 0) {
209 break;
210 }
211 }
212#endif
213 else {
178 ++it; 214 ++it;
179 } 215 }
180 } 216 }
181 217
182 if (!kick) { 218 if (!kick
219#ifdef USERDEBUG_BUILD
220 || !mPrune.worstUidEnabled()
221#endif
222 ) {
183 break; // the following loop will ask bad clients to skip/drop 223 break; // the following loop will ask bad clients to skip/drop
184 } 224 }
185 } 225 }
186 226
227#ifdef USERDEBUG_BUILD
228 bool whitelist = false;
229#endif
187 it = mLogElements.begin(); 230 it = mLogElements.begin();
188 while((pruneRows > 0) && (it != mLogElements.end())) { 231 while((pruneRows > 0) && (it != mLogElements.end())) {
189 LogBufferElement *e = *it; 232 LogBufferElement *e = *it;
190 if (e->getLogId() == id) { 233 if (e->getLogId() == id) {
191 if (oldest && (oldest->mStart <= e->getMonotonicTime())) { 234 if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
192 if (stats.sizes(id) > (2 * LOG_BUFFER_SIZE)) { 235#ifdef USERDEBUG_BUILD
193 // kick a misbehaving log reader client off the island 236 if (!whitelist)
194 oldest->release_Locked(); 237#endif
195 } else { 238 {
196 oldest->triggerSkip_Locked(pruneRows); 239 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
240 // kick a misbehaving log reader client off the island
241 oldest->release_Locked();
242 } else {
243 oldest->triggerSkip_Locked(pruneRows);
244 }
197 } 245 }
198 break; 246 break;
199 } 247 }
248#ifdef USERDEBUG_BUILD
249 if (mPrune.nice(e)) { // WhiteListed
250 whitelist = true;
251 it++;
252 continue;
253 }
254#endif
200 it = mLogElements.erase(it); 255 it = mLogElements.erase(it);
201 stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid()); 256 stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
202 delete e; 257 delete e;
@@ -206,6 +261,32 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
206 } 261 }
207 } 262 }
208 263
264#ifdef USERDEBUG_BUILD
265 if (whitelist && (pruneRows > 0)) {
266 it = mLogElements.begin();
267 while((it != mLogElements.end()) && (pruneRows > 0)) {
268 LogBufferElement *e = *it;
269 if (e->getLogId() == id) {
270 if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
271 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
272 // kick a misbehaving log reader client off the island
273 oldest->release_Locked();
274 } else {
275 oldest->triggerSkip_Locked(pruneRows);
276 }
277 break;
278 }
279 it = mLogElements.erase(it);
280 stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
281 delete e;
282 pruneRows--;
283 } else {
284 it++;
285 }
286 }
287 }
288#endif
289
209 LogTimeEntry::unlock(); 290 LogTimeEntry::unlock();
210} 291}
211 292
@@ -224,11 +305,37 @@ unsigned long LogBuffer::getSizeUsed(log_id_t id) {
224 return retval; 305 return retval;
225} 306}
226 307
308#ifdef USERDEBUG_BUILD
309
310// set the total space allocated to "id"
311int LogBuffer::setSize(log_id_t id, unsigned long size) {
312 // Reasonable limits ...
313 if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
314 return -1;
315 }
316 pthread_mutex_lock(&mLogElementsLock);
317 log_buffer_size(id) = size;
318 pthread_mutex_unlock(&mLogElementsLock);
319 return 0;
320}
321
322// get the total space allocated to "id"
323unsigned long LogBuffer::getSize(log_id_t id) {
324 pthread_mutex_lock(&mLogElementsLock);
325 size_t retval = log_buffer_size(id);
326 pthread_mutex_unlock(&mLogElementsLock);
327 return retval;
328}
329
330#else // ! USERDEBUG_BUILD
331
227// get the total space allocated to "id" 332// get the total space allocated to "id"
228unsigned long LogBuffer::getSize(log_id_t /*id*/) { 333unsigned long LogBuffer::getSize(log_id_t /*id*/) {
229 return LOG_BUFFER_SIZE; 334 return log_buffer_size(id);
230} 335}
231 336
337#endif
338
232log_time LogBuffer::flushTo( 339log_time LogBuffer::flushTo(
233 SocketClient *reader, const log_time start, bool privileged, 340 SocketClient *reader, const log_time start, bool privileged,
234 bool (*filter)(const LogBufferElement *element, void *arg), void *arg) { 341 bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
@@ -269,7 +376,7 @@ log_time LogBuffer::flushTo(
269 return max; 376 return max;
270} 377}
271 378
272size_t LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) { 379void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
273 log_time oldest(CLOCK_MONOTONIC); 380 log_time oldest(CLOCK_MONOTONIC);
274 381
275 pthread_mutex_lock(&mLogElementsLock); 382 pthread_mutex_lock(&mLogElementsLock);
@@ -285,9 +392,7 @@ size_t LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask)
285 } 392 }
286 } 393 }
287 394
288 size_t ret = stats.format(strp, uid, logMask, oldest); 395 stats.format(strp, uid, logMask, oldest);
289 396
290 pthread_mutex_unlock(&mLogElementsLock); 397 pthread_mutex_unlock(&mLogElementsLock);
291
292 return ret;
293} 398}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 92dd107a5..0745e5604 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -26,6 +26,7 @@
26#include "LogBufferElement.h" 26#include "LogBufferElement.h"
27#include "LogTimes.h" 27#include "LogTimes.h"
28#include "LogStatistics.h" 28#include "LogStatistics.h"
29#include "LogWhiteBlackList.h"
29 30
30typedef android::List<LogBufferElement *> LogBufferElementCollection; 31typedef android::List<LogBufferElement *> LogBufferElementCollection;
31 32
@@ -35,6 +36,12 @@ class LogBuffer {
35 36
36 LogStatistics stats; 37 LogStatistics stats;
37 38
39#ifdef USERDEBUG_BUILD
40 PruneList mPrune;
41
42 unsigned long mMaxSize[LOG_ID_MAX];
43#endif
44
38public: 45public:
39 LastLogTimes &mTimes; 46 LastLogTimes &mTimes;
40 47
@@ -49,9 +56,18 @@ public:
49 56
50 void clear(log_id_t id); 57 void clear(log_id_t id);
51 unsigned long getSize(log_id_t id); 58 unsigned long getSize(log_id_t id);
59#ifdef USERDEBUG_BUILD
60 int setSize(log_id_t id, unsigned long size);
61#endif
52 unsigned long getSizeUsed(log_id_t id); 62 unsigned long getSizeUsed(log_id_t id);
53 // *strp uses malloc, use free to release. 63 // *strp uses malloc, use free to release.
54 size_t formatStatistics(char **strp, uid_t uid, unsigned int logMask); 64 void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
65
66#ifdef USERDEBUG_BUILD
67 int initPrune(char *cp) { return mPrune.init(cp); }
68 // *strp uses malloc, use free to release.
69 void formatPrune(char **strp) { mPrune.format(strp); }
70#endif
55 71
56private: 72private:
57 void maybePrune(log_id_t id); 73 void maybePrune(log_id_t id);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 50ce442bb..49ee50d0a 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -335,8 +335,8 @@ size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
335 return elements; 335 return elements;
336} 336}
337 337
338size_t LogStatistics::format(char **buf, 338void LogStatistics::format(char **buf,
339 uid_t uid, unsigned int logMask, log_time oldest) { 339 uid_t uid, unsigned int logMask, log_time oldest) {
340 const unsigned short spaces_current = 13; 340 const unsigned short spaces_current = 13;
341 const unsigned short spaces_total = 19; 341 const unsigned short spaces_total = 19;
342 342
@@ -551,20 +551,5 @@ size_t LogStatistics::format(char **buf,
551 } 551 }
552 } 552 }
553 553
554 // Calculate total buffer size prefix 554 *buf = strdup(string.string());
555 char re_fmt[32];
556 size_t ret;
557 for(size_t l = string.length(), y = 0, x = 6;
558 y != x;
559 y = x, x = strlen(re_fmt) - 2) {
560 snprintf(re_fmt, sizeof(re_fmt), "%zu\n%%s\n\f", l + x);
561 ret = l + x;
562 }
563
564 android::String8 intermediate = string.format(re_fmt, string.string());
565 string.clear();
566
567 *buf = strdup(intermediate.string());
568
569 return ret;
570} 555}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index c8eeb45de..d44afa2f6 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -146,7 +146,7 @@ public:
146 pid_t pid = pid_all); 146 pid_t pid = pid_all);
147 147
148 // *strp = malloc, balance with free 148 // *strp = malloc, balance with free
149 size_t format(char **strp, uid_t uid, unsigned int logMask, log_time oldest); 149 void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
150}; 150};
151 151
152#endif // _LOGD_LOG_STATISTICS_H__ 152#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
new file mode 100644
index 000000000..d0ceb9fca
--- /dev/null
+++ b/logd/LogWhiteBlackList.cpp
@@ -0,0 +1,243 @@
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifdef USERDEBUG_BUILD
18
19#include <ctype.h>
20
21#include <utils/String8.h>
22
23#include "LogWhiteBlackList.h"
24
25// White and Black list
26
27Prune::Prune(uid_t uid, pid_t pid)
28 : mUid(uid)
29 , mPid(pid)
30{ }
31
32int Prune::cmp(uid_t uid, pid_t pid) const {
33 if ((mUid == uid_all) || (mUid == uid)) {
34 if (mPid == pid_all) {
35 return 0;
36 }
37 return pid - mPid;
38 }
39 return uid - mUid;
40}
41
42void Prune::format(char **strp) {
43 if (mUid != uid_all) {
44 asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid);
45 } else {
46 // NB: mPid == pid_all can not happen if mUid == uid_all
47 asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid);
48 }
49}
50
51PruneList::PruneList()
52 : mWorstUidEnabled(true) {
53 mNaughty.clear();
54 mNice.clear();
55}
56
57PruneList::~PruneList() {
58 PruneCollection::iterator it;
59 for (it = mNice.begin(); it != mNice.end();) {
60 delete (*it);
61 it = mNice.erase(it);
62 }
63 for (it = mNaughty.begin(); it != mNaughty.end();) {
64 delete (*it);
65 it = mNaughty.erase(it);
66 }
67}
68
69int PruneList::init(char *str) {
70 mWorstUidEnabled = true;
71 PruneCollection::iterator it;
72 for (it = mNice.begin(); it != mNice.end();) {
73 delete (*it);
74 it = mNice.erase(it);
75 }
76 for (it = mNaughty.begin(); it != mNaughty.end();) {
77 delete (*it);
78 it = mNaughty.erase(it);
79 }
80
81 if (!str) {
82 return 0;
83 }
84
85 mWorstUidEnabled = false;
86
87 for(; *str; ++str) {
88 if (isspace(*str)) {
89 continue;
90 }
91
92 PruneCollection *list;
93 if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
94 ++str;
95 // special case, translates to worst UID at priority in blacklist
96 if (*str == '!') {
97 mWorstUidEnabled = true;
98 ++str;
99 if (!*str) {
100 break;
101 }
102 if (!isspace(*str)) {
103 return 1;
104 }
105 continue;
106 }
107 if (!*str) {
108 return 1;
109 }
110 list = &mNaughty;
111 } else {
112 list = &mNice;
113 }
114
115 uid_t uid = Prune::uid_all;
116 if (isdigit(*str)) {
117 uid = 0;
118 do {
119 uid = uid * 10 + *str++ - '0';
120 } while (isdigit(*str));
121 }
122
123 pid_t pid = Prune::pid_all;
124 if (*str == '/') {
125 ++str;
126 if (isdigit(*str)) {
127 pid = 0;
128 do {
129 pid = pid * 10 + *str++ - '0';
130 } while (isdigit(*str));
131 }
132 }
133
134 if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
135 return 1;
136 }
137
138 if (*str && !isspace(*str)) {
139 return 1;
140 }
141
142 // insert sequentially into list
143 PruneCollection::iterator it = list->begin();
144 while (it != list->end()) {
145 Prune *p = *it;
146 int m = uid - p->mUid;
147 if (m == 0) {
148 if (p->mPid == p->pid_all) {
149 break;
150 }
151 if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
152 it = list->erase(it);
153 continue;
154 }
155 m = pid - p->mPid;
156 }
157 if (m >= 0) {
158 if (m > 0) {
159 list->insert(it, new Prune(uid,pid));
160 }
161 break;
162 }
163 ++it;
164 }
165 if (it == list->end()) {
166 list->push_back(new Prune(uid,pid));
167 }
168 if (!*str) {
169 break;
170 }
171 }
172
173 return 0;
174}
175
176void PruneList::format(char **strp) {
177 if (*strp) {
178 free(*strp);
179 *strp = NULL;
180 }
181
182 static const char nice_format[] = " %s";
183 const char *fmt = nice_format + 1;
184
185 android::String8 string;
186
187 if (mWorstUidEnabled) {
188 string.setTo("~!");
189 fmt = nice_format;
190 }
191
192 PruneCollection::iterator it;
193
194 for (it = mNice.begin(); it != mNice.end(); ++it) {
195 char *a = NULL;
196 (*it)->format(&a);
197
198 string.appendFormat(fmt, a);
199 fmt = nice_format;
200
201 free(a);
202 }
203
204 static const char naughty_format[] = " ~%s";
205 fmt = naughty_format + (*fmt != ' ');
206 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
207 char *a = NULL;
208 (*it)->format(&a);
209
210 string.appendFormat(fmt, a);
211 fmt = naughty_format;
212
213 free(a);
214 }
215
216 *strp = strdup(string.string());
217}
218
219// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
220// If there is scaling issues, resort to a better algorithm than linear
221// based on these assumptions.
222
223bool PruneList::naughty(LogBufferElement *element) {
224 PruneCollection::iterator it;
225 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
226 if (!(*it)->cmp(element)) {
227 return true;
228 }
229 }
230 return false;
231}
232
233bool PruneList::nice(LogBufferElement *element) {
234 PruneCollection::iterator it;
235 for (it = mNice.begin(); it != mNice.end(); ++it) {
236 if (!(*it)->cmp(element)) {
237 return true;
238 }
239 }
240 return false;
241}
242
243#endif // USERDEBUG_BUILD
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
new file mode 100644
index 000000000..769d6513a
--- /dev/null
+++ b/logd/LogWhiteBlackList.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LOGD_LOG_WHITE_BLACK_LIST_H__
18#define _LOGD_LOG_WHITE_BLACK_LIST_H__
19
20#include <sys/types.h>
21
22#include <utils/List.h>
23
24#include <LogBufferElement.h>
25
26// White and Blacklist
27
28class Prune {
29 friend class PruneList;
30
31 const uid_t mUid;
32 const pid_t mPid;
33 int cmp(uid_t uid, pid_t pid) const;
34
35public:
36 static const uid_t uid_all = (uid_t) -1;
37 static const pid_t pid_all = (pid_t) -1;
38
39 Prune(uid_t uid, pid_t pid);
40
41 uid_t getUid() const { return mUid; }
42 pid_t getPid() const { return mPid; }
43
44 int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
45
46 // *strp is malloc'd, use free to release
47 void format(char **strp);
48};
49
50typedef android::List<Prune *> PruneCollection;
51
52class PruneList {
53 PruneCollection mNaughty;
54 PruneCollection mNice;
55 bool mWorstUidEnabled;
56
57public:
58 PruneList();
59 ~PruneList();
60
61 int init(char *str);
62
63 bool naughty(LogBufferElement *element);
64 bool nice(LogBufferElement *element);
65 bool worstUidEnabled() const { return mWorstUidEnabled; }
66
67 // *strp is malloc'd, use free to release
68 void format(char **strp);
69};
70
71#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__