blob: c8fcf46a38905f67f65d430576352be7131cc169 [file] [log] [blame]
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001/*
Elliott Hughesdaf63992021-11-16 18:45:06 -08002 * Copyright (C) 2006 The Android Open Source Project
Mark Salyzynd8b454f2017-02-10 13:09:07 -08003 *
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 */
The Android Open Source Project190995d2009-03-03 19:32:55 -080016
Mark Salyzyn12af9652013-12-13 11:10:11 -080017#include <ctype.h>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070018#include <dirent.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080019#include <errno.h>
Tom Cherry96840882019-12-06 10:25:37 -080020#include <error.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080021#include <fcntl.h>
Elliott Hughes442d8582018-06-15 15:16:20 -070022#include <getopt.h>
Elliott Hughesdaf63992021-11-16 18:45:06 -080023#include <linux/f2fs.h>
Daeho Jeong2c1bee52023-08-22 13:47:39 -070024#include <linux/fs.h>
Christopher Ferris4ab94a12023-08-18 15:09:19 -070025#include <malloc.h>
Aristidis Papaioannouf7cc6622014-10-16 22:19:55 -070026#include <math.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070027#include <sched.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070028#include <stdarg.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080029#include <stdio.h>
30#include <stdlib.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080031#include <string.h>
Traian Schiau9f978602015-04-10 15:51:39 +030032#include <sys/cdefs.h>
Jaegeuk Kim64352f22019-07-04 18:09:38 -070033#include <sys/ioctl.h>
Riley Andrews53fe1b02015-06-08 23:36:34 -070034#include <sys/resource.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080035#include <sys/stat.h>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070036#include <sys/types.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070037#include <time.h>
38#include <unistd.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080039
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070040#include <memory>
Elliott Hughesaccc1012019-08-08 08:53:59 -070041#include <regex>
Tom Cherry3ade1d22020-04-13 10:07:53 -070042#include <set>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070043#include <string>
Wei Wang8b584172018-09-05 11:05:57 -070044#include <utility>
Mark Salyzyna511fef2017-02-10 13:09:07 -080045#include <vector>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070046
Elliott Hughes0a7adf02015-12-04 22:00:26 -080047#include <android-base/file.h>
Tom Cherryb1cf4282019-10-24 17:35:26 -070048#include <android-base/macros.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070049#include <android-base/parseint.h>
bohu25889532017-02-21 14:31:19 -080050#include <android-base/properties.h>
Mark Salyzyn2a1233e2016-08-03 14:20:41 -070051#include <android-base/stringprintf.h>
Elliott Hughes0a7adf02015-12-04 22:00:26 -080052#include <android-base/strings.h>
Tom Cherryb1cf4282019-10-24 17:35:26 -070053#include <android-base/unique_fd.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070054#include <android/log.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070055#include <log/event_tag_map.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070056#include <log/log_id.h>
Tom Cherry1e2ebe32020-04-17 09:38:55 -070057#include <log/log_read.h>
Colin Crosse355ded2013-07-23 16:59:20 -070058#include <log/logprint.h>
Mark Salyzyn8b8bfd22016-09-30 13:30:33 -070059#include <private/android_logger.h>
Suren Baghdasaryan3e671a52019-01-25 05:32:52 +000060#include <processgroup/sched_policy.h>
Elliott Hughes411f8632016-02-17 11:58:01 -080061#include <system/thread_defs.h>
Fabien Sanglardb0484d92023-06-12 20:04:16 +000062#include "logcat.pb.h"
Fabien Sanglard5beb0782023-06-14 01:29:23 +000063#include "process_names.h"
Fabien Sanglardb0484d92023-06-12 20:04:16 +000064
65using com::android::logcat::proto::LogcatEntryProto;
66using com::android::logcat::proto::LogcatPriorityProto;
The Android Open Source Project190995d2009-03-03 19:32:55 -080067
The Android Open Source Project190995d2009-03-03 19:32:55 -080068#define DEFAULT_MAX_ROTATED_LOGS 4
69
Tom Cherryfb1373a2019-10-29 07:05:24 -070070using android::base::Join;
71using android::base::ParseByteCount;
72using android::base::ParseUint;
73using android::base::Split;
Tom Cherryb1cf4282019-10-24 17:35:26 -070074using android::base::StringPrintf;
Jiyong Park7ceed102021-11-22 14:21:30 +090075using android::base::WaitForProperty;
Tom Cherry5837d332020-08-05 14:01:11 -070076using android::base::WriteFully;
Tom Cherryb1cf4282019-10-24 17:35:26 -070077
Fabien Sanglardb0484d92023-06-12 20:04:16 +000078namespace {
79enum OutputType {
80 TEXT, // Human-readable formatted
81 BINARY, // Raw struct log_msg as obtained from logd
82 PROTO // Protobuffer format. See logcat.proto for details. Each message is prefixed with
83 // 8 bytes (little endian) size of the message.
84};
85} // namespace
86
Tom Cherryb1cf4282019-10-24 17:35:26 -070087class Logcat {
88 public:
Tom Cherryb1cf4282019-10-24 17:35:26 -070089 int Run(int argc, char** argv);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -080090
Tom Cherryb1cf4282019-10-24 17:35:26 -070091 private:
Daeho Jeong43c6d762023-09-12 09:56:21 -070092 FILE* OpenLogFile(const char* path);
Tom Cherryb1cf4282019-10-24 17:35:26 -070093 void RotateLogs();
Tom Cherryfb1373a2019-10-29 07:05:24 -070094 void ProcessBuffer(struct log_msg* buf);
Fabien Sanglardb0484d92023-06-12 20:04:16 +000095 LogcatPriorityProto GetProtoPriority(const AndroidLogEntry& entry);
96 uint64_t PrintToProto(const AndroidLogEntry& entry);
Tom Cherryfb1373a2019-10-29 07:05:24 -070097 void PrintDividers(log_id_t log_id, bool print_dividers);
Tom Cherryb1cf4282019-10-24 17:35:26 -070098 void SetupOutputAndSchedulingPolicy(bool blocking);
99 int SetLogFormat(const char* format_string);
Elliott Hughesdaf63992021-11-16 18:45:06 -0800100 void WriteFully(const void* p, size_t n) {
101 if (fwrite(p, 1, n, output_file_) != n) {
102 error(EXIT_FAILURE, errno, "Write to output file failed");
103 }
104 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700105
Daeho Jeong2c1bee52023-08-22 13:47:39 -0700106 const bool kCompressLogcat = android::base::GetBoolProperty("ro.logcat.compress", false);
107
Tom Cherryfb1373a2019-10-29 07:05:24 -0700108 // Used for all options
Tom Cherryb1cf4282019-10-24 17:35:26 -0700109 std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
110 android_log_format_new(), &android_log_format_free};
Elliott Hughesdaf63992021-11-16 18:45:06 -0800111 // This isn't a unique_ptr because it's usually stdout;
112 // stdio's atexit handler ensures we flush on exit.
113 FILE* output_file_ = stdout;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700114
115 // For logging to a file and log rotation
Tom Cherryb1cf4282019-10-24 17:35:26 -0700116 const char* output_file_name_ = nullptr;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700117 size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
118 size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
Elliott Hughesdaf63992021-11-16 18:45:06 -0800119 uint64_t out_byte_count_ = 0;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700120
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000121 enum OutputType output_type_ = TEXT;
122
Tom Cherryfb1373a2019-10-29 07:05:24 -0700123 // For binary log buffers
Tom Cherryb1cf4282019-10-24 17:35:26 -0700124 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
125 nullptr, &android_closeEventTagMap};
Tom Cherryb1cf4282019-10-24 17:35:26 -0700126 bool has_opened_event_tag_map_ = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700127
128 // For the related --regex, --max-count, --print
129 std::unique_ptr<std::regex> regex_;
130 size_t max_count_ = 0; // 0 means "infinite"
131 size_t print_count_ = 0;
Elliott Hughesd45a5f82021-05-10 16:23:58 -0700132 bool print_it_anyway_ = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700133
134 // For PrintDividers()
Tom Cherry89b610c2020-12-14 15:35:05 -0800135 bool print_dividers_ = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700136 log_id_t last_printed_id_ = LOG_ID_MAX;
137 bool printed_start_[LOG_ID_MAX] = {};
138
139 bool debug_ = false;
Fabien Sanglard5beb0782023-06-14 01:29:23 +0000140
141 ProcessNames process_names_;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800142};
143
Daeho Jeong2c1bee52023-08-22 13:47:39 -0700144static void startCompMode(int fd) {
145 // Ignore errors.
146 long flag = FS_COMPR_FL;
147 ioctl(fd, FS_IOC_SETFLAGS, &flag);
148}
149
150static void releaseCompBlocks(const char* pathname) {
151 int fd = open(pathname, O_RDONLY);
152 if (fd != -1) {
153 // Ignore errors.
154 unsigned long long blkcnt;
155 ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
156 close(fd);
157 }
158}
159
Daeho Jeong43c6d762023-09-12 09:56:21 -0700160FILE* Logcat::OpenLogFile(const char* path) {
Elliott Hughesdaf63992021-11-16 18:45:06 -0800161 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
162 if (fd == -1) {
163 error(EXIT_FAILURE, errno, "couldn't open output file '%s'", path);
164 }
Daeho Jeong43c6d762023-09-12 09:56:21 -0700165 if (kCompressLogcat) {
Daeho Jeong2c1bee52023-08-22 13:47:39 -0700166 startCompMode(fd);
167 }
Elliott Hughesdaf63992021-11-16 18:45:06 -0800168 return fdopen(fd, "w");
Jaegeuk Kimc51a4532020-04-23 08:28:35 -0700169}
170
Tom Cherryb1cf4282019-10-24 17:35:26 -0700171void Logcat::RotateLogs() {
The Android Open Source Project190995d2009-03-03 19:32:55 -0800172 // Can't rotate logs if we're not outputting to a file
Tom Cherryb1cf4282019-10-24 17:35:26 -0700173 if (!output_file_name_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800174
Elliott Hughesdaf63992021-11-16 18:45:06 -0800175 fclose(output_file_);
176 output_file_ = nullptr;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800177
Daeho Jeong2c1bee52023-08-22 13:47:39 -0700178 if (kCompressLogcat) {
179 releaseCompBlocks(output_file_name_);
180 }
181
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800182 // Compute the maximum number of digits needed to count up to
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800183 // maxRotatedLogs in decimal. eg:
184 // maxRotatedLogs == 30
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800185 // -> log10(30) == 1.477
186 // -> maxRotationCountDigits == 2
Tom Cherryb1cf4282019-10-24 17:35:26 -0700187 int max_rotation_count_digits =
188 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
Aristidis Papaioannouf7cc6622014-10-16 22:19:55 -0700189
Tom Cherryb1cf4282019-10-24 17:35:26 -0700190 for (int i = max_rotated_logs_; i > 0; i--) {
191 std::string file1 =
192 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800193
Mark Salyzyn2a1233e2016-08-03 14:20:41 -0700194 std::string file0;
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800195 if (!(i - 1)) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700196 file0 = output_file_name_;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800197 } else {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700198 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800199 }
200
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800201 if (!file0.length() || !file1.length()) {
Traian Schiau9f978602015-04-10 15:51:39 +0300202 perror("while rotating log files");
203 break;
204 }
205
Elliott Hughesdaf63992021-11-16 18:45:06 -0800206 if (rename(file0.c_str(), file1.c_str()) == -1 && errno != ENOENT) {
207 error(0, errno, "rename('%s', '%s') failed while rotating log files", file0.c_str(),
208 file1.c_str());
The Android Open Source Project190995d2009-03-03 19:32:55 -0800209 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800210 }
211
Daeho Jeong43c6d762023-09-12 09:56:21 -0700212 output_file_ = OpenLogFile(output_file_name_);
Tom Cherryb1cf4282019-10-24 17:35:26 -0700213 out_byte_count_ = 0;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800214}
215
Tom Cherryfb1373a2019-10-29 07:05:24 -0700216void Logcat::ProcessBuffer(struct log_msg* buf) {
The Android Open Source Project190995d2009-03-03 19:32:55 -0800217 AndroidLogEntry entry;
Elliott Hughesdaf63992021-11-16 18:45:06 -0800218 char binaryMsgBuf[1024] __attribute__((__uninitialized__));
The Android Open Source Project190995d2009-03-03 19:32:55 -0800219
Tom Cherryfb1373a2019-10-29 07:05:24 -0700220 bool is_binary =
221 buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
Elliott Hughesdaf63992021-11-16 18:45:06 -0800222 int err;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700223 if (is_binary) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700224 if (!event_tag_map_ && !has_opened_event_tag_map_) {
225 event_tag_map_.reset(android_openEventTagMap(nullptr));
226 has_opened_event_tag_map_ = true;
Mark Salyzyn784d64f2015-02-26 14:33:35 -0800227 }
Elliott Hughesdaf63992021-11-16 18:45:06 -0800228 // This causes entry to point to binaryMsgBuf!
Tom Cherryb1cf4282019-10-24 17:35:26 -0700229 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
Tom Cherry47856dd2019-10-15 16:53:11 -0700230 binaryMsgBuf, sizeof(binaryMsgBuf));
Elliott Hughesdaf63992021-11-16 18:45:06 -0800231
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800232 // printf(">>> pri=%d len=%d msg='%s'\n",
The Android Open Source Project190995d2009-03-03 19:32:55 -0800233 // entry.priority, entry.messageLen, entry.message);
234 } else {
Tom Cherry47856dd2019-10-15 16:53:11 -0700235 err = android_log_processLogBuffer(&buf->entry, &entry);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800236 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700237 if (err < 0 && !debug_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800238
Tom Cherryb1cf4282019-10-24 17:35:26 -0700239 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
240 entry.priority)) {
241 bool match = !regex_ ||
242 std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
Joe Onorato400da4a2010-03-01 09:11:54 -0800243
Tom Cherryb1cf4282019-10-24 17:35:26 -0700244 print_count_ += match;
Elliott Hughesd45a5f82021-05-10 16:23:58 -0700245 if (match || print_it_anyway_) {
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000246 switch (output_type_) {
247 case TEXT: {
248 PrintDividers(buf->id(), print_dividers_);
249 out_byte_count_ +=
250 android_log_printLogLine(logformat_.get(), output_file_, &entry);
251 break;
252 }
253 case PROTO: {
254 out_byte_count_ += PrintToProto(entry);
255 break;
256 }
257 case BINARY: {
258 error(EXIT_FAILURE, errno, "Binary output reached ProcessBuffer");
259 }
260 }
Joe Onorato400da4a2010-03-01 09:11:54 -0800261 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800262 }
263
Tom Cherryb1cf4282019-10-24 17:35:26 -0700264 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
265 RotateLogs();
The Android Open Source Project190995d2009-03-03 19:32:55 -0800266 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800267}
268
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000269LogcatPriorityProto Logcat::GetProtoPriority(const AndroidLogEntry& entry) {
270 switch (entry.priority) {
271 case ANDROID_LOG_UNKNOWN:
272 return com::android::logcat::proto::UNKNOWN;
273 case ANDROID_LOG_DEFAULT:
274 return com::android::logcat::proto::DEFAULT;
275 case ANDROID_LOG_VERBOSE:
276 return com::android::logcat::proto::VERBOSE;
277 case ANDROID_LOG_DEBUG:
278 return com::android::logcat::proto::DEBUG;
279 case ANDROID_LOG_INFO:
280 return com::android::logcat::proto::INFO;
281 case ANDROID_LOG_WARN:
282 return com::android::logcat::proto::WARN;
283 case ANDROID_LOG_ERROR:
284 return com::android::logcat::proto::ERROR;
285 case ANDROID_LOG_FATAL:
286 return com::android::logcat::proto::FATAL;
287 case ANDROID_LOG_SILENT:
288 return com::android::logcat::proto::SILENT;
289 }
290 return com::android::logcat::proto::UNKNOWN;
291}
292uint64_t Logcat::PrintToProto(const AndroidLogEntry& entry) {
293 // Convert AndroidLogEntry to LogcatEntryProto
294 LogcatEntryProto proto;
295 proto.set_time_sec(entry.tv_sec);
296 proto.set_time_nsec(entry.tv_nsec);
297 proto.set_priority(GetProtoPriority(entry));
298 proto.set_uid(entry.uid);
299 proto.set_pid(entry.pid);
300 proto.set_tid(entry.tid);
301 proto.set_tag(entry.tag, entry.tagLen);
302 proto.set_message(entry.message, entry.messageLen);
Fabien Sanglard5beb0782023-06-14 01:29:23 +0000303 const std::string name = process_names_.Get(entry.pid);
304 if (!name.empty()) {
305 proto.set_process_name(name);
306 }
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000307
308 // Serialize
309 std::string data;
310 proto.SerializeToString(&data);
311
312 uint64_t size = data.length();
313 WriteFully(&size, sizeof(size));
314
315 // Write proto
316 WriteFully(data.data(), data.length());
317
318 // Return how many bytes we wrote so log file rotation can happen
319 return sizeof(size) + sizeof(data.length());
320}
321
Tom Cherryfb1373a2019-10-29 07:05:24 -0700322void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
Tom Cherry89b610c2020-12-14 15:35:05 -0800323 if (log_id == last_printed_id_) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700324 return;
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800325 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700326 if (!printed_start_[log_id] || print_dividers) {
Elliott Hughesdaf63992021-11-16 18:45:06 -0800327 if (fprintf(output_file_, "--------- %s %s\n",
Tom Cherryfb1373a2019-10-29 07:05:24 -0700328 printed_start_[log_id] ? "switch to" : "beginning of",
329 android_log_id_to_name(log_id)) < 0) {
Tom Cherry96840882019-12-06 10:25:37 -0800330 error(EXIT_FAILURE, errno, "Output error");
Tom Cherryfb1373a2019-10-29 07:05:24 -0700331 }
332 }
333 last_printed_id_ = log_id;
334 printed_start_[log_id] = true;
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800335}
336
Tom Cherryb1cf4282019-10-24 17:35:26 -0700337void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
338 if (!output_file_name_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800339
Mark Salyzyn60231da2016-08-04 07:53:52 -0700340 if (blocking) {
341 // Lower priority and set to batch scheduling if we are saving
342 // the logs into files and taking continuous content.
Tom Cherryb1cf4282019-10-24 17:35:26 -0700343 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
344 fprintf(stderr, "failed to set background scheduling policy\n");
Mark Salyzyn38fc72c2015-06-02 07:57:16 -0700345 }
346
Tom Cherryb1cf4282019-10-24 17:35:26 -0700347 struct sched_param param = {};
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800348 if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
Mark Salyzyn38fc72c2015-06-02 07:57:16 -0700349 fprintf(stderr, "failed to set to batch scheduler\n");
350 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800351
Tom Cherryb1cf4282019-10-24 17:35:26 -0700352 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
353 fprintf(stderr, "failed set to priority\n");
Riley Andrews53fe1b02015-06-08 23:36:34 -0700354 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800355 }
Mark Salyzyn60231da2016-08-04 07:53:52 -0700356
Daeho Jeong43c6d762023-09-12 09:56:21 -0700357 output_file_ = OpenLogFile(output_file_name_);
Mark Salyzyn60231da2016-08-04 07:53:52 -0700358
Elliott Hughesdaf63992021-11-16 18:45:06 -0800359 struct stat sb;
360 if (fstat(fileno(output_file_), &sb) == -1) {
361 error(EXIT_FAILURE, errno, "Couldn't stat output file");
Mark Salyzyn60231da2016-08-04 07:53:52 -0700362 }
Elliott Hughesdaf63992021-11-16 18:45:06 -0800363 out_byte_count_ = sb.st_size;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800364}
365
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800366// clang-format off
Tom Cherryb1cf4282019-10-24 17:35:26 -0700367static void show_help() {
Elliott Hughes370261f2023-04-04 17:29:15 +0000368 printf(R"logcat(
369 Usage: logcat [OPTION]... [FILTERSPEC]...
The Android Open Source Project190995d2009-03-03 19:32:55 -0800370
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000371 General options:
Tom Cherrya59bde42019-11-21 10:31:06 -0800372
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000373 -b BUFFER, --buffer=BUFFER
374 Request alternate ring buffer(s). Options are:
375 main system radio events crash default all
376 Additionally, 'kernel' for userdebug and eng builds, and 'security' for
377 Device Owner installations.
378 Multiple -b parameters or comma separated list of buffers are
379 allowed. Buffers are interleaved.
380 Default is "main,system,crash,kernel".
381 -c, --clear
382 Clear (flush) the entire log and exit. With -f, clear the specified file
383 and its related rotated log files instead. With -L, clear pstore instead.
384 -d Dump the log and then exit (don't block).
385 -L, --last Dump logs from prior to last reboot from pstore.
386 --pid=PID Only print logs from the given pid.
387 --wrap
388 Sleep for 2 hours or until buffer about to wrap (whichever comes first).
389 Improves efficiency of polling by providing an about-to-wrap wakeup.
390
391 Formatting:
392
393 -v, --format=FORMAT Sets log print format. See FORMAT below.
Tom Cherrya59bde42019-11-21 10:31:06 -0800394 -D, --dividers Print dividers between each log buffer.
395 -B, --binary Output the log in binary.
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000396 --proto Output the log in protobuffer.
Tom Cherrya59bde42019-11-21 10:31:06 -0800397
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000398 Output files:
Tom Cherrya59bde42019-11-21 10:31:06 -0800399
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000400 -f, --file=FILE Log to FILE instead of stdout.
401 -r, --rotate-kbytes=N Rotate log every N KiB. Requires -f.
402 -n, --rotate-count=N Sets max number of rotated logs, default 4.
403 --id=<id>
404 Clears the associated files if the signature <id> for logging to file
405 changes.
Tom Cherrya59bde42019-11-21 10:31:06 -0800406
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000407 Logd control:
The Android Open Source Project190995d2009-03-03 19:32:55 -0800408
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000409 These options send a control message to the logd daemon on device, print its
410 return message if applicable, then exit. They are incompatible with -L
411 because these attributes do not apply to pstore.
The Android Open Source Project190995d2009-03-03 19:32:55 -0800412
Elliott Hughesc0cafdb2023-02-28 18:14:40 +0000413 -g, --buffer-size
414 Get size of the ring buffers within logd.
415 -G, --buffer-size=SIZE
416 Set size of a ring buffer in logd. May suffix with K or M.
417 This can individually control each buffer's size with -b.
418 -p, --prune
419 Get prune rules. Each rule is specified as UID, UID/PID or /PID. A
420 '~' prefix indicates that elements matching the rule should be pruned
421 with higher priority otherwise they're pruned with lower priority. All
422 other pruning activity is oldest first. Special case ~! represents an
423 automatic pruning for the noisiest UID as determined by the current
424 statistics. Special case ~1000/! represents pruning of the worst PID
425 within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
426 -P, --prune='LIST ...'
427 Set prune rules, using same format as listed above. Must be quoted.
428 -S, --statistics
429 Output statistics. With --pid provides pid-specific stats.
430
431 Filtering:
432
433 -s Set default filter to silent (like filterspec '*:S').
434 -e, --regex=EXPR Only print lines matching ECMAScript regex.
435 -m, --max-count=N Exit after printing <count> lines.
436 --print With --regex and --max-count, prints all messages
437 even if they do not match the regex, but exits after
438 printing max-count matching lines.
439 -t N Print most recent <count> lines (implies -d).
440 -T N Print most recent <count> lines (does not imply -d).
441 -t TIME Print lines since specified time (implies -d).
442 -T TIME Print lines since specified time (not imply -d).
443 Time format is 'MM-DD hh:mm:ss.mmm...',
444 'YYYY-MM-DD hh:mm:ss.mmm...', or 'sssss.mmm...'.
445 --uid=UIDS
446 Only display log messages from UIDs in the comma-separated list UIDS.
447 UIDs must be numeric because no name lookup is performed.
448 Note that only root/log/system users can view logs from other users.
449
450 FILTERSPEC:
451
452 Filter specifications are a series of
453
454 <tag>[:priority]
455
456 where <tag> is a log component tag (or * for all) and priority is:
457
458 V Verbose (default for <tag>)
459 D Debug (default for '*')
460 I Info
461 W Warn
462 E Error
463 F Fatal
464 S Silent (suppress all output)
465
466 '*' by itself means '*:D' and <tag> by itself means <tag>:V.
467 If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
468 '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.
469
470 If not specified on the command line, FILTERSPEC is $ANDROID_LOG_TAGS.
471
472 FORMAT:
473
474 Formats are a comma-separated sequence of verbs and adverbs.
475
476 Single format verbs:
477
478 brief Show priority, tag, and PID of the process issuing the message.
479 long Show all metadata fields and separate messages with blank lines.
480 process Show PID only.
481 raw Show the raw log message with no other metadata fields.
482 tag Show the priority and tag only.
483 thread Show priority, PID, and TID of the thread issuing the message.
484 threadtime Show the date, invocation time, priority, tag, PID, and TID of
485 the thread issuing the message. (This is the default.)
486 time Show the date, invocation time, priority, tag, and PID of the
487 process issuing the message.
488
489 Adverb modifiers can be used in combination:
490
491 color Show each priority with a different color.
492 descriptive Show event descriptions from event-log-tags database.
493 epoch Show time as seconds since 1970-01-01 (Unix epoch).
494 monotonic Show time as CPU seconds since boot.
495 printable Ensure that any binary logging content is escaped.
496 uid Show UID or Android ID of logged process (if permitted).
497 usec Show time with microsecond precision.
498 UTC Show time as UTC.
499 year Add the year to the displayed time.
500 zone Add the local timezone to the displayed time.
501 \"<ZONE>\" Print using this named timezone (experimental).
502
503 If not specified with -v on command line, FORMAT is $ANDROID_PRINTF_LOG or
504 defaults to "threadtime".
505)logcat");
Mark Salyzyn604679a2016-10-18 11:30:11 -0700506}
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800507// clang-format on
Mark Salyzyn604679a2016-10-18 11:30:11 -0700508
Tom Cherryb1cf4282019-10-24 17:35:26 -0700509int Logcat::SetLogFormat(const char* format_string) {
510 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800511
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800512 // invalid string?
513 if (format == FORMAT_OFF) return -1;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800514
Tom Cherryb1cf4282019-10-24 17:35:26 -0700515 return android_log_setPrintFormat(logformat_.get(), format);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800516}
517
Wei Wang8b584172018-09-05 11:05:57 -0700518static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
519 static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
520 size_t i;
Mark Salyzyn4e756fb2014-05-06 07:34:59 -0700521 for (i = 0;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800522 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
523 value /= 1024, ++i)
524 ;
Wei Wang8b584172018-09-05 11:05:57 -0700525 return std::make_pair(value, multipliers[i]);
Mark Salyzyn4e756fb2014-05-06 07:34:59 -0700526}
527
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800528static char* parseTime(log_time& t, const char* cp) {
529 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800530 if (ep) return ep;
Mark Salyzyn4d0473f2015-08-31 15:53:41 -0700531 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800532 if (ep) return ep;
Mark Salyzyn4d0473f2015-08-31 15:53:41 -0700533 return t.strptime(cp, "%s.%q");
Mark Salyzyneb0456d2015-08-31 08:01:33 -0700534}
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700535
Mark Salyzyn05b88232016-08-04 07:43:46 -0700536// Find last logged line in <outputFileName>, or <outputFileName>.1
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800537static log_time lastLogTime(const char* outputFileName) {
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700538 log_time retval(log_time::EPOCH);
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800539 if (!outputFileName) return retval;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700540
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700541 std::string directory;
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800542 const char* file = strrchr(outputFileName, '/');
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700543 if (!file) {
544 directory = ".";
545 file = outputFileName;
546 } else {
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800547 directory = std::string(outputFileName, file - outputFileName);
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700548 ++file;
549 }
Mark Salyzyn17475732016-04-01 07:52:20 -0700550
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800551 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
552 closedir);
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800553 if (!dir.get()) return retval;
Mark Salyzyn17475732016-04-01 07:52:20 -0700554
Tom Cherrya5ff7ae2020-04-08 14:36:05 -0700555 log_time now(CLOCK_REALTIME);
Mark Salyzyn17475732016-04-01 07:52:20 -0700556
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700557 size_t len = strlen(file);
558 log_time modulo(0, NS_PER_SEC);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800559 struct dirent* dp;
Mark Salyzyn17475732016-04-01 07:52:20 -0700560
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800561 while (!!(dp = readdir(dir.get()))) {
562 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800563 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800564 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700565 continue;
566 }
567
568 std::string file_name = directory;
569 file_name += "/";
570 file_name += dp->d_name;
571 std::string file;
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800572 if (!android::base::ReadFileToString(file_name, &file)) continue;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700573
574 bool found = false;
575 for (const auto& line : android::base::Split(file, "\n")) {
576 log_time t(log_time::EPOCH);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800577 char* ep = parseTime(t, line.c_str());
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800578 if (!ep || (*ep != ' ')) continue;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700579 // determine the time precision of the logs (eg: msec or usec)
580 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
581 if (t.tv_nsec % (mod * 10)) {
582 modulo.tv_nsec = mod;
583 break;
584 }
585 }
586 // We filter any times later than current as we may not have the
587 // year stored with each log entry. Also, since it is possible for
588 // entries to be recorded out of order (very rare) we select the
589 // maximum we find just in case.
590 if ((t < now) && (t > retval)) {
591 retval = t;
592 found = true;
593 }
594 }
595 // We count on the basename file to be the definitive end, so stop here.
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800596 if (!dp->d_name[len] && found) break;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700597 }
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800598 if (retval == log_time::EPOCH) return retval;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700599 // tail_time prints matching or higher, round up by the modulo to prevent
600 // a replay of the last entry we have just checked.
601 retval += modulo;
602 return retval;
603}
604
Tom Cherryfb1373a2019-10-29 07:05:24 -0700605void ReportErrorName(const std::string& name, bool allow_security,
606 std::vector<std::string>* errors) {
607 if (allow_security || name != "security") {
608 errors->emplace_back(name);
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800609 }
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800610}
Traian Schiau9f978602015-04-10 15:51:39 +0300611
Tom Cherryb1cf4282019-10-24 17:35:26 -0700612int Logcat::Run(int argc, char** argv) {
Mark Salyzynd5920022017-02-28 09:20:31 -0800613 bool hasSetLogFormat = false;
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800614 bool clearLog = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700615 bool security_buffer_selected =
616 false; // Do not report errors on the security buffer unless it is explicitly named.
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800617 bool getLogSize = false;
618 bool getPruneList = false;
619 bool printStatistics = false;
Mark Salyzync89839a2014-02-11 12:29:31 -0800620 unsigned long setLogSize = 0;
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800621 const char* setPruneList = nullptr;
622 const char* setId = nullptr;
Tom Cherry3d1687e2020-03-23 13:40:10 -0700623 int mode = 0;
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800624 std::string forceFilters;
Traian Schiau9f978602015-04-10 15:51:39 +0300625 size_t tail_lines = 0;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800626 log_time tail_time(log_time::EPOCH);
Kristian Monsen694cdf62015-06-05 14:10:12 -0700627 size_t pid = 0;
Casey Dahlined028f92016-03-17 14:04:52 -0700628 bool got_t = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700629 unsigned id_mask = 0;
Tom Cherry3ade1d22020-04-13 10:07:53 -0700630 std::set<uid_t> uids;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800631
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800632 if (argc == 2 && !strcmp(argv[1], "--help")) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700633 show_help();
634 return EXIT_SUCCESS;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800635 }
636
Mark Salyzynd5920022017-02-28 09:20:31 -0800637 // meant to catch comma-delimited values, but cast a wider
638 // net for stability dealing with possible mistaken inputs.
639 static const char delimiters[] = ",:; \t\n\r\f";
640
Elliott Hughes442d8582018-06-15 15:16:20 -0700641 optind = 0;
642 while (true) {
Kristian Monsen694cdf62015-06-05 14:10:12 -0700643 int option_index = 0;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700644 // list of long-argument only strings for later comparison
Kristian Monsen694cdf62015-06-05 14:10:12 -0700645 static const char pid_str[] = "pid";
Mark Salyzyn14369232016-11-16 15:28:31 -0800646 static const char debug_str[] = "debug";
Mark Salyzyn175773d2016-08-03 14:20:41 -0700647 static const char id_str[] = "id";
Mark Salyzyn712caab2015-11-30 13:48:56 -0800648 static const char wrap_str[] = "wrap";
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700649 static const char print_str[] = "print";
Tom Cherry3ade1d22020-04-13 10:07:53 -0700650 static const char uid_str[] = "uid";
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000651 static const char proto_str[] = "proto";
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800652 // clang-format off
Kristian Monsen694cdf62015-06-05 14:10:12 -0700653 static const struct option long_options[] = {
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800654 { "binary", no_argument, nullptr, 'B' },
655 { "buffer", required_argument, nullptr, 'b' },
656 { "buffer-size", optional_argument, nullptr, 'g' },
657 { "clear", no_argument, nullptr, 'c' },
658 { debug_str, no_argument, nullptr, 0 },
659 { "dividers", no_argument, nullptr, 'D' },
660 { "file", required_argument, nullptr, 'f' },
661 { "format", required_argument, nullptr, 'v' },
Mark Salyzyn17475732016-04-01 07:52:20 -0700662 // hidden and undocumented reserved alias for --regex
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800663 { "grep", required_argument, nullptr, 'e' },
Mark Salyzyn12d83062016-03-30 09:15:09 -0700664 // hidden and undocumented reserved alias for --max-count
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800665 { "head", required_argument, nullptr, 'm' },
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700666 { "help", no_argument, nullptr, 'h' },
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800667 { id_str, required_argument, nullptr, 0 },
668 { "last", no_argument, nullptr, 'L' },
669 { "max-count", required_argument, nullptr, 'm' },
670 { pid_str, required_argument, nullptr, 0 },
671 { print_str, no_argument, nullptr, 0 },
672 { "prune", optional_argument, nullptr, 'p' },
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000673 { proto_str, no_argument, nullptr, 0 },
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800674 { "regex", required_argument, nullptr, 'e' },
675 { "rotate-count", required_argument, nullptr, 'n' },
676 { "rotate-kbytes", required_argument, nullptr, 'r' },
677 { "statistics", no_argument, nullptr, 'S' },
Mark Salyzyn12d83062016-03-30 09:15:09 -0700678 // hidden and undocumented reserved alias for -t
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800679 { "tail", required_argument, nullptr, 't' },
Tom Cherry3ade1d22020-04-13 10:07:53 -0700680 { uid_str, required_argument, nullptr, 0 },
Mark Salyzyn712caab2015-11-30 13:48:56 -0800681 // support, but ignore and do not document, the optional argument
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800682 { wrap_str, optional_argument, nullptr, 0 },
683 { nullptr, 0, nullptr, 0 }
Kristian Monsen694cdf62015-06-05 14:10:12 -0700684 };
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800685 // clang-format on
Kristian Monsen694cdf62015-06-05 14:10:12 -0700686
Elliott Hughes442d8582018-06-15 15:16:20 -0700687 int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
688 &option_index);
689 if (c == -1) break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800690
Elliott Hughes442d8582018-06-15 15:16:20 -0700691 switch (c) {
Kristian Monsen694cdf62015-06-05 14:10:12 -0700692 case 0:
Mark Salyzyn175773d2016-08-03 14:20:41 -0700693 // only long options
Kristian Monsen694cdf62015-06-05 14:10:12 -0700694 if (long_options[option_index].name == pid_str) {
Steven Moreland36f05952019-08-02 10:13:57 -0700695 if (pid != 0) {
Tom Cherry96840882019-12-06 10:25:37 -0800696 error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
Steven Moreland36f05952019-08-02 10:13:57 -0700697 }
698
Tom Cherryfb1373a2019-10-29 07:05:24 -0700699 if (!ParseUint(optarg, &pid) || pid < 1) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700700 error(EXIT_FAILURE, 0, "pid '%s' out of range.", optarg);
Kristian Monsen694cdf62015-06-05 14:10:12 -0700701 }
702 break;
703 }
Mark Salyzyn712caab2015-11-30 13:48:56 -0800704 if (long_options[option_index].name == wrap_str) {
Tom Cherry3d1687e2020-03-23 13:40:10 -0700705 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
Mark Salyzyn712caab2015-11-30 13:48:56 -0800706 // ToDo: implement API that supports setting a wrap timeout
Tom Cherrycbd31f92020-07-27 11:20:29 -0700707 size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
708 if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700709 error(EXIT_FAILURE, 0, "wrap timeout '%s' out of range.", optarg);
Mark Salyzyn712caab2015-11-30 13:48:56 -0800710 }
Tom Cherrycbd31f92020-07-27 11:20:29 -0700711 if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700712 fprintf(stderr, "WARNING: wrap timeout %zus, not default %us\n", timeout,
713 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
Mark Salyzyn712caab2015-11-30 13:48:56 -0800714 }
715 break;
716 }
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700717 if (long_options[option_index].name == print_str) {
Elliott Hughesd45a5f82021-05-10 16:23:58 -0700718 print_it_anyway_ = true;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700719 break;
720 }
Mark Salyzyn14369232016-11-16 15:28:31 -0800721 if (long_options[option_index].name == debug_str) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700722 debug_ = true;
Mark Salyzyn14369232016-11-16 15:28:31 -0800723 break;
724 }
Mark Salyzyn175773d2016-08-03 14:20:41 -0700725 if (long_options[option_index].name == id_str) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700726 setId = (optarg && optarg[0]) ? optarg : nullptr;
Mark Salyzyn175773d2016-08-03 14:20:41 -0700727 }
Tom Cherry3ade1d22020-04-13 10:07:53 -0700728 if (long_options[option_index].name == uid_str) {
729 auto uid_strings = Split(optarg, delimiters);
730 for (const auto& uid_string : uid_strings) {
731 uid_t uid;
732 if (!ParseUint(uid_string, &uid)) {
733 error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
734 }
735 uids.emplace(uid);
736 }
737 break;
738 }
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000739 if (long_options[option_index].name == proto_str) {
740 output_type_ = PROTO;
741 break;
742 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800743 break;
Kristian Monsen694cdf62015-06-05 14:10:12 -0700744
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800745 case 's':
The Android Open Source Project190995d2009-03-03 19:32:55 -0800746 // default to all silent
Tom Cherryb1cf4282019-10-24 17:35:26 -0700747 android_log_addFilterRule(logformat_.get(), "*:s");
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800748 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800749
750 case 'c':
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800751 clearLog = true;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800752 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800753
Mark Salyzyn66460fc2014-12-15 10:01:31 -0800754 case 'L':
Tom Cherry3d1687e2020-03-23 13:40:10 -0700755 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800756 break;
Mark Salyzyn66460fc2014-12-15 10:01:31 -0800757
The Android Open Source Project190995d2009-03-03 19:32:55 -0800758 case 'd':
Tom Cherry3d1687e2020-03-23 13:40:10 -0700759 mode |= ANDROID_LOG_NONBLOCK;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800760 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800761
Dan Egnorcce2b082010-03-11 20:32:17 -0800762 case 't':
Casey Dahlined028f92016-03-17 14:04:52 -0700763 got_t = true;
Tom Cherry3d1687e2020-03-23 13:40:10 -0700764 mode |= ANDROID_LOG_NONBLOCK;
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700765 FALLTHROUGH_INTENDED;
Mark Salyzyn2256e2f2013-12-09 13:47:00 -0800766 case 'T':
Elliott Hughes442d8582018-06-15 15:16:20 -0700767 if (strspn(optarg, "0123456789") != strlen(optarg)) {
768 char* cp = parseTime(tail_time, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800769 if (!cp) {
Tom Cherry96840882019-12-06 10:25:37 -0800770 error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800771 }
772 if (*cp) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700773 char ch = *cp;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800774 *cp = '\0';
Tom Cherry96840882019-12-06 10:25:37 -0800775 fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
776 cp + 1);
Elliott Hughes442d8582018-06-15 15:16:20 -0700777 *cp = ch;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800778 }
779 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700780 if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700781 fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800782 tail_lines = 1;
783 }
784 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800785 break;
Dan Egnorcce2b082010-03-11 20:32:17 -0800786
Mark Salyzyn1ff18092015-01-26 13:41:33 -0800787 case 'D':
Tom Cherry89b610c2020-12-14 15:35:05 -0800788 print_dividers_ = true;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800789 break;
Mark Salyzyn1ff18092015-01-26 13:41:33 -0800790
Casey Dahlin4cf025a2016-03-17 16:18:55 -0700791 case 'e':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700792 regex_.reset(new std::regex(optarg));
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800793 break;
Casey Dahlin4cf025a2016-03-17 16:18:55 -0700794
Casey Dahlined028f92016-03-17 14:04:52 -0700795 case 'm': {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700796 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
Tom Cherry96840882019-12-06 10:25:37 -0800797 error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
798 optarg);
Casey Dahlined028f92016-03-17 14:04:52 -0700799 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800800 } break;
Casey Dahlined028f92016-03-17 14:04:52 -0700801
The Android Open Source Project190995d2009-03-03 19:32:55 -0800802 case 'g':
Elliott Hughes442d8582018-06-15 15:16:20 -0700803 if (!optarg) {
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800804 getLogSize = true;
Mark Salyzynaef4c7e2015-11-30 12:57:56 -0800805 break;
806 }
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700807 FALLTHROUGH_INTENDED;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800808
Mark Salyzync89839a2014-02-11 12:29:31 -0800809 case 'G': {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700810 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
Tom Cherry96840882019-12-06 10:25:37 -0800811 error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
Mark Salyzync89839a2014-02-11 12:29:31 -0800812 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800813 } break;
Mark Salyzync89839a2014-02-11 12:29:31 -0800814
815 case 'p':
Elliott Hughes442d8582018-06-15 15:16:20 -0700816 if (!optarg) {
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800817 getPruneList = true;
Mark Salyzynaef4c7e2015-11-30 12:57:56 -0800818 break;
819 }
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700820 FALLTHROUGH_INTENDED;
Mark Salyzync89839a2014-02-11 12:29:31 -0800821
822 case 'P':
Elliott Hughes442d8582018-06-15 15:16:20 -0700823 setPruneList = optarg;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800824 break;
Mark Salyzync89839a2014-02-11 12:29:31 -0800825
Tom Cherryfb1373a2019-10-29 07:05:24 -0700826 case 'b':
827 for (const auto& buffer : Split(optarg, delimiters)) {
828 if (buffer == "default") {
829 id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
830 } else if (buffer == "all") {
831 id_mask = -1;
Mark Salyzyn9ca3be32016-04-11 14:03:48 -0700832 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700833 log_id_t log_id = android_name_to_log_id(buffer.c_str());
834 if (log_id >= LOG_ID_MAX) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700835 error(EXIT_FAILURE, 0, "Unknown -b buffer '%s'.", buffer.c_str());
Mark Salyzynd774bce2014-02-06 14:48:50 -0800836 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700837 if (log_id == LOG_ID_SECURITY) {
838 security_buffer_selected = true;
Mark Salyzync9690862015-12-04 10:59:45 -0800839 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700840 id_mask |= (1 << log_id);
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800841 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800842 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700843 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800844
845 case 'B':
Fabien Sanglardb0484d92023-06-12 20:04:16 +0000846 output_type_ = BINARY;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800847 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800848
849 case 'f':
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800850 if ((tail_time == log_time::EPOCH) && !tail_lines) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700851 tail_time = lastLogTime(optarg);
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700852 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800853 // redirect output to a file
Tom Cherryb1cf4282019-10-24 17:35:26 -0700854 output_file_name_ = optarg;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800855 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800856
Mark Salyzynff5f4b12016-06-07 13:03:10 -0700857 case 'r':
Tom Cherryfb1373a2019-10-29 07:05:24 -0700858 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700859 error(EXIT_FAILURE, 0, "Invalid -r '%s'.", optarg);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800860 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800861 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800862
Mark Salyzynff5f4b12016-06-07 13:03:10 -0700863 case 'n':
Tom Cherryfb1373a2019-10-29 07:05:24 -0700864 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700865 error(EXIT_FAILURE, 0, "Invalid -n '%s'.", optarg);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800866 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800867 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800868
Tom Cherryfb1373a2019-10-29 07:05:24 -0700869 case 'v':
Tom Cherryfb1373a2019-10-29 07:05:24 -0700870 for (const auto& arg : Split(optarg, delimiters)) {
871 int err = SetLogFormat(arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800872 if (err < 0) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700873 error(EXIT_FAILURE, 0, "Invalid -v '%s'.", arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800874 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800875 if (err) hasSetLogFormat = true;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800876 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700877 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800878
Mark Salyzynd774bce2014-02-06 14:48:50 -0800879 case 'S':
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800880 printStatistics = true;
Mark Salyzynd774bce2014-02-06 14:48:50 -0800881 break;
882
Traian Schiau9f978602015-04-10 15:51:39 +0300883 case ':':
Tom Cherry96840882019-12-06 10:25:37 -0800884 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
885 break;
Traian Schiau9f978602015-04-10 15:51:39 +0300886
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700887 case 'h':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700888 show_help();
Tom Cherryb1cf4282019-10-24 17:35:26 -0700889 return EXIT_SUCCESS;
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700890
Tom Cherry96840882019-12-06 10:25:37 -0800891 case '?':
Steven Morelandbc3bc622023-03-28 19:29:16 +0000892 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
Tom Cherry96840882019-12-06 10:25:37 -0800893 break;
894
The Android Open Source Project190995d2009-03-03 19:32:55 -0800895 default:
Tom Cherry96840882019-12-06 10:25:37 -0800896 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800897 }
898 }
899
Tom Cherryb1cf4282019-10-24 17:35:26 -0700900 if (max_count_ && got_t) {
Tom Cherry96840882019-12-06 10:25:37 -0800901 error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
Casey Dahlined028f92016-03-17 14:04:52 -0700902 }
Elliott Hughesd45a5f82021-05-10 16:23:58 -0700903 if (print_it_anyway_ && (!regex_ || !max_count_)) {
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700904 // One day it would be nice if --print -v color and --regex <expr>
905 // could play with each other and show regex highlighted content.
Tom Cherryb1cf4282019-10-24 17:35:26 -0700906 fprintf(stderr,
907 "WARNING: "
908 "--print ignored, to be used in combination with\n"
909 " "
910 "--regex <expr> and --max-count <N>\n");
Elliott Hughesd45a5f82021-05-10 16:23:58 -0700911 print_it_anyway_ = false;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700912 }
Casey Dahlined028f92016-03-17 14:04:52 -0700913
Tom Cherryfb1373a2019-10-29 07:05:24 -0700914 // If no buffers are specified, default to using these buffers.
915 if (id_mask == 0) {
916 id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
917 (1 << LOG_ID_KERNEL);
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800918 }
919
Tom Cherryb1cf4282019-10-24 17:35:26 -0700920 if (log_rotate_size_kb_ != 0 && !output_file_name_) {
Tom Cherry96840882019-12-06 10:25:37 -0800921 error(EXIT_FAILURE, 0, "-r requires -f as well.");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800922 }
923
Tom Cherryb1cf4282019-10-24 17:35:26 -0700924 if (setId != 0) {
925 if (!output_file_name_) {
Tom Cherry96840882019-12-06 10:25:37 -0800926 error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
Mark Salyzyn175773d2016-08-03 14:20:41 -0700927 }
928
Tom Cherryb1cf4282019-10-24 17:35:26 -0700929 std::string file_name = StringPrintf("%s.id", output_file_name_);
Mark Salyzyn175773d2016-08-03 14:20:41 -0700930 std::string file;
931 bool file_ok = android::base::ReadFileToString(file_name, &file);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800932 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
933 getuid(), getgid());
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800934 if (!file_ok || !file.compare(setId)) setId = nullptr;
Mark Salyzyn175773d2016-08-03 14:20:41 -0700935 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800936
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800937 if (!hasSetLogFormat) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700938 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800939
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800940 if (!!logFormat) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700941 for (const auto& arg : Split(logFormat, delimiters)) {
942 int err = SetLogFormat(arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800943 // environment should not cause crash of logcat
Tom Cherryb1cf4282019-10-24 17:35:26 -0700944 if (err < 0) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700945 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800946 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800947 if (err > 0) hasSetLogFormat = true;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800948 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800949 }
950 if (!hasSetLogFormat) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700951 SetLogFormat("threadtime");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800952 }
953 }
954
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800955 if (forceFilters.size()) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700956 int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
The Android Open Source Project190995d2009-03-03 19:32:55 -0800957 if (err < 0) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700958 error(EXIT_FAILURE, 0, "Invalid filter expression '%s' in logcat args.",
959 forceFilters.c_str());
The Android Open Source Project190995d2009-03-03 19:32:55 -0800960 }
Elliott Hughes442d8582018-06-15 15:16:20 -0700961 } else if (argc == optind) {
The Android Open Source Project190995d2009-03-03 19:32:55 -0800962 // Add from environment variable
Tom Cherryb1cf4282019-10-24 17:35:26 -0700963 const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800964
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800965 if (!!env_tags_orig) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700966 int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800967
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800968 if (err < 0) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -0700969 error(EXIT_FAILURE, 0, "Invalid filter expression '%s' in ANDROID_LOG_TAGS.",
970 env_tags_orig);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800971 }
972 }
973 } else {
974 // Add from commandline
Elliott Hughes442d8582018-06-15 15:16:20 -0700975 for (int i = optind ; i < argc ; i++) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700976 int err = android_log_addFilterString(logformat_.get(), argv[i]);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800977 if (err < 0) {
Tom Cherry96840882019-12-06 10:25:37 -0800978 error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800979 }
980 }
981 }
982
Tom Cherryf459c582019-11-14 08:56:39 -0800983 if (mode & ANDROID_LOG_PSTORE) {
Tom Cherryeb2258a2019-12-04 14:37:38 -0800984 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
Tom Cherry96840882019-12-06 10:25:37 -0800985 error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
Tom Cherryeb2258a2019-12-04 14:37:38 -0800986 }
Tom Cherryf459c582019-11-14 08:56:39 -0800987 if (clearLog) {
Elliott Hughesf45bd382021-09-07 18:23:48 -0700988 if (output_file_name_) {
989 error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
990 }
Tom Cherryf459c582019-11-14 08:56:39 -0800991 unlink("/sys/fs/pstore/pmsg-ramoops-0");
992 return EXIT_SUCCESS;
993 }
Tom Cherryeb2258a2019-12-04 14:37:38 -0800994 }
995
996 if (output_file_name_) {
Tom Cherryf459c582019-11-14 08:56:39 -0800997 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
Tom Cherry96840882019-12-06 10:25:37 -0800998 error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
Tom Cherryeb2258a2019-12-04 14:37:38 -0800999 }
1000
1001 if (clearLog || setId) {
1002 int max_rotation_count_digits =
1003 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
1004
1005 for (int i = max_rotated_logs_; i >= 0; --i) {
1006 std::string file;
1007
1008 if (!i) {
1009 file = output_file_name_;
1010 } else {
1011 file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
1012 }
1013
1014 int err = unlink(file.c_str());
1015
1016 if (err < 0 && errno != ENOENT) {
1017 fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
1018 strerror(errno));
1019 }
1020 }
1021 }
1022
1023 if (clearLog) {
1024 return EXIT_SUCCESS;
Tom Cherryf459c582019-11-14 08:56:39 -08001025 }
1026 }
1027
Tom Cherryfb1373a2019-10-29 07:05:24 -07001028 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
1029 nullptr, &android_logger_list_free};
Mark Salyzyn9addf592014-02-14 16:05:05 -08001030 if (tail_time != log_time::EPOCH) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001031 logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
Mark Salyzyn9addf592014-02-14 16:05:05 -08001032 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001033 logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
Mark Salyzyn9addf592014-02-14 16:05:05 -08001034 }
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001035 // We have three orthogonal actions below to clear, set log size and
1036 // get log size. All sharing the same iteration loop.
Tom Cherryfb1373a2019-10-29 07:05:24 -07001037 std::vector<std::string> open_device_failures;
1038 std::vector<std::string> clear_failures;
1039 std::vector<std::string> set_size_failures;
1040 std::vector<std::string> get_size_failures;
1041
1042 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
1043 if (!(id_mask & (1 << i))) continue;
1044 const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
1045
1046 auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
1047 if (logger == nullptr) {
1048 ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001049 continue;
The Android Open Source Project190995d2009-03-03 19:32:55 -08001050 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001051
Tom Cherryeb2258a2019-12-04 14:37:38 -08001052 if (clearLog) {
1053 if (android_logger_clear(logger)) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001054 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001055 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001056 }
1057
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001058 if (setLogSize) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001059 if (android_logger_set_log_size(logger, setLogSize)) {
1060 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001061 }
Mark Salyzync89839a2014-02-11 12:29:31 -08001062 }
1063
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001064 if (getLogSize) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001065 long size = android_logger_get_log_size(logger);
1066 long readable = android_logger_get_log_readable_size(logger);
Tom Cherry9a92d572020-08-05 11:22:44 -07001067 long consumed = android_logger_get_log_consumed_size(logger);
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001068
Tom Cherryfb1373a2019-10-29 07:05:24 -07001069 if (size < 0 || readable < 0) {
1070 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001071 } else {
Wei Wang8b584172018-09-05 11:05:57 -07001072 auto size_format = format_of_size(size);
1073 auto readable_format = format_of_size(readable);
Tom Cherry9a92d572020-08-05 11:22:44 -07001074 auto consumed_format = format_of_size(consumed);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001075 std::string str = android::base::StringPrintf(
Tom Cherry9a92d572020-08-05 11:22:44 -07001076 "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
Tom Cherryfb1373a2019-10-29 07:05:24 -07001077 " max entry is %d B, max payload is %d B\n",
Tom Cherry9a92d572020-08-05 11:22:44 -07001078 buffer_name, size_format.first, size_format.second, consumed_format.first,
1079 consumed_format.second, readable_format.first, readable_format.second,
1080 (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
Elliott Hughesdaf63992021-11-16 18:45:06 -08001081 WriteFully(str.data(), str.length());
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001082 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001083 }
The Android Open Source Project190995d2009-03-03 19:32:55 -08001084 }
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001085
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001086 // report any errors in the above loop and exit
Tom Cherryfb1373a2019-10-29 07:05:24 -07001087 if (!open_device_failures.empty()) {
Tom Cherry96840882019-12-06 10:25:37 -08001088 error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
1089 open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001090 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001091 if (!clear_failures.empty()) {
Tom Cherry96840882019-12-06 10:25:37 -08001092 error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
1093 clear_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001094 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001095 if (!set_size_failures.empty()) {
Tom Cherry96840882019-12-06 10:25:37 -08001096 error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
1097 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001098 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001099 if (!get_size_failures.empty()) {
Tom Cherry96840882019-12-06 10:25:37 -08001100 error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1101 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001102 }
The Android Open Source Project190995d2009-03-03 19:32:55 -08001103
Mark Salyzync89839a2014-02-11 12:29:31 -08001104 if (setPruneList) {
Traian Schiau9f978602015-04-10 15:51:39 +03001105 size_t len = strlen(setPruneList);
Tom Cherryc8c906e2019-12-06 11:01:51 -08001106 if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
Elliott Hughes6aabf6b2023-06-13 15:34:29 -07001107 error(EXIT_FAILURE, 0, "Failed to set the prune list to '%s'.", setPruneList);
Mark Salyzync89839a2014-02-11 12:29:31 -08001108 }
Tom Cherryb1cf4282019-10-24 17:35:26 -07001109 return EXIT_SUCCESS;
Mark Salyzync89839a2014-02-11 12:29:31 -08001110 }
1111
Mark Salyzync402bc72014-04-01 17:19:47 -07001112 if (printStatistics || getPruneList) {
Tom Cherryf30875b2019-12-06 13:33:11 -08001113 std::string buf(8192, '\0');
1114 size_t ret_length = 0;
1115 int retry = 32;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001116
Tom Cherryf30875b2019-12-06 13:33:11 -08001117 for (; retry >= 0; --retry) {
Mark Salyzync89839a2014-02-11 12:29:31 -08001118 if (getPruneList) {
Tom Cherryf30875b2019-12-06 13:33:11 -08001119 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
Mark Salyzync89839a2014-02-11 12:29:31 -08001120 } else {
Tom Cherryf30875b2019-12-06 13:33:11 -08001121 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
Mark Salyzync89839a2014-02-11 12:29:31 -08001122 }
Tom Cherryf30875b2019-12-06 13:33:11 -08001123
1124 ret_length = atol(buf.c_str());
1125 if (ret_length < 3) {
1126 error(EXIT_FAILURE, 0, "Failed to read data.");
1127 }
1128
1129 if (ret_length < buf.size()) {
Mark Salyzynd774bce2014-02-06 14:48:50 -08001130 break;
1131 }
Tom Cherryf30875b2019-12-06 13:33:11 -08001132
1133 buf.resize(ret_length + 1);
Mark Salyzynd774bce2014-02-06 14:48:50 -08001134 }
1135
Tom Cherryf30875b2019-12-06 13:33:11 -08001136 if (retry < 0) {
Tom Cherry96840882019-12-06 10:25:37 -08001137 error(EXIT_FAILURE, 0, "Failed to read data.");
Mark Salyzynd774bce2014-02-06 14:48:50 -08001138 }
1139
Tom Cherryf30875b2019-12-06 13:33:11 -08001140 buf.resize(ret_length);
1141 if (buf.back() == '\f') {
1142 buf.pop_back();
Mark Salyzynd774bce2014-02-06 14:48:50 -08001143 }
1144
Tom Cherryf30875b2019-12-06 13:33:11 -08001145 // Remove the byte count prefix
1146 const char* cp = buf.c_str();
1147 while (isdigit(*cp)) ++cp;
1148 if (*cp == '\n') ++cp;
1149
Elliott Hughesdaf63992021-11-16 18:45:06 -08001150 WriteFully(cp, strlen(cp));
Tom Cherryb1cf4282019-10-24 17:35:26 -07001151 return EXIT_SUCCESS;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001152 }
1153
Tom Cherryb1cf4282019-10-24 17:35:26 -07001154 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
The Android Open Source Project190995d2009-03-03 19:32:55 -08001155
Elliott Hughesdaf63992021-11-16 18:45:06 -08001156 bool blocking = !(mode & ANDROID_LOG_NONBLOCK);
1157 SetupOutputAndSchedulingPolicy(blocking);
The Android Open Source Project190995d2009-03-03 19:32:55 -08001158
Christopher Ferris4ab94a12023-08-18 15:09:19 -07001159 // Purge as much memory as possible before going into the log reading loop.
1160 // Do this before checking if logd is ready just in case logd isn't
1161 // ready and this call can be done without penalizing start up.
1162 mallopt(M_PURGE_ALL, 0);
1163
Jiyong Park7ceed102021-11-22 14:21:30 +09001164 if (!WaitForProperty("logd.ready", "true", std::chrono::seconds(1))) {
1165 error(EXIT_FAILURE, 0, "Failed to wait for logd.ready to become true. logd not running?");
1166 }
1167
Tom Cherryb1cf4282019-10-24 17:35:26 -07001168 while (!max_count_ || print_count_ < max_count_) {
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001169 struct log_msg log_msg;
Tom Cherryfb1373a2019-10-29 07:05:24 -07001170 int ret = android_logger_list_read(logger_list.get(), &log_msg);
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001171 if (!ret) {
Tom Cherry96840882019-12-06 10:25:37 -08001172 error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
Tom Cherrya59bde42019-11-21 10:31:06 -08001173
Tom Cherryeac7e412020-02-14 10:01:57 -08001174This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
Tom Cherrya59bde42019-11-21 10:31:06 -08001175messages as quickly as they were being produced.
1176
Tom Cherry96840882019-12-06 10:25:37 -08001177If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001178 }
1179
1180 if (ret < 0) {
Andrei Diead32eb462023-08-30 15:15:51 +00001181 if (ret == -EAGAIN || ret == -EWOULDBLOCK || ret == -ETIMEDOUT) {
1182 // For non-blocking mode, a socket with a 2s timeout is used to read logs.
1183 // Either recv returned -EAGAIN or -EWOULDBLOCK (see man recv)
1184 // or connect returned -EAGAIN or -ETIMEOUT.
1185 // In either case, the caller should call logcat again at a later time.
1186 break;
1187 }
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001188 if (ret == -EIO) {
Tom Cherry96840882019-12-06 10:25:37 -08001189 error(EXIT_FAILURE, 0, "Unexpected EOF!");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001190 }
1191 if (ret == -EINVAL) {
Tom Cherry96840882019-12-06 10:25:37 -08001192 error(EXIT_FAILURE, 0, "Unexpected length.");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001193 }
Tom Cherry96840882019-12-06 10:25:37 -08001194 error(EXIT_FAILURE, errno, "Logcat read failure");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001195 }
1196
Tom Cherryfb1373a2019-10-29 07:05:24 -07001197 if (log_msg.id() > LOG_ID_MAX) {
Tom Cherry96840882019-12-06 10:25:37 -08001198 error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1199 LOG_ID_MAX);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001200 }
1201
Tom Cherry3ade1d22020-04-13 10:07:53 -07001202 if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1203 continue;
1204 }
1205
Fabien Sanglardb0484d92023-06-12 20:04:16 +00001206 switch (output_type_) {
1207 case BINARY:
1208 WriteFully(&log_msg, log_msg.len());
1209 break;
1210 case TEXT:
1211 case PROTO:
1212 ProcessBuffer(&log_msg);
1213 break;
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001214 }
Alon Albertd3407212023-04-11 20:49:15 +00001215 if (blocking && output_file_ == stdout) fflush(stdout);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001216 }
Tom Cherryb1cf4282019-10-24 17:35:26 -07001217 return EXIT_SUCCESS;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001218}
1219
Tom Cherryd8ea11f2019-10-30 13:51:03 -07001220int main(int argc, char** argv) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001221 Logcat logcat;
1222 return logcat.Run(argc, argv);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001223}