diff options
Diffstat (limited to 'logd')
| -rw-r--r-- | logd/Android.bp | 21 | ||||
| -rw-r--r-- | logd/LogAudit.cpp | 8 | ||||
| -rw-r--r-- | logd/LogBufferTest.cpp | 10 | ||||
| -rw-r--r-- | logd/LogKlog.cpp | 14 | ||||
| -rw-r--r-- | logd/LogStatistics.cpp | 39 | ||||
| -rw-r--r-- | logd/LogStatistics.h | 4 | ||||
| -rw-r--r-- | logd/README.property | 9 | ||||
| -rw-r--r-- | logd/README.replay.md | 46 | ||||
| -rw-r--r-- | logd/RecordedLogMessage.h | 30 | ||||
| -rw-r--r-- | logd/RecordingLogBuffer.cpp | 62 | ||||
| -rw-r--r-- | logd/RecordingLogBuffer.h | 43 | ||||
| -rw-r--r-- | logd/ReplayMessages.cpp | 472 | ||||
| -rw-r--r-- | logd/SerializedFlushToState.cpp | 6 | ||||
| -rw-r--r-- | logd/SerializedLogBuffer.cpp | 2 | ||||
| -rw-r--r-- | logd/SerializedLogChunk.cpp | 16 | ||||
| -rw-r--r-- | logd/SerializedLogChunk.h | 7 | ||||
| -rw-r--r-- | logd/SerializedLogChunkTest.cpp | 7 | ||||
| -rw-r--r-- | logd/fuzz/log_buffer_log_fuzzer.cpp | 10 | ||||
| -rw-r--r-- | logd/logd_test.cpp | 128 | ||||
| -rw-r--r-- | logd/main.cpp | 38 |
20 files changed, 773 insertions, 199 deletions
diff --git a/logd/Android.bp b/logd/Android.bp index 036cb7e448..265e19e8fd 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -177,6 +177,27 @@ cc_test { }, test_suites: [ "cts", + "device-tests", "vts10", ], } + +cc_binary { + name: "replay_messages", + defaults: ["logd_defaults"], + host_supported: true, + + srcs: [ + "ReplayMessages.cpp", + ], + + static_libs: [ + "libbase", + "libcutils", + "liblog", + "liblogd", + "libselinux", + "libz", + "libzstd", + ], +} diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index 0ce9796b0a..0e17476ea6 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -32,7 +32,7 @@ #include <sstream> #include <android-base/macros.h> -#include <log/log_properties.h> +#include <android-base/properties.h> #include <private/android_filesystem_config.h> #include <private/android_logger.h> @@ -40,6 +40,8 @@ #include "LogUtils.h" #include "libaudit.h" +using android::base::GetBoolProperty; + #define KMSG_PRIORITY(PRI) \ '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \ '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>' @@ -48,8 +50,8 @@ LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats) : SocketListener(getLogSocket(), false), logbuf(buf), fdDmesg(fdDmesg), - main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)), - events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)), + main(GetBoolProperty("ro.logd.auditd.main", true)), + events(GetBoolProperty("ro.logd.auditd.events", true)), initialized(false), stats_(stats) { static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp index 47d2a2f920..191110522e 100644 --- a/logd/LogBufferTest.cpp +++ b/logd/LogBufferTest.cpp @@ -34,16 +34,6 @@ using android::base::Join; using android::base::Split; using android::base::StringPrintf; -#ifndef __ANDROID__ -unsigned long __android_logger_get_buffer_size(log_id_t) { - return 1024 * 1024; -} - -bool __android_logger_valid_buffer_size(unsigned long) { - return true; -} -#endif - char* android::uidToName(uid_t) { return nullptr; } diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index dbdf7fdd0c..d6c7d25275 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp @@ -381,8 +381,8 @@ pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) { } if ((i == 9) && (cp[i] == ' ')) { int pid = 0; - char dummy; - if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) { + char placeholder; + if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) { buf = cp + 10; // skip-it-all return pid; } @@ -392,8 +392,8 @@ pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) { // Mediatek kernels with modified printk if (*cp == '[') { int pid = 0; - char dummy; - if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) { + char placeholder; + if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) { return pid; } break; // Only the first one @@ -703,7 +703,7 @@ int LogKlog::log(const char* buf, ssize_t len) { p = " "; b = 1; } - // paranoid sanity check, can not happen ... + // This shouldn't happen, but clamp the size if it does. if (b > LOGGER_ENTRY_MAX_PAYLOAD) { b = LOGGER_ENTRY_MAX_PAYLOAD; } @@ -712,7 +712,7 @@ int LogKlog::log(const char* buf, ssize_t len) { } // calculate buffer copy requirements ssize_t n = 1 + taglen + 1 + b + 1; - // paranoid sanity check, first two just can not happen ... + // Extra checks for likely impossible cases. if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) { return -EINVAL; } @@ -722,7 +722,7 @@ int LogKlog::log(const char* buf, ssize_t len) { // If we malloc'd this buffer, we could get away without n's USHRT_MAX // test above, but we would then required a max(n, USHRT_MAX) as // truncating length argument to logbuf->log() below. Gain is protection - // of stack sanity and speedup, loss is truncated long-line content. + // against stack corruption and speedup, loss is truncated long-line content. char newstr[n]; char* np = newstr; diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 1705d48088..87069b3ed2 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -26,8 +26,10 @@ #include <unistd.h> #include <list> +#include <vector> #include <android-base/logging.h> +#include <android-base/strings.h> #include <private/android_logger.h> #include "LogBufferElement.h" @@ -61,7 +63,8 @@ static std::string TagNameKey(const LogStatisticsElement& element) { return std::string(msg, len); } -LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size) +LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size, + std::optional<log_time> start_time) : enable(enable_statistics), track_total_size_(track_total_size) { log_time now(CLOCK_REALTIME); log_id_for_each(id) { @@ -70,8 +73,13 @@ LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size) mDroppedElements[id] = 0; mSizesTotal[id] = 0; mElementsTotal[id] = 0; - mOldest[id] = now; - mNewest[id] = now; + if (start_time) { + mOldest[id] = *start_time; + mNewest[id] = *start_time; + } else { + mOldest[id] = now; + mNewest[id] = now; + } mNewestDropped[id] = now; } } @@ -784,6 +792,31 @@ std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, return output; } +std::string LogStatistics::ReportInteresting() const { + auto lock = std::lock_guard{lock_}; + + std::vector<std::string> items; + + log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); } + + log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); } + + log_id_for_each(i) { + items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i])); + } + + log_id_for_each(i) { + uint64_t oldest = mOldest[i].msec() / 1000; + uint64_t newest = mNewest[i].msec() / 1000; + + int span = newest - oldest; + + items.emplace_back(std::to_string(span)); + } + + return android::base::Join(items, ","); +} + std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const { auto lock = std::lock_guard{lock_}; diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index d440a8c61b..e222d3f244 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -515,7 +515,8 @@ class LogStatistics { } public: - LogStatistics(bool enable_statistics, bool track_total_size); + LogStatistics(bool enable_statistics, bool track_total_size, + std::optional<log_time> start_time = {}); void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_); @@ -556,6 +557,7 @@ class LogStatistics { return SizesTotal; } + std::string ReportInteresting() const EXCLUDES(lock_); std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_); const char* PidToName(pid_t pid) const EXCLUDES(lock_); diff --git a/logd/README.property b/logd/README.property index 1d7d990224..8fd7f481bd 100644 --- a/logd/README.property +++ b/logd/README.property @@ -7,8 +7,8 @@ ro.logd.auditd.main bool true selinux audit messages sent to main. ro.logd.auditd.events bool true selinux audit messages sent to events. persist.logd.security bool false Enable security buffer. ro.organization_owned bool false Override persist.logd.security to false -ro.logd.kernel bool+ svelte+ Enable klogd daemon -ro.logd.statistics bool+ svelte+ Enable logcat -S statistics. +ro.logd.kernel bool svelte+ Enable klogd daemon +logd.statistics bool svelte+ Enable logcat -S statistics. ro.debuggable number if not "1", logd.statistics & ro.logd.kernel default false. logd.logpersistd.enable bool auto Safe to start logpersist daemon service @@ -57,11 +57,8 @@ logd.buffer_type string (empty) Set the log buffer type. Current choi NB: - auto - managed by /init -- bool+ - "true", "false" and comma separated list of "eng" (forced false if - ro.debuggable is not "1") or "svelte" (forced false if ro.config.low_ram is - true). - svelte - see ro.config.low_ram for details. -- svelte+ - see ro.config.low_ram and ro.debuggable for details. +- svelte+ - If empty, default to true if `ro.config.low_ram == false && ro.debuggable == true` - ro - <base property> temporary override, ro.<base property> platform default. - persist - <base property> override, persist.<base property> platform default. - build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option. diff --git a/logd/README.replay.md b/logd/README.replay.md new file mode 100644 index 0000000000..5f7ec9eef1 --- /dev/null +++ b/logd/README.replay.md @@ -0,0 +1,46 @@ +logd can record and replay log messages for offline analysis. + +Recording Messages +------------------ + +logd has a `RecordingLogBuffer` buffer that records messages to /data/misc/logd/recorded-messages. +It stores messages in memory until that file is accessible, in order to capture all messages since +the beginning of boot. It is only meant for logging developers to use and must be manually enabled +in by adding `RecordingLogBuffer.cpp` to `Android.bp` and setting +`log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);` in `main.cpp`. + +Recording messages may delay the Log() function from completing and it is highly recommended to make +the logd socket in `liblog` blocking, by removing `SOCK_NONBLOCK` from the `socket()` call in +`liblog/logd_writer.cpp`. + +Replaying Messages +------------------ + +Recorded messages can be replayed offline with the `replay_messages` tool. It runs on host and +device and supports the following options: + +1. `interesting` - this prints 'interesting' statistics for each of the log buffer types (simple, + chatty, serialized). The statistics are: + 1. Log Entry Count + 2. Size (the uncompressed size of the log messages in bytes) + 3. Overhead (the total cost of the log messages in memory in bytes) + 4. Range (the range of time that the logs cover in seconds) +2. `memory_usage BUFFER_TYPE` - this prints the memory usage (sum of private dirty pages of the + `replay_messages` process). Note that the input file is mmap()'ed as RO/Shared so it does not + appear in these dirty pages, and a baseline is taken before allocating the log buffers, so only + their contributions are measured. The tool outputs the memory usage every 100,000 messages. +3. `latency BUFFER_TYPE` - this prints statistics of the latency of the Log() function for the given + buffer type. It specifically prints the 1st, 2nd, and 3rd quartiles; the 95th, 99th, and 99.99th + percentiles; and the maximum latency. +4. `print_logs BUFFER_TYPE [buffers] [print_point]` - this prints the logs as processed by the given + buffer_type from the buffers specified by `buffers` starting after the number of logs specified by + `print_point` have been logged. This acts as if a user called `logcat` immediately after the + specified logs have been logged, which is particularly useful since it will show the chatty + pruning messages at that point. It additionally prints the statistics from `logcat -S` after the + logs. + `buffers` is a comma separated list of the numeric buffer id values from `<android/log.h>`. For + example, `0,1,3` represents the main, radio, and system buffers. It can can also be `all`. + `print_point` is an positive integer. If it is unspecified, logs are printed after the entire + input file is consumed. +5. `nothing BUFFER_TYPE` - this does nothing other than read the input file and call Log() for the + given buffer type. This is used for profiling CPU usage of strictly the log buffer. diff --git a/logd/RecordedLogMessage.h b/logd/RecordedLogMessage.h new file mode 100644 index 0000000000..f18c422c85 --- /dev/null +++ b/logd/RecordedLogMessage.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <inttypes.h> + +#include <log/log_time.h> + +struct __attribute__((packed)) RecordedLogMessage { + uint32_t uid; + uint32_t pid; + uint32_t tid; + log_time realtime; + uint16_t msg_len; + uint8_t log_id; +}; diff --git a/logd/RecordingLogBuffer.cpp b/logd/RecordingLogBuffer.cpp new file mode 100644 index 0000000000..f5991f3701 --- /dev/null +++ b/logd/RecordingLogBuffer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RecordingLogBuffer.h" + +#include <android-base/file.h> + +static void WriteLogMessage(int fd, const RecordedLogMessage& meta, const std::string& msg) { + android::base::WriteFully(fd, &meta, sizeof(meta)); + android::base::WriteFully(fd, msg.c_str(), meta.msg_len); +} + +void RecordingLogBuffer::RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, + pid_t tid, const char* msg, uint16_t len) { + auto lock = std::lock_guard{lock_}; + if (len > LOGGER_ENTRY_MAX_PAYLOAD) { + len = LOGGER_ENTRY_MAX_PAYLOAD; + } + + RecordedLogMessage recorded_log_message = { + .uid = uid, + .pid = static_cast<uint32_t>(pid), + .tid = static_cast<uint32_t>(tid), + .realtime = realtime, + .msg_len = len, + .log_id = static_cast<uint8_t>(log_id), + }; + + if (!fd_.ok()) { + fd_.reset(open("/data/misc/logd/recorded-messages", + O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666)); + if (!fd_.ok()) { + since_boot_messages_.emplace_back(recorded_log_message, std::string(msg, len)); + return; + } else { + for (const auto& [meta, msg] : since_boot_messages_) { + WriteLogMessage(fd_.get(), meta, msg); + } + } + } + + WriteLogMessage(fd_.get(), recorded_log_message, std::string(msg, len)); +} + +int RecordingLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len) { + RecordLogMessage(log_id, realtime, uid, pid, tid, msg, len); + return SimpleLogBuffer::Log(log_id, realtime, uid, pid, tid, msg, len); +}
\ No newline at end of file diff --git a/logd/RecordingLogBuffer.h b/logd/RecordingLogBuffer.h new file mode 100644 index 0000000000..49a0aba373 --- /dev/null +++ b/logd/RecordingLogBuffer.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "SimpleLogBuffer.h" + +#include <string> +#include <tuple> +#include <vector> + +#include <android-base/unique_fd.h> + +#include "RecordedLogMessage.h" + +class RecordingLogBuffer : public SimpleLogBuffer { + public: + RecordingLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats) + : SimpleLogBuffer(reader_list, tags, stats) {} + + int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg, + uint16_t len) override; + + private: + void RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len); + + std::vector<std::pair<RecordedLogMessage, std::string>> since_boot_messages_; + android::base::unique_fd fd_; +}; diff --git a/logd/ReplayMessages.cpp b/logd/ReplayMessages.cpp new file mode 100644 index 0000000000..56509ecad0 --- /dev/null +++ b/logd/ReplayMessages.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <inttypes.h> + +#include <chrono> +#include <map> + +#include <android-base/file.h> +#include <android-base/mapped_file.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <android/log.h> +#include <log/log_time.h> +#include <log/logprint.h> + +#include "ChattyLogBuffer.h" +#include "LogBuffer.h" +#include "LogStatistics.h" +#include "RecordedLogMessage.h" +#include "SerializedLogBuffer.h" +#include "SimpleLogBuffer.h" + +using android::base::MappedFile; +using android::base::ParseInt; +using android::base::ParseUint; +using android::base::Split; + +char* android::uidToName(uid_t) { + return nullptr; +} + +static size_t GetPrivateDirty() { + // Allocate once and hope that we don't need to reallocate >40000, to prevent heap fragmentation + static std::string smaps(40000, '\0'); + android::base::ReadFileToString("/proc/self/smaps", &smaps); + + size_t result = 0; + size_t base = 0; + size_t found; + while (true) { + found = smaps.find("Private_Dirty:", base); + if (found == smaps.npos) break; + + found += sizeof("Private_Dirty:"); + + result += atoi(&smaps[found]); + + base = found + 1; + } + + return result; +} + +static AndroidLogFormat* GetLogFormat() { + static AndroidLogFormat* format = [] { + auto* format = android_log_format_new(); + android_log_setPrintFormat(format, android_log_formatFromString("threadtime")); + android_log_setPrintFormat(format, android_log_formatFromString("uid")); + return format; + }(); + return format; +} + +static void PrintMessage(struct log_msg* buf) { + bool is_binary = + buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY; + + AndroidLogEntry entry; + int err; + if (is_binary) { + char binaryMsgBuf[1024]; + err = android_log_processBinaryLogBuffer(&buf->entry, &entry, nullptr, binaryMsgBuf, + sizeof(binaryMsgBuf)); + } else { + err = android_log_processLogBuffer(&buf->entry, &entry); + } + if (err < 0) { + fprintf(stderr, "Error parsing log message\n"); + } + + android_log_printLogLine(GetLogFormat(), STDOUT_FILENO, &entry); +} + +static log_time GetFirstTimeStamp(const MappedFile& recorded_messages) { + if (sizeof(RecordedLogMessage) >= recorded_messages.size()) { + fprintf(stderr, "At least one log message must be present in the input\n"); + exit(1); + } + + auto* meta = reinterpret_cast<RecordedLogMessage*>(recorded_messages.data()); + return meta->realtime; +} + +static LogMask BuffersToLogMask(const char* buffers) { + if (buffers == nullptr || !strcmp(buffers, "all")) { + return kLogMaskAll; + } + auto string_ids = Split(buffers, ","); + LogMask log_mask = 0; + for (const auto& string_id : string_ids) { + int buffer_id; + if (!ParseInt(string_id, &buffer_id, 0, 7)) { + fprintf(stderr, "Could not parse buffer_id '%s'\n", string_id.c_str()); + exit(1); + } + log_mask |= 1 << buffer_id; + } + return log_mask; +} + +class StdoutWriter : public LogWriter { + public: + StdoutWriter() : LogWriter(0, true) {} + bool Write(const logger_entry& entry, const char* message) override { + struct log_msg log_msg; + log_msg.entry = entry; + if (log_msg.entry.len > LOGGER_ENTRY_MAX_PAYLOAD) { + fprintf(stderr, "payload too large %" PRIu16, log_msg.entry.len); + exit(1); + } + memcpy(log_msg.msg(), message, log_msg.entry.len); + + PrintMessage(&log_msg); + + return true; + } + + void Shutdown() override { + fprintf(stderr, "LogWriter::Shutdown() called\n"); + exit(1); + } + + std::string name() const override { return "stdout writer"; } +}; + +class Operation { + public: + virtual ~Operation() {} + + virtual void Begin() {} + virtual void Log(const RecordedLogMessage& meta, const char* msg) = 0; + virtual void End() {} +}; + +class PrintInteresting : public Operation { + public: + PrintInteresting(log_time first_log_timestamp) + : stats_simple_{false, false, first_log_timestamp}, + stats_chatty_{false, false, first_log_timestamp}, + stats_serialized_{false, true, first_log_timestamp} {} + + void Begin() override { + printf("message_count,simple_main_lines,simple_radio_lines,simple_events_lines,simple_" + "system_lines,simple_crash_lines,simple_stats_lines,simple_security_lines,simple_" + "kernel_lines,simple_main_size,simple_radio_size,simple_events_size,simple_system_" + "size,simple_crash_size,simple_stats_size,simple_security_size,simple_kernel_size," + "simple_main_overhead,simple_radio_overhead,simple_events_overhead,simple_system_" + "overhead,simple_crash_overhead,simple_stats_overhead,simple_security_overhead," + "simple_kernel_overhead,simple_main_range,simple_radio_range,simple_events_range," + "simple_system_range,simple_crash_range,simple_stats_range,simple_security_range," + "simple_kernel_range,chatty_main_lines,chatty_radio_lines,chatty_events_lines," + "chatty_system_lines,chatty_crash_lines,chatty_stats_lines,chatty_security_lines," + "chatty_" + "kernel_lines,chatty_main_size,chatty_radio_size,chatty_events_size,chatty_system_" + "size,chatty_crash_size,chatty_stats_size,chatty_security_size,chatty_kernel_size," + "chatty_main_overhead,chatty_radio_overhead,chatty_events_overhead,chatty_system_" + "overhead,chatty_crash_overhead,chatty_stats_overhead,chatty_security_overhead," + "chatty_kernel_overhead,chatty_main_range,chatty_radio_range,chatty_events_range," + "chatty_system_range,chatty_crash_range,chatty_stats_range,chatty_security_range," + "chatty_kernel_range,serialized_main_lines,serialized_radio_lines,serialized_events_" + "lines,serialized_" + "system_lines,serialized_crash_lines,serialized_stats_lines,serialized_security_" + "lines,serialized_" + "kernel_lines,serialized_main_size,serialized_radio_size,serialized_events_size," + "serialized_system_" + "size,serialized_crash_size,serialized_stats_size,serialized_security_size," + "serialized_kernel_size," + "serialized_main_overhead,serialized_radio_overhead,serialized_events_overhead," + "serialized_system_" + "overhead,serialized_crash_overhead,serialized_stats_overhead,serialized_security_" + "overhead," + "serialized_kernel_overhead,serialized_main_range,serialized_radio_range,serialized_" + "events_range," + "serialized_system_range,serialized_crash_range,serialized_stats_range,serialized_" + "security_range," + "serialized_kernel_range\n"); + } + + void Log(const RecordedLogMessage& meta, const char* msg) override { + simple_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + chatty_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + serialized_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + if (num_message_ % 10000 == 0) { + printf("%" PRIu64 ",%s,%s,%s\n", num_message_, + stats_simple_.ReportInteresting().c_str(), + stats_chatty_.ReportInteresting().c_str(), + stats_serialized_.ReportInteresting().c_str()); + } + + num_message_++; + } + + private: + uint64_t num_message_ = 1; + + LogReaderList reader_list_; + LogTags tags_; + PruneList prune_list_; + + LogStatistics stats_simple_; + SimpleLogBuffer simple_log_buffer_{&reader_list_, &tags_, &stats_simple_}; + + LogStatistics stats_chatty_; + ChattyLogBuffer chatty_log_buffer_{&reader_list_, &tags_, &prune_list_, &stats_chatty_}; + + LogStatistics stats_serialized_; + SerializedLogBuffer serialized_log_buffer_{&reader_list_, &tags_, &stats_serialized_}; +}; + +class SingleBufferOperation : public Operation { + public: + SingleBufferOperation(log_time first_log_timestamp, const char* buffer) { + if (!strcmp(buffer, "simple")) { + stats_.reset(new LogStatistics{false, false, first_log_timestamp}); + log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, stats_.get())); + } else if (!strcmp(buffer, "chatty")) { + stats_.reset(new LogStatistics{false, false, first_log_timestamp}); + log_buffer_.reset( + new ChattyLogBuffer(&reader_list_, &tags_, &prune_list_, stats_.get())); + } else if (!strcmp(buffer, "serialized")) { + stats_.reset(new LogStatistics{false, true, first_log_timestamp}); + log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, stats_.get())); + } else { + fprintf(stderr, "invalid log buffer type '%s'\n", buffer); + abort(); + } + } + + void Log(const RecordedLogMessage& meta, const char* msg) override { + PreOperation(); + log_buffer_->Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, meta.pid, + meta.tid, msg, meta.msg_len); + + Operation(); + + num_message_++; + } + + virtual void PreOperation() {} + virtual void Operation() {} + + protected: + uint64_t num_message_ = 1; + + LogReaderList reader_list_; + LogTags tags_; + PruneList prune_list_; + + std::unique_ptr<LogStatistics> stats_; + std::unique_ptr<LogBuffer> log_buffer_; +}; + +class PrintMemory : public SingleBufferOperation { + public: + PrintMemory(log_time first_log_timestamp, const char* buffer) + : SingleBufferOperation(first_log_timestamp, buffer) {} + + void Operation() override { + if (num_message_ % 100000 == 0) { + printf("%" PRIu64 ",%s\n", num_message_, + std::to_string(GetPrivateDirty() - baseline_memory_).c_str()); + } + } + + private: + size_t baseline_memory_ = GetPrivateDirty(); +}; + +class PrintLogs : public SingleBufferOperation { + public: + PrintLogs(log_time first_log_timestamp, const char* buffer, const char* buffers, + const char* print_point) + : SingleBufferOperation(first_log_timestamp, buffer) { + mask_ = BuffersToLogMask(buffers); + if (print_point != nullptr) { + uint64_t result = 0; + if (!ParseUint(print_point, &result)) { + fprintf(stderr, "Could not parse print point '%s'\n", print_point); + exit(1); + } + print_point_ = result; + } + } + + void Operation() override { + if (print_point_ && num_message_ >= *print_point_) { + End(); + exit(0); + } + } + + void End() override { + std::unique_ptr<LogWriter> test_writer(new StdoutWriter()); + std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, mask_); + log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr); + + auto stats_string = stats_->Format(0, 0, mask_); + printf("%s\n", stats_string.c_str()); + } + + private: + LogMask mask_ = kLogMaskAll; + std::optional<uint64_t> print_point_; +}; + +class PrintLatency : public SingleBufferOperation { + public: + PrintLatency(log_time first_log_timestamp, const char* buffer) + : SingleBufferOperation(first_log_timestamp, buffer) {} + + void PreOperation() override { operation_start_ = std::chrono::steady_clock::now(); } + + void Operation() override { + auto end = std::chrono::steady_clock::now(); + auto duration = (end - operation_start_).count(); + durations_.emplace_back(duration); + } + + void End() override { + std::sort(durations_.begin(), durations_.end()); + auto q1 = durations_.size() / 4; + auto q2 = durations_.size() / 2; + auto q3 = 3 * durations_.size() / 4; + + auto p95 = 95 * durations_.size() / 100; + auto p99 = 99 * durations_.size() / 100; + auto p9999 = 9999 * durations_.size() / 10000; + + printf("q1: %lld q2: %lld q3: %lld p95: %lld p99: %lld p99.99: %lld max: %lld\n", + durations_[q1], durations_[q2], durations_[q3], durations_[p95], durations_[p99], + durations_[p9999], durations_.back()); + } + + private: + std::chrono::steady_clock::time_point operation_start_; + std::vector<long long> durations_; +}; + +class PrintAllLogs : public SingleBufferOperation { + public: + PrintAllLogs(log_time first_log_timestamp, const char* buffer, const char* buffers) + : SingleBufferOperation(first_log_timestamp, buffer) { + LogMask mask = BuffersToLogMask(buffers); + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + std::unique_ptr<LogWriter> stdout_writer(new StdoutWriter()); + std::unique_ptr<LogReaderThread> log_reader( + new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(stdout_writer), + false, 0, mask, 0, {}, 1, {})); + reader_list_.reader_threads().emplace_back(std::move(log_reader)); + } + + void Operation() override { + // If the rate of reading logs is slower than the rate of incoming logs, then the reader + // thread is disconnected to not overflow log buffers, therefore we artificially slow down + // the incoming log rate. + usleep(100); + } +}; + +int main(int argc, char** argv) { + if (argc < 3) { + fprintf(stderr, "Usage: %s FILE OPERATION [BUFFER] [OPTIONS]\n", argv[0]); + return 1; + } + + if (strcmp(argv[2], "interesting") != 0 && argc < 4) { + fprintf(stderr, "Operations other than 'interesting' require a BUFFER argument\n"); + return 1; + } + + int recorded_messages_fd = open(argv[1], O_RDONLY); + if (recorded_messages_fd == -1) { + fprintf(stderr, "Couldn't open input file\n"); + return 1; + } + struct stat fd_stat; + if (fstat(recorded_messages_fd, &fd_stat) != 0) { + fprintf(stderr, "Couldn't fstat input file\n"); + return 1; + } + auto recorded_messages = MappedFile::FromFd(recorded_messages_fd, 0, + static_cast<size_t>(fd_stat.st_size), PROT_READ); + if (recorded_messages == nullptr) { + fprintf(stderr, "Couldn't mmap input file\n"); + return 1; + } + + // LogStatistics typically uses 'now()' to initialize its log range state, but this doesn't work + // when replaying older logs, so we instead give it the timestamp from the first log. + log_time first_log_timestamp = GetFirstTimeStamp(*recorded_messages); + + std::unique_ptr<Operation> operation; + if (!strcmp(argv[2], "interesting")) { + operation.reset(new PrintInteresting(first_log_timestamp)); + } else if (!strcmp(argv[2], "memory_usage")) { + operation.reset(new PrintMemory(first_log_timestamp, argv[3])); + } else if (!strcmp(argv[2], "latency")) { + operation.reset(new PrintLatency(first_log_timestamp, argv[3])); + } else if (!strcmp(argv[2], "print_logs")) { + operation.reset(new PrintLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr, + argc > 5 ? argv[5] : nullptr)); + } else if (!strcmp(argv[2], "print_all_logs")) { + operation.reset( + new PrintAllLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr)); + } else if (!strcmp(argv[2], "nothing")) { + operation.reset(new SingleBufferOperation(first_log_timestamp, argv[3])); + } else { + fprintf(stderr, "unknown operation '%s'\n", argv[2]); + return 1; + } + + // LogBuffer::Log() won't log without this on host. + __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE); + // But we still want to suppress messages <= error to not interrupt the rest of the output. + __android_log_set_logger([](const struct __android_log_message* log_message) { + if (log_message->priority < ANDROID_LOG_ERROR) { + return; + } + __android_log_stderr_logger(log_message); + }); + + operation->Begin(); + + uint64_t read_position = 0; + while (read_position + sizeof(RecordedLogMessage) < recorded_messages->size()) { + auto* meta = + reinterpret_cast<RecordedLogMessage*>(recorded_messages->data() + read_position); + if (read_position + sizeof(RecordedLogMessage) + meta->msg_len >= + recorded_messages->size()) { + break; + } + char* msg = recorded_messages->data() + read_position + sizeof(RecordedLogMessage); + read_position += sizeof(RecordedLogMessage) + meta->msg_len; + + operation->Log(*meta, msg); + } + + operation->End(); + + return 0; +} diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp index 2633348cf0..b02ccc3494 100644 --- a/logd/SerializedFlushToState.cpp +++ b/logd/SerializedFlushToState.cpp @@ -31,7 +31,7 @@ SerializedFlushToState::SerializedFlushToState(uint64_t start, LogMask log_mask) SerializedFlushToState::~SerializedFlushToState() { log_id_for_each(i) { if (log_positions_[i]) { - log_positions_[i]->buffer_it->DecReaderRefCount(true); + log_positions_[i]->buffer_it->DecReaderRefCount(); } } } @@ -78,7 +78,7 @@ void SerializedFlushToState::AddMinHeapEntry(log_id_t log_id) { logs_needed_from_next_position_[log_id] = true; } else { // Otherwise, if there is another buffer piece, move to that and do the same check. - buffer_it->DecReaderRefCount(true); + buffer_it->DecReaderRefCount(); ++buffer_it; buffer_it->IncReaderRefCount(); log_positions_[log_id]->read_offset = 0; @@ -134,7 +134,7 @@ void SerializedFlushToState::Prune(log_id_t log_id, } // // Decrease the ref count since we're deleting our reference. - buffer_it->DecReaderRefCount(false); + buffer_it->DecReaderRefCount(); // Delete in the reference. log_positions_[log_id].reset(); diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp index a626d30e83..972a3f3a97 100644 --- a/logd/SerializedLogBuffer.cpp +++ b/logd/SerializedLogBuffer.cpp @@ -123,7 +123,7 @@ void SerializedLogBuffer::RemoveChunkFromStats(log_id_t log_id, SerializedLogChu stats_->Subtract(entry->ToLogStatisticsElement(log_id)); read_offset += entry->total_len(); } - chunk.DecReaderRefCount(false); + chunk.DecReaderRefCount(); } void SerializedLogBuffer::NotifyReadersOfPrune( diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp index e444856a40..de641d62a2 100644 --- a/logd/SerializedLogChunk.cpp +++ b/logd/SerializedLogChunk.cpp @@ -31,7 +31,6 @@ void SerializedLogChunk::Compress() { << " size used: " << write_offset_ << " compressed size: " << compressed_log_.size(); } - contents_.Resize(0); } // TODO: Develop a better reference counting strategy to guard against the case where the writer is @@ -44,13 +43,13 @@ void SerializedLogChunk::IncReaderRefCount() { CompressionEngine::GetInstance().Decompress(compressed_log_, contents_); } -void SerializedLogChunk::DecReaderRefCount(bool compress) { +void SerializedLogChunk::DecReaderRefCount() { CHECK_NE(reader_ref_count_, 0U); if (--reader_ref_count_ != 0) { return; } - if (compress && !writer_active_) { - Compress(); + if (!writer_active_) { + contents_.Resize(0); } } @@ -83,18 +82,19 @@ bool SerializedLogChunk::ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* } if (new_write_offset == 0) { - DecReaderRefCount(false); + DecReaderRefCount(); return true; } - // Clear the old compressed logs and set write_offset_ appropriately for DecReaderRefCount() - // to compress the new partially cleared log. + // Clear the old compressed logs and set write_offset_ appropriately to compress the new + // partially cleared log. if (new_write_offset != write_offset_) { compressed_log_.Resize(0); write_offset_ = new_write_offset; + Compress(); } - DecReaderRefCount(true); + DecReaderRefCount(); return false; } diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h index 50bae638c6..0991eacb6b 100644 --- a/logd/SerializedLogChunk.h +++ b/logd/SerializedLogChunk.h @@ -30,9 +30,7 @@ class SerializedLogChunk { void Compress(); void IncReaderRefCount(); - // Decrease the reader ref count and compress the log if appropriate. `compress` should only be - // set to false in the case that the log buffer will be deleted afterwards. - void DecReaderRefCount(bool compress); + void DecReaderRefCount(); // Must have no readers referencing this. Return true if there are no logs left in this chunk. bool ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats); @@ -50,8 +48,9 @@ class SerializedLogChunk { void FinishWriting() { writer_active_ = false; + Compress(); if (reader_ref_count_ == 0) { - Compress(); + contents_.Resize(0); } } diff --git a/logd/SerializedLogChunkTest.cpp b/logd/SerializedLogChunkTest.cpp index 2b478a3fbb..f10b9c673b 100644 --- a/logd/SerializedLogChunkTest.cpp +++ b/logd/SerializedLogChunkTest.cpp @@ -113,8 +113,7 @@ TEST(SerializedLogChunk, three_logs) { TEST(SerializedLogChunk, catch_DecCompressedRef_CHECK) { size_t chunk_size = 10 * 4096; auto chunk = SerializedLogChunk{chunk_size}; - EXPECT_DEATH({ chunk.DecReaderRefCount(true); }, ""); - EXPECT_DEATH({ chunk.DecReaderRefCount(false); }, ""); + EXPECT_DEATH({ chunk.DecReaderRefCount(); }, ""); } // Check that the CHECK() in ClearUidLogs() if the ref count is greater than 0 is caught. @@ -123,7 +122,7 @@ TEST(SerializedLogChunk, catch_ClearUidLogs_CHECK) { auto chunk = SerializedLogChunk{chunk_size}; chunk.IncReaderRefCount(); EXPECT_DEATH({ chunk.ClearUidLogs(1000, LOG_ID_MAIN, nullptr); }, ""); - chunk.DecReaderRefCount(false); + chunk.DecReaderRefCount(); } class UidClearTest : public testing::TestWithParam<bool> { @@ -144,7 +143,7 @@ class UidClearTest : public testing::TestWithParam<bool> { check(chunk_); if (finish_writing) { - chunk_.DecReaderRefCount(false); + chunk_.DecReaderRefCount(); } } diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp index 8309f95147..d71a2f91f0 100644 --- a/logd/fuzz/log_buffer_log_fuzzer.cpp +++ b/logd/fuzz/log_buffer_log_fuzzer.cpp @@ -30,16 +30,6 @@ #define MIN_TAG_ID 1000 #define TAG_MOD 10 -#ifndef __ANDROID__ -unsigned long __android_logger_get_buffer_size(log_id_t) { - return 1024 * 1024; -} - -bool __android_logger_valid_buffer_size(unsigned long) { - return true; -} -#endif - char* android::uidToName(uid_t) { return strdup("fake"); } diff --git a/logd/logd_test.cpp b/logd/logd_test.cpp index ed34ea413c..5a0585a735 100644 --- a/logd/logd_test.cpp +++ b/logd/logd_test.cpp @@ -162,6 +162,7 @@ static char* find_benchmark_spam(char* cp) { } #endif +#ifdef LOGD_ENABLE_FLAKY_TESTS TEST(logd, statistics) { #ifdef __ANDROID__ size_t len; @@ -237,6 +238,7 @@ TEST(logd, statistics) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } +#endif #ifdef __ANDROID__ static void caught_signal(int /* signum */) { @@ -720,6 +722,7 @@ TEST(logd, timeout) { } #endif +#ifdef LOGD_ENABLE_FLAKY_TESTS // b/27242723 confirmed fixed TEST(logd, SNDTIMEO) { #ifdef __ANDROID__ @@ -777,6 +780,7 @@ TEST(logd, SNDTIMEO) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } +#endif TEST(logd, getEventTag_list) { #ifdef __ANDROID__ @@ -832,127 +836,3 @@ TEST(logd, getEventTag_newentry) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } - -#ifdef __ANDROID__ -static inline uint32_t get4LE(const uint8_t* src) { - return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); -} - -static inline uint32_t get4LE(const char* src) { - return get4LE(reinterpret_cast<const uint8_t*>(src)); -} -#endif - -void __android_log_btwrite_multiple__helper(int count) { -#ifdef __ANDROID__ - log_time ts(CLOCK_MONOTONIC); - usleep(100); - log_time ts1(CLOCK_MONOTONIC); - - // We fork to create a unique pid for the submitted log messages - // so that we do not collide with the other _multiple_ tests. - - pid_t pid = fork(); - - if (pid == 0) { - // child - for (int i = count; i; --i) { - ASSERT_LT( - 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); - usleep(100); - } - ASSERT_LT(0, - __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1))); - usleep(1000000); - - _exit(0); - } - - siginfo_t info = {}; - ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))); - ASSERT_EQ(0, info.si_status); - - struct logger_list* logger_list; - ASSERT_TRUE(nullptr != (logger_list = android_logger_list_open(LOG_ID_EVENTS, - ANDROID_LOG_NONBLOCK, 0, pid))); - - int expected_count = (count < 2) ? count : 2; - int expected_chatty_count = (count <= 2) ? 0 : 1; - int expected_identical_count = (count < 2) ? 0 : (count - 2); - static const int expected_expire_count = 0; - - count = 0; - int second_count = 0; - int chatty_count = 0; - int identical_count = 0; - int expire_count = 0; - - for (;;) { - log_msg log_msg; - if (android_logger_list_read(logger_list, &log_msg) <= 0) break; - - if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) || - (log_msg.id() != LOG_ID_EVENTS)) - continue; - - char* eventData = log_msg.msg(); - if (!eventData) continue; - - uint32_t tag = get4LE(eventData); - - if ((eventData[4] == EVENT_TYPE_LONG) && - (log_msg.entry.len == (4 + 1 + 8))) { - if (tag != 0) continue; - - log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1); - if (ts == *tx) { - ++count; - } else if (ts1 == *tx) { - ++second_count; - } - } else if (eventData[4] == EVENT_TYPE_STRING) { - if (tag != CHATTY_LOG_TAG) continue; - ++chatty_count; - // int len = get4LE(eventData + 4 + 1); - log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0'; - const char* cp; - if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) { - unsigned val = 0; - sscanf(cp, " identical %u lines", &val); - identical_count += val; - } else if ((cp = strstr(eventData + 4 + 1 + 4, " expire "))) { - unsigned val = 0; - sscanf(cp, " expire %u lines", &val); - expire_count += val; - } - } - } - - android_logger_list_close(logger_list); - - EXPECT_EQ(expected_count, count); - EXPECT_EQ(1, second_count); - EXPECT_EQ(expected_chatty_count, chatty_count); - EXPECT_EQ(expected_identical_count, identical_count); - EXPECT_EQ(expected_expire_count, expire_count); -#else - count = 0; - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif -} - -TEST(logd, multiple_test_1) { - __android_log_btwrite_multiple__helper(1); -} - -TEST(logd, multiple_test_2) { - __android_log_btwrite_multiple__helper(2); -} - -TEST(logd, multiple_test_3) { - __android_log_btwrite_multiple__helper(3); -} - -TEST(logd, multiple_test_10) { - __android_log_btwrite_multiple__helper(10); -} diff --git a/logd/main.cpp b/logd/main.cpp index 897e11e3a3..c92c5b7194 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -62,7 +62,9 @@ #include "SerializedLogBuffer.h" #include "SimpleLogBuffer.h" +using android::base::GetBoolProperty; using android::base::GetProperty; +using android::base::SetProperty; #define KMSG_PRIORITY(PRI) \ '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \ @@ -82,9 +84,10 @@ static void DropPrivs(bool klogd, bool auditd) { PLOG(FATAL) << "failed to set batch scheduler"; } - if (!__android_logger_property_get_bool("ro.debuggable", BOOL_DEFAULT_FALSE) && - prctl(PR_SET_DUMPABLE, 0) == -1) { - PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE"; + if (!GetBoolProperty("ro.debuggable", false)) { + if (prctl(PR_SET_DUMPABLE, 0) == -1) { + PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE"; + } } std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free); @@ -110,6 +113,14 @@ static void DropPrivs(bool klogd, bool auditd) { } } +// GetBoolProperty that defaults to true if `ro.debuggable == true && ro.config.low_rawm == false`. +static bool GetBoolPropertyEngSvelteDefault(const std::string& name) { + bool default_value = + GetBoolProperty("ro.debuggable", false) && !GetBoolProperty("ro.config.low_ram", false); + + return GetBoolProperty(name, default_value); +} + char* android::uidToName(uid_t u) { struct Userdata { uid_t uid; @@ -207,6 +218,8 @@ static int issueReinit() { // logging plugins like auditd and restart control. Additional // transitory per-client threads are created for each reader. int main(int argc, char* argv[]) { + // We want EPIPE when a reader disconnects, not to terminate logd. + signal(SIGPIPE, SIG_IGN); // logd is written under the assumption that the timezone is UTC. // If TZ is not set, persist.sys.timezone is looked up in some time utility // libc functions, including mktime. It confuses the logd time handling, @@ -236,10 +249,9 @@ int main(int argc, char* argv[]) { } int fdPmesg = -1; - bool klogd = __android_logger_property_get_bool( - "ro.logd.kernel", - BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); + bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel"); if (klogd) { + SetProperty("ro.logd.kernel", "true"); static const char proc_kmsg[] = "/proc/kmsg"; fdPmesg = android_get_control_file(proc_kmsg); if (fdPmesg < 0) { @@ -249,7 +261,7 @@ int main(int argc, char* argv[]) { if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg; } - bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE); + bool auditd = GetBoolProperty("ro.logd.auditd", true); DropPrivs(klogd, auditd); // A cache of event log tags @@ -258,13 +270,11 @@ int main(int argc, char* argv[]) { // Pruning configuration. PruneList prune_list; - std::string buffer_type = GetProperty("logd.buffer_type", "chatty"); + std::string buffer_type = GetProperty("logd.buffer_type", "serialized"); // Partial (required for chatty) or full logging statistics. - bool enable_full_log_statistics = __android_logger_property_get_bool( - "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST | - BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); - LogStatistics log_statistics(enable_full_log_statistics, buffer_type == "serialized"); + LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"), + buffer_type == "serialized"); // Serves the purpose of managing the last logs times read on a socket connection, and as a // reader lock on a range of log entries. @@ -309,9 +319,7 @@ int main(int argc, char* argv[]) { // and LogReader is notified to send updates to connected clients. LogAudit* al = nullptr; if (auditd) { - int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE) - ? fdDmesg - : -1; + int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1; al = new LogAudit(log_buffer, dmesg_fd, &log_statistics); } |
