Merge changes from topic "bug_168791309"
* changes:
Add symlinks to satisfy include paths.
Remove liblog, logcat, logd, logwrapper
diff --git a/liblog b/liblog
new file mode 120000
index 0000000..71443ae
--- /dev/null
+++ b/liblog
@@ -0,0 +1 @@
+../logging/liblog
\ No newline at end of file
diff --git a/liblog/.clang-format b/liblog/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/liblog/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/liblog/Android.bp b/liblog/Android.bp
deleted file mode 100644
index 8f15541..0000000
--- a/liblog/Android.bp
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-// Copyright (C) 2008-2014 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.
-//
-
-liblog_sources = [
- "log_event_list.cpp",
- "log_event_write.cpp",
- "logger_name.cpp",
- "logger_read.cpp",
- "logger_write.cpp",
- "logprint.cpp",
- "properties.cpp",
-]
-liblog_target_sources = [
- "event_tag_map.cpp",
- "log_time.cpp",
- "pmsg_reader.cpp",
- "pmsg_writer.cpp",
- "logd_reader.cpp",
- "logd_writer.cpp",
-]
-
-cc_library_headers {
- name: "liblog_headers",
- host_supported: true,
- vendor_available: true,
- ramdisk_available: true,
- recovery_available: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
- min_sdk_version: "29",
- sdk_version: "minimum",
- native_bridge_supported: true,
- export_include_dirs: ["include"],
- system_shared_libs: [],
- stl: "none",
- target: {
- windows: {
- enabled: true,
- },
- linux_bionic: {
- enabled: true,
- },
- vendor: {
- override_export_include_dirs: ["include_vndk"],
- },
- },
-}
-
-// Shared and static library for host and device
-// ========================================================
-cc_library {
- name: "liblog",
- host_supported: true,
- ramdisk_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- srcs: liblog_sources,
-
- target: {
- android: {
- version_script: "liblog.map.txt",
- srcs: liblog_target_sources,
- // AddressSanitizer runtime library depends on liblog.
- sanitize: {
- address: false,
- },
- },
- android_arm: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
- },
- windows: {
- enabled: true,
- },
- not_windows: {
- srcs: ["event_tag_map.cpp"],
- },
- linux_bionic: {
- enabled: true,
- },
- },
-
- header_libs: [
- "libbase_headers",
- "libcutils_headers",
- "liblog_headers",
- ],
- export_header_lib_headers: ["liblog_headers"],
-
- stubs: {
- symbol_file: "liblog.map.txt",
- versions: ["29", "30"],
- },
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- // This is what we want to do:
- // liblog_cflags := $(shell \
- // sed -n \
- // 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
- // $(LOCAL_PATH)/event.logtags)
- // so make sure we do not regret hard-coding it as follows:
- "-DLIBLOG_LOG_TAG=1006",
- "-DSNET_EVENT_LOG_TAG=1397638484",
- ],
- logtags: ["event.logtags"],
- compile_multilib: "both",
- apex_available: [
- "//apex_available:platform",
- // liblog is exceptionally available to the runtime APEX
- // because the dynamic linker has to use it statically.
- // See b/151051671
- "com.android.runtime",
- // DO NOT add more apex names here
- ],
-}
-
-ndk_headers {
- name: "liblog_ndk_headers",
- from: "include/android",
- to: "android",
- srcs: ["include/android/log.h"],
- license: "NOTICE",
-}
-
-ndk_library {
- name: "liblog",
- symbol_file: "liblog.map.txt",
- first_version: "9",
- unversioned_until: "current",
-}
-
-llndk_library {
- name: "liblog",
- native_bridge_supported: true,
- symbol_file: "liblog.map.txt",
- export_include_dirs: ["include_vndk"],
-}
diff --git a/liblog/NOTICE b/liblog/NOTICE
deleted file mode 100644
index 06a9081..0000000
--- a/liblog/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2014, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/liblog/OWNERS b/liblog/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/liblog/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/liblog/README.md b/liblog/README.md
deleted file mode 100644
index 74a2cd7..0000000
--- a/liblog/README.md
+++ /dev/null
@@ -1,161 +0,0 @@
-Android liblog
---------------
-
-Public Functions and Macros
----------------------------
-
- /*
- * Please limit to 24 characters for runtime is loggable,
- * 16 characters for persist is loggable, and logcat pretty
- * alignment with limit of 7 characters.
- */
- #define LOG_TAG "yourtag"
- #include <log/log.h>
-
- ALOG(android_priority, tag, format, ...)
- IF_ALOG(android_priority, tag)
- LOG_PRI(priority, tag, format, ...)
- LOG_PRI_VA(priority, tag, format, args)
- #define LOG_TAG NULL
- ALOGV(format, ...)
- SLOGV(format, ...)
- RLOGV(format, ...)
- ALOGV_IF(cond, format, ...)
- SLOGV_IF(cond, format, ...)
- RLOGV_IF(cond, format, ...)
- IF_ALOGC()
- ALOGD(format, ...)
- SLOGD(format, ...)
- RLOGD(format, ...)
- ALOGD_IF(cond, format, ...)
- SLOGD_IF(cond, format, ...)
- RLOGD_IF(cond, format, ...)
- IF_ALOGD()
- ALOGI(format, ...)
- SLOGI(format, ...)
- RLOGI(format, ...)
- ALOGI_IF(cond, format, ...)
- SLOGI_IF(cond, format, ...)
- RLOGI_IF(cond, format, ...)
- IF_ALOGI()
- ALOGW(format, ...)
- SLOGW(format, ...)
- RLOGW(format, ...)
- ALOGW_IF(cond, format, ...)
- SLOGW_IF(cond, format, ...)
- RLOGW_IF(cond, format, ...)
- IF_ALOGW()
- ALOGE(format, ...)
- SLOGE(format, ...)
- RLOGE(format, ...)
- ALOGE_IF(cond, format, ...)
- SLOGE_IF(cond, format, ...)
- RLOGE_IF(cond, format, ...)
- IF_ALOGE()
- LOG_FATAL(format, ...)
- LOG_ALWAYS_FATAL(format, ...)
- LOG_FATAL_IF(cond, format, ...)
- LOG_ALWAYS_FATAL_IF(cond, format, ...)
- ALOG_ASSERT(cond, format, ...)
- LOG_EVENT_INT(tag, value)
- LOG_EVENT_LONG(tag, value)
-
- log_id_t android_logger_get_id(struct logger *logger)
- int android_logger_clear(struct logger *logger)
- int android_logger_get_log_size(struct logger *logger)
- int android_logger_get_log_readable_size(struct logger *logger)
- int android_logger_get_log_version(struct logger *logger)
-
- struct logger_list *android_logger_list_alloc(int mode, unsigned int tail, pid_t pid)
- struct logger *android_logger_open(struct logger_list *logger_list, log_id_t id)
- struct logger_list *android_logger_list_open(log_id_t id, int mode, unsigned int tail, pid_t pid)
- int android_logger_list_read(struct logger_list *logger_list, struct log_msg *log_msg)
- void android_logger_list_free(struct logger_list *logger_list)
-
- log_id_t android_name_to_log_id(const char *logName)
- const char *android_log_id_to_name(log_id_t log_id)
-
- android_log_context create_android_logger(uint32_t tag)
-
- int android_log_write_list_begin(android_log_context ctx)
- int android_log_write_list_end(android_log_context ctx)
-
- int android_log_write_int32(android_log_context ctx, int32_t value)
- int android_log_write_int64(android_log_context ctx, int64_t value)
- int android_log_write_string8(android_log_context ctx, const char *value)
- int android_log_write_string8_len(android_log_context ctx, const char *value, size_t maxlen)
- int android_log_write_float32(android_log_context ctx, float value)
-
- int android_log_write_list(android_log_context ctx, log_id_t id = LOG_ID_EVENTS)
-
- android_log_context create_android_log_parser(const char *msg, size_t len)
- android_log_list_element android_log_read_next(android_log_context ctx)
- android_log_list_element android_log_peek_next(android_log_context ctx)
-
- int android_log_destroy(android_log_context *ctx)
-
-Description
------------
-
-liblog represents an interface to the volatile Android Logging system for NDK (Native) applications
-and libraries. Interfaces for either writing or reading logs. The log buffers are divided up in
-Main, System, Radio and Events sub-logs.
-
-The logging interfaces are a series of macros, all of which can be overridden individually in order
-to control the verbosity of the application or library. `[ASR]LOG[VDIWE]` calls are used to log to
-BAsic, System or Radio sub-logs in either the Verbose, Debug, Info, Warning or Error priorities.
-`[ASR]LOG[VDIWE]_IF` calls are used to perform thus based on a condition being true.
-`IF_ALOG[VDIWE]` calls are true if the current `LOG_TAG` is enabled at the specified priority.
-`LOG_ALWAYS_FATAL` is used to `ALOG` a message, then kill the process. `LOG_FATAL` call is a
-variant of `LOG_ALWAYS_FATAL`, only enabled in engineering, and not release builds. `ALOG_ASSERT`
-is used to `ALOG` a message if the condition is false; the condition is part of the logged message.
-`LOG_EVENT_(INT|LONG)` is used to drop binary content into the Events sub-log.
-
-The log reading interfaces permit opening the logs either singly or multiply, retrieving a log entry
-at a time in time sorted order, optionally limited to a specific pid and tail of the log(s) and
-finally a call closing the logs. A single log can be opened with `android_logger_list_open()`; or
-multiple logs can be opened with `android_logger_list_alloc()`, calling in turn the
-`android_logger_open()` for each log id. Each entry can be retrieved with
-`android_logger_list_read()`. The log(s) can be closed with `android_logger_list_free()`.
-`ANDROID_LOG_NONBLOCK` mode will report when the log reading is done with an `EAGAIN` error return
-code, otherwise the `android_logger_list_read()` call will block for new entries.
-
-The `ANDROID_LOG_WRAP` mode flag to the `android_logger_list_alloc_time()` signals logd to quiesce
-the reader until the buffer is about to prune at the start time then proceed to dumping content.
-
-The `ANDROID_LOG_PSTORE` mode flag to the `android_logger_open()` is used to switch from the active
-logs to the persistent logs from before the last reboot.
-
-The value returned by `android_logger_open()` can be used as a parameter to the
-`android_logger_clear()` function to empty the sub-log.
-
-The value returned by `android_logger_open()` can be used as a parameter to the
-`android_logger_get_log_(size|readable_size|version)` to retrieve the sub-log maximum size, readable
-size and log buffer format protocol version respectively. `android_logger_get_id()` returns the id
-that was used when opening the sub-log.
-
-Errors
-------
-
-If messages fail, a negative error code will be returned to the caller.
-
-The `-ENOTCONN` return code indicates that the logger daemon is stopped.
-
-The `-EBADF` return code indicates that the log access point can not be opened, or the log buffer id
-is out of range.
-
-For the `-EAGAIN` return code, this means that the logging message was temporarily backed-up either
-because of Denial Of Service (DOS) logging pressure from some chatty application or service in the
-Android system, or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen. To aid in
-diagnosing the occurence of this, a binary event from liblog will be sent to the log daemon once a
-new message can get through indicating how many messages were dropped as a result. Please take
-action to resolve the structural problems at the source.
-
-It is generally not advised for the caller to retry the `-EAGAIN` return code as this will only make
-the problem(s) worse and cause your application to temporarily drop to the logger daemon priority,
-BATCH scheduling policy and background task cgroup. If you require a group of messages to be passed
-atomically, merge them into one message with embedded newlines to the maximum length
-`LOGGER_ENTRY_MAX_PAYLOAD`.
-
-Other return codes from writing operation can be returned. Since the library retries on `EINTR`,
-`-EINTR` should never be returned.
diff --git a/liblog/README.protocol.md b/liblog/README.protocol.md
deleted file mode 100644
index f247b28..0000000
--- a/liblog/README.protocol.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# liblog -> logd
-
-The data that liblog sends to logd is represented below.
-
- struct {
- android_log_header_t header;
- union {
- struct {
- char prio;
- char tag[...];
- char message[...];
- } string;
- struct {
- android_event_header_t event_header;
- android_event_*_t payload[...];
- } binary;
- };
- };
-
-where the embedded structs are defined as:
-
- struct android_log_header_t {
- uint8_t id;
- uint16_t tid;
- log_time realtime;
- };
-
- struct log_time {
- uint32_t tv_sec = 0;
- uint32_t tv_nsec = 0;
- }
-
- struct android_event_header_t {
- int32_t tag;
- };
-
- struct android_event_list_t {
- int8_t type; // EVENT_TYPE_LIST
- int8_t element_count;
- };
-
- struct android_event_float_t {
- int8_t type; // EVENT_TYPE_FLOAT
- float data;
- };
-
- struct android_event_int_t {
- int8_t type; // EVENT_TYPE_INT
- int32_t data;
- } android_event_int_t;
-
- struct android_event_long_t {
- int8_t type; // EVENT_TYPE_LONG
- int64_t data;
- };
-
- struct android_event_string_t {
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length;
- char data[];
- };
-
-The payload, excluding the header, has a max size of LOGGER_ENTRY_MAX_PAYLOAD.
-
-## header
-
-The header is added immediately before sending the log message to logd.
-
-## `string` payload
-
-The `string` part of the union is for normal buffers (main, system, radio, etc) and consists of a
-single character priority, followed by a variable length null terminated string for the tag, and
-finally a variable length null terminated string for the message.
-
-This payload is used for the `__android_log_buf_write()` family of functions.
-
-## `binary` payload
-
-The `binary` part of the union is for binary buffers (events, security, etc) and consists of an
-android_event_header_t struct followed by a variable number of android_event_*_t
-(android_event_list_t, android_event_int_t, etc) structs.
-
-If multiple android_event_*_t elements are present, then they must be in a list and the first
-element in payload must be an android_event_list_t.
-
-This payload is used for the `__android_log_bwrite()` family of functions. It is additionally used
-for `android_log_write_list()` and the related functions that manipulate event lists.
-
-# logd -> liblog
-
-logd sends a `logger_entry` struct to liblog followed by the payload. The payload is identical to
-the payloads defined above. The max size of the entire message from logd is LOGGER_ENTRY_MAX_LEN.
diff --git a/liblog/event.logtags b/liblog/event.logtags
deleted file mode 100644
index 0a3b650..0000000
--- a/liblog/event.logtags
+++ /dev/null
@@ -1,37 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-1006 liblog (dropped|1)
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
deleted file mode 100644
index 85556e8..0000000
--- a/liblog/event_tag_map.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-
-#include <functional>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-
-#include <log/event_tag_map.h>
-#include <private/android_logger.h>
-#include <utils/FastStrcmp.h>
-#include <utils/RWLock.h>
-
-#define OUT_TAG "EventTagMap"
-
-typedef std::pair<std::string_view, std::string_view> TagFmt;
-
-// Map
-struct EventTagMap {
-#define NUM_MAPS 2
- // memory-mapped source file; we get strings from here
- void* mapAddr[NUM_MAPS];
- size_t mapLen[NUM_MAPS];
-
- private:
- std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
- std::unordered_map<std::string_view, uint32_t> Tag2Idx;
- // protect unordered sets
- android::RWLock rwlock;
-
- public:
- EventTagMap() {
- memset(mapAddr, 0, sizeof(mapAddr));
- memset(mapLen, 0, sizeof(mapLen));
- }
-
- ~EventTagMap() {
- Idx2TagFmt.clear();
- Tag2Idx.clear();
- for (size_t which = 0; which < NUM_MAPS; ++which) {
- if (mapAddr[which]) {
- munmap(mapAddr[which], mapLen[which]);
- mapAddr[which] = 0;
- }
- }
- }
-
- bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
- const TagFmt* find(uint32_t tag) const;
- int find(std::string_view tag) const;
-};
-
-bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
- bool verbose) {
- bool ret = true;
- static const char errorFormat[] =
- OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
- ":%.*s:%.*s)\n";
- android::RWLock::AutoWLock writeLock(rwlock);
- {
- auto it = Idx2TagFmt.find(tag);
- if (it != Idx2TagFmt.end()) {
- if (verbose) {
- fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
- it->second.first.data(), (int)it->second.second.length(),
- it->second.second.data(), tag, (int)tagfmt.first.length(),
- tagfmt.first.data(), (int)tagfmt.second.length(),
- tagfmt.second.data());
- }
- ret = false;
- } else {
- Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
- }
- }
-
- {
- auto it = Tag2Idx.find(tagfmt.first);
- if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
- Tag2Idx.erase(it);
- it = Tag2Idx.end();
- }
- if (it == Tag2Idx.end()) {
- Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
- }
- }
-
- return ret;
-}
-
-const TagFmt* EventTagMap::find(uint32_t tag) const {
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- auto it = Idx2TagFmt.find(tag);
- if (it == Idx2TagFmt.end()) return NULL;
- return &(it->second);
-}
-
-int EventTagMap::find(std::string_view tag) const {
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- auto it = Tag2Idx.find(std::move(tag));
- if (it == Tag2Idx.end()) return -1;
- return it->second;
-}
-
-// The position after the end of a valid section of the tag string,
-// caller makes sure delimited appropriately.
-static const char* endOfTag(const char* cp) {
- while (*cp && (isalnum(*cp) || strchr("_.-@,", *cp))) ++cp;
- return cp;
-}
-
-// Scan one tag line.
-//
-// "pData" should be pointing to the first digit in the tag number. On
-// successful return, it will be pointing to the last character in the
-// tag line (i.e. the character before the start of the next line).
-//
-// Returns 0 on success, nonzero on failure.
-static int scanTagLine(EventTagMap* map, const char*& pData, int line_num) {
- char* ep;
- unsigned long val = strtoul(pData, &ep, 10);
- const char* cp = ep;
- if (cp == pData) {
- fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", line_num);
- errno = EINVAL;
- return -1;
- }
-
- uint32_t tagIndex = val;
- if (tagIndex != val) {
- fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", line_num);
- errno = ERANGE;
- return -1;
- }
-
- while ((*++cp != '\n') && isspace(*cp)) {
- }
-
- if (*cp == '\n') {
- fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", line_num);
- errno = EINVAL;
- return -1;
- }
-
- const char* tag = cp;
- cp = endOfTag(cp);
- size_t tagLen = cp - tag;
-
- if (!isspace(*cp)) {
- fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp, line_num);
- errno = EINVAL;
- return -1;
- }
-
- while (isspace(*cp) && (*cp != '\n')) ++cp;
- const char* fmt = NULL;
- size_t fmtLen = 0;
- if (*cp && (*cp != '#')) {
- fmt = cp;
- while (*cp && (*cp != '\n') && (*cp != '#')) ++cp;
- while ((cp > fmt) && isspace(*(cp - 1))) --cp;
- fmtLen = cp - fmt;
- }
-
- // KISS Only report identicals if they are global
- // Ideally we want to check if there are identicals
- // recorded for the same uid, but recording that
- // unused detail in our database is too burdensome.
- bool verbose = true;
- while (*cp && (*cp != '#') && (*cp != '\n')) ++cp;
- if (*cp == '#') {
- do {
- ++cp;
- } while (isspace(*cp) && (*cp != '\n'));
- verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
- }
-
- while (*cp && (*cp != '\n')) ++cp;
-#ifdef DEBUG
- fprintf(stderr, "%d: %p: %.*s\n", line_num, tag, (int)(cp - pData), pData);
-#endif
- pData = cp;
-
- if (map->emplaceUnique(
- tagIndex,
- TagFmt(std::make_pair(std::string_view(tag, tagLen), std::string_view(fmt, fmtLen))),
- verbose)) {
- return 0;
- }
- errno = EMLINK;
- return -1;
-}
-
-static const char* eventTagFiles[NUM_MAPS] = {
- EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
-};
-
-// Parse the tags out of the file.
-static int parseMapLines(EventTagMap* map, size_t which) {
- const char* cp = static_cast<char*>(map->mapAddr[which]);
- size_t len = map->mapLen[which];
- const char* endp = cp + len;
-
- // insist on EOL at EOF; simplifies parsing and null-termination
- if (!len || (*(endp - 1) != '\n')) {
-#ifdef DEBUG
- fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
- which, len);
-#endif
- if (which) { // do not propagate errors for other files
- return 0;
- }
- errno = EINVAL;
- return -1;
- }
-
- bool lineStart = true;
- int lineNum = 1;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = true;
- lineNum++;
- } else if (lineStart) {
- if (*cp == '#') {
- // comment; just scan to end
- lineStart = false;
- } else if (isdigit(*cp)) {
- // looks like a tag; scan it out
- if (scanTagLine(map, cp, lineNum) != 0) {
- if (!which || (errno != EMLINK)) {
- return -1;
- }
- }
- lineNum++; // we eat the '\n'
- // leave lineStart==true
- } else if (isspace(*cp)) {
- // looks like leading whitespace; keep scanning
- } else {
- fprintf(stderr,
- OUT_TAG
- ": unexpected chars (0x%02x) in tag number on line %d\n",
- *cp, lineNum);
- errno = EINVAL;
- return -1;
- }
- } else {
- // this is a blank or comment line
- }
- cp++;
- }
-
- return 0;
-}
-
-// Open the map file and allocate a structure to manage it.
-//
-// We create a private mapping because we want to terminate the log tag
-// strings with '\0'.
-EventTagMap* android_openEventTagMap(const char* fileName) {
- EventTagMap* newTagMap;
- off_t end[NUM_MAPS];
- int save_errno, fd[NUM_MAPS];
- size_t which;
-
- memset(fd, -1, sizeof(fd));
- memset(end, 0, sizeof(end));
-
- for (which = 0; which < NUM_MAPS; ++which) {
- const char* tagfile = fileName ? fileName : eventTagFiles[which];
-
- fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
- if (fd[which] < 0) {
- if (!which) {
- save_errno = errno;
- fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
- strerror(save_errno));
- goto fail_errno;
- }
- continue;
- }
- end[which] = lseek(fd[which], 0L, SEEK_END);
- save_errno = errno;
- (void)lseek(fd[which], 0L, SEEK_SET);
- if (!which && (end[0] < 0)) {
- fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
- strerror(save_errno));
- goto fail_close;
- }
- if (fileName) break; // Only allow one as specified
- }
-
- newTagMap = new EventTagMap;
- if (newTagMap == NULL) {
- save_errno = errno;
- goto fail_close;
- }
-
- for (which = 0; which < NUM_MAPS; ++which) {
- if (fd[which] >= 0) {
- newTagMap->mapAddr[which] =
- mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
- which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
- save_errno = errno;
- close(fd[which]); /* fd DONE */
- fd[which] = -1;
- if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
- (newTagMap->mapAddr[which] != NULL)) {
- newTagMap->mapLen[which] = end[which];
- } else if (!which) {
- const char* tagfile = fileName ? fileName : eventTagFiles[which];
-
- fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
- strerror(save_errno));
- goto fail_unmap;
- }
- }
- }
-
- for (which = 0; which < NUM_MAPS; ++which) {
- if (parseMapLines(newTagMap, which) != 0) {
- delete newTagMap;
- return NULL;
- }
- /* See 'fd DONE' comments above and below, no need to clean up here */
- }
-
- return newTagMap;
-
-fail_unmap:
- save_errno = EINVAL;
- delete newTagMap;
-fail_close:
- for (which = 0; which < NUM_MAPS; ++which) close(fd[which]); /* fd DONE */
-fail_errno:
- errno = save_errno;
- return NULL;
-}
-
-// Close the map.
-void android_closeEventTagMap(EventTagMap* map) {
- if (map) delete map;
-}
-
-// Look up an entry in the map.
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->first.length();
- return str->first.data();
-}
-
-// Look up an entry in the map.
-const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len, unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->second.length();
- return str->second.data();
-}
-
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
deleted file mode 100644
index 8a0ebf2..0000000
--- a/liblog/include/android/log.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2009 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
-
-/**
- * @addtogroup Logging
- * @{
- */
-
-/**
- * \file
- *
- * Support routines to send messages to the Android log buffer,
- * which can later be accessed through the `logcat` utility.
- *
- * Each log message must have
- * - a priority
- * - a log tag
- * - some text
- *
- * The tag normally corresponds to the component that emits the log message,
- * and should be reasonably small.
- *
- * Log message text may be truncated to less than an implementation-specific
- * limit (1023 bytes).
- *
- * Note that a newline character ("\n") will be appended automatically to your
- * log message, if not already there. It is not possible to send several
- * messages and have them appear on a single line in logcat.
- *
- * Please use logging in moderation:
- *
- * - Sending log messages eats CPU and slow down your application and the
- * system.
- *
- * - The circular log buffer is pretty small, so sending many messages
- * will hide other important log messages.
- *
- * - In release builds, only send log messages to account for exceptional
- * conditions.
- */
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/cdefs.h>
-
-#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
-#define __INTRODUCED_IN(x)
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Android log priority values, in increasing order of priority.
- */
-typedef enum android_LogPriority {
- /** For internal use only. */
- ANDROID_LOG_UNKNOWN = 0,
- /** The default priority, for internal use only. */
- ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
- /** Verbose logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_VERBOSE,
- /** Debug logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_DEBUG,
- /** Informational logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_INFO,
- /** Warning logging. For use with recoverable failures. */
- ANDROID_LOG_WARN,
- /** Error logging. For use with unrecoverable failures. */
- ANDROID_LOG_ERROR,
- /** Fatal logging. For use when aborting. */
- ANDROID_LOG_FATAL,
- /** For internal use only. */
- ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
-} android_LogPriority;
-
-/**
- * Writes the constant string `text` to the log, with priority `prio` and tag
- * `tag`.
- */
-int __android_log_write(int prio, const char* tag, const char* text);
-
-/**
- * Writes a formatted string to the log, with priority `prio` and tag `tag`.
- * The details of formatting are the same as for
- * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
- */
-int __android_log_print(int prio, const char* tag, const char* fmt, ...)
- __attribute__((__format__(printf, 3, 4)));
-
-/**
- * Equivalent to `__android_log_print`, but taking a `va_list`.
- * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
- */
-int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
- __attribute__((__format__(printf, 3, 0)));
-
-/**
- * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
- * stderr, before calling
- * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
- *
- * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
- * `Assertion failed: %s` is used with `cond` as the string argument.
- * If both `fmt` and `cond` are null, a default string is provided.
- *
- * Most callers should use
- * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
- * `<assert.h>` instead, or the `__assert` and `__assert2` functions
- * provided by bionic if more control is needed. They support automatically
- * including the source filename and line number more conveniently than this
- * function.
- */
-void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...)
- __attribute__((__noreturn__)) __attribute__((__format__(printf, 3, 4)));
-
-/**
- * Identifies a specific log buffer for __android_log_buf_write()
- * and __android_log_buf_print().
- */
-typedef enum log_id {
- LOG_ID_MIN = 0,
-
- /** The main log buffer. This is the only log buffer available to apps. */
- LOG_ID_MAIN = 0,
- /** The radio log buffer. */
- LOG_ID_RADIO = 1,
- /** The event log buffer. */
- LOG_ID_EVENTS = 2,
- /** The system log buffer. */
- LOG_ID_SYSTEM = 3,
- /** The crash log buffer. */
- LOG_ID_CRASH = 4,
- /** The statistics log buffer. */
- LOG_ID_STATS = 5,
- /** The security log buffer. */
- LOG_ID_SECURITY = 6,
- /** The kernel log buffer. */
- LOG_ID_KERNEL = 7,
-
- LOG_ID_MAX,
-
- /** Let the logging function choose the best log target. */
- LOG_ID_DEFAULT = 0x7FFFFFFF
-} log_id_t;
-
-/**
- * Writes the constant string `text` to the log buffer `id`,
- * with priority `prio` and tag `tag`.
- *
- * Apps should use __android_log_write() instead.
- */
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
-
-/**
- * Writes a formatted string to log buffer `id`,
- * with priority `prio` and tag `tag`.
- * The details of formatting are the same as for
- * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
- *
- * Apps should use __android_log_print() instead.
- */
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
- __attribute__((__format__(printf, 4, 5)));
-
-/**
- * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
- * and sending log messages to user defined loggers specified in __android_log_set_logger().
- */
-struct __android_log_message {
- /** Must be set to sizeof(__android_log_message) and is used for versioning. */
- size_t struct_size;
-
- /** {@link log_id_t} values. */
- int32_t buffer_id;
-
- /** {@link android_LogPriority} values. */
- int32_t priority;
-
- /** The tag for the log message. */
- const char* tag;
-
- /** Optional file name, may be set to nullptr. */
- const char* file;
-
- /** Optional line number, ignore if file is nullptr. */
- uint32_t line;
-
- /** The log message itself. */
- const char* message;
-};
-
-/**
- * Prototype for the 'logger' function that is called for every log message.
- */
-typedef void (*__android_logger_function)(const struct __android_log_message* log_message);
-/**
- * Prototype for the 'abort' function that is called when liblog will abort due to
- * __android_log_assert() failures.
- */
-typedef void (*__android_aborter_function)(const char* abort_message);
-
-#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
-/**
- * Writes the log message specified by log_message. log_message includes additional file name and
- * line number information that a logger may use. log_message is versioned for backwards
- * compatibility.
- * This assumes that loggability has already been checked through __android_log_is_loggable().
- * Higher level logging libraries, such as libbase, first check loggability, then format their
- * buffers, then pass the message to liblog via this function, and therefore we do not want to
- * duplicate the loggability check here.
- *
- * @param log_message the log message itself, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_write_log_message(struct __android_log_message* log_message) __INTRODUCED_IN(30);
-
-/**
- * Sets a user defined logger function. All log messages sent to liblog will be set to the
- * function pointer specified by logger for processing. It is not expected that log messages are
- * already terminated with a new line. This function should add new lines if required for line
- * separation.
- *
- * @param logger the new function that will handle log messages.
- *
- * Available since API level 30.
- */
-void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
-
-/**
- * Writes the log message to logd. This is an __android_logger_function and can be provided to
- * __android_log_set_logger(). It is the default logger when running liblog on a device.
- *
- * @param log_message the log message to write, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_logd_logger(const struct __android_log_message* log_message) __INTRODUCED_IN(30);
-
-/**
- * Writes the log message to stderr. This is an __android_logger_function and can be provided to
- * __android_log_set_logger(). It is the default logger when running liblog on host.
- *
- * @param log_message the log message to write, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_stderr_logger(const struct __android_log_message* log_message)
- __INTRODUCED_IN(30);
-
-/**
- * Sets a user defined aborter function that is called for __android_log_assert() failures. This
- * user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
- * required to.
- *
- * @param aborter the new aborter function, see __android_aborter_function.
- *
- * Available since API level 30.
- */
-void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
-
-/**
- * Calls the stored aborter function. This allows for other logging libraries to use the same
- * aborter function by calling this function in liblog.
- *
- * @param abort_message an additional message supplied when aborting, for example this is used to
- * call android_set_abort_message() in __android_log_default_aborter().
- *
- * Available since API level 30.
- */
-void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
-
-/**
- * Sets android_set_abort_message() on device then aborts(). This is the default aborter.
- *
- * @param abort_message an additional message supplied when aborting. This functions calls
- * android_set_abort_message() with its contents.
- *
- * Available since API level 30.
- */
-void __android_log_default_aborter(const char* abort_message) __attribute__((noreturn))
-__INTRODUCED_IN(30);
-
-/**
- * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
- * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
- * be printed. A non-zero result indicates yes, zero indicates false.
- *
- * If both a priority for a tag and a minimum priority are set by
- * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
- * minimum priority needed to log. If only one is set, then that value is used to determine the
- * minimum priority needed. If none are set, then default_priority is used.
- *
- * @param prio the priority to test, takes android_LogPriority values.
- * @param tag the tag to test.
- * @param default_prio the default priority to use if no properties or minimum priority are set.
- * @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
- *
- * Available since API level 30.
- */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
-
-/**
- * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
- * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
- * be printed. A non-zero result indicates yes, zero indicates false.
- *
- * If both a priority for a tag and a minimum priority are set by
- * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
- * minimum priority needed to log. If only one is set, then that value is used to determine the
- * minimum priority needed. If none are set, then default_priority is used.
- *
- * @param prio the priority to test, takes android_LogPriority values.
- * @param tag the tag to test.
- * @param len the length of the tag.
- * @param default_prio the default priority to use if no properties or minimum priority are set.
- * @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
- *
- * Available since API level 30.
- */
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
- __INTRODUCED_IN(30);
-
-/**
- * Sets the minimum priority that will be logged for this process.
- *
- * @param priority the new minimum priority to set, takes android_LogPriority values.
- * @return the previous set minimum priority as android_LogPriority values, or
- * ANDROID_LOG_DEFAULT if none was set.
- *
- * Available since API level 30.
- */
-int32_t __android_log_set_minimum_priority(int32_t priority) __INTRODUCED_IN(30);
-
-/**
- * Gets the minimum priority that will be logged for this process. If none has been set by a
- * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
- *
- * @return the current minimum priority as android_LogPriority values, or
- * ANDROID_LOG_DEFAULT if none is set.
- *
- * Available since API level 30.
- */
-int32_t __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
-
-/**
- * Sets the default tag if no tag is provided when writing a log message. Defaults to
- * getprogname(). This truncates tag to the maximum log message size, though appropriate tags
- * should be much smaller.
- *
- * @param tag the new log tag.
- *
- * Available since API level 30.
- */
-void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @} */
diff --git a/liblog/include/log/event_tag_map.h b/liblog/include/log/event_tag_map.h
deleted file mode 100644
index de49fbf..0000000
--- a/liblog/include/log/event_tag_map.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007 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 <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
-
-struct EventTagMap;
-typedef struct EventTagMap EventTagMap;
-
-/*
- * Open the specified file as an event log tag map.
- *
- * Returns NULL on failure.
- */
-EventTagMap* android_openEventTagMap(const char* fileName);
-
-/*
- * Close the map.
- */
-void android_closeEventTagMap(EventTagMap* map);
-
-/*
- * Look up a tag by index. Returns the tag string & string length, or NULL if
- * not found. Returned string is not guaranteed to be nul terminated.
- */
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len,
- unsigned int tag);
-
-/*
- * Look up a format by index. Returns the format string & string length,
- * or NULL if not found. Returned string is not guaranteed to be nul terminated.
- */
-const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len,
- unsigned int tag);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
deleted file mode 100644
index d7e9b7d..0000000
--- a/liblog/include/log/log.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2005-2014 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
-
-/* Too many in the ecosystem assume these are included */
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-#include <stdint.h> /* uint16_t, int32_t */
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <log/log_id.h>
-#include <log/log_main.h>
-#include <log/log_radio.h>
-#include <log/log_safetynet.h>
-#include <log/log_system.h>
-#include <log/log_time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * LOG_TAG is the local tag used for the following simplified
- * logging macros. You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/*
- * The maximum size of the log entry payload that can be
- * written to the logger. An attempt to write more than
- * this amount will result in a truncated log entry.
- */
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068
-
-/*
- * Event logging.
- */
-
-/*
- * The following should not be used directly.
- */
-
-int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
-int __android_log_btwrite(int32_t tag, char type, const void* payload,
- size_t len);
-int __android_log_bswrite(int32_t tag, const char* payload);
-
-int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len);
-
-#define android_bWriteLog(tag, payload, len) \
- __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
- __android_log_btwrite(tag, type, payload, len)
-
-/*
- * Event log entry types.
- */
-typedef enum {
- /* Special markers for android_log_list_element type */
- EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
- EVENT_TYPE_UNKNOWN = '?', /* protocol error */
-
- /* must match with declaration in java/android/android/util/EventLog.java */
- EVENT_TYPE_INT = 0, /* int32_t */
- EVENT_TYPE_LONG = 1, /* int64_t */
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
-} AndroidEventLogType;
-
-#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) \
- { \
- int intBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) \
- { \
- long long longBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_FLOAT
-#define LOG_EVENT_FLOAT(_tag, _value) \
- { \
- float floatBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
- sizeof(floatBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value) \
- (void)__android_log_bswrite(_tag, _value);
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Release any logger resources (a new log write will immediately re-acquire)
- *
- * This is specifically meant to be used by Zygote to close open file descriptors after fork()
- * and before specialization. O_CLOEXEC is used on file descriptors, so they will be closed upon
- * exec() in normal use cases.
- *
- * Note that this is not safe to call from a multi-threaded program.
- */
-void __android_log_close(void);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
deleted file mode 100644
index deadf20..0000000
--- a/liblog/include/log/log_event_list.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2005-2016 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 <errno.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <log/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-typedef struct android_log_context_internal* android_log_context;
-
-/*
- * Elements returned when reading a list of events.
- */
-typedef struct {
- AndroidEventLogType type;
- uint16_t complete;
- uint16_t len;
- union {
- int32_t int32;
- int64_t int64;
- char* string;
- float float32;
- } data;
-} android_log_list_element;
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx, const char* value,
- size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char* msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Reset writer context */
-int android_log_reset(android_log_context ctx);
-
-/* Reset reader context */
-int android_log_parser_reset(android_log_context ctx,
- const char* msg, size_t len);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-/* android_log_list C++ helpers */
-extern "C++" {
-class android_log_event_list {
- private:
- android_log_context ctx;
- int ret;
-
- android_log_event_list(const android_log_event_list&) = delete;
- void operator=(const android_log_event_list&) = delete;
-
- public:
- explicit android_log_event_list(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- ~android_log_event_list() {
- android_log_destroy(&ctx);
- }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) ret = retval;
- return retval;
- }
-
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const {
- return ctx;
- }
-
- /* return errors or transmit status */
- int status() const {
- return ret;
- }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- android_log_event_list& operator<<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(bool value) {
- int retval = android_log_write_int32(ctx, value ? 1 : 0);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- int write(log_id_t id = LOG_ID_EVENTS) {
- /* facilitate -EBUSY retry */
- if ((ret == -EBUSY) || (ret > 0)) ret = 0;
- int retval = android_log_write_list(ctx, id);
- /* existing errors trump transmission errors */
- if (!ret) ret = retval;
- return ret;
- }
-
- int operator<<(log_id_t id) {
- write(id);
- android_log_destroy(&ctx);
- return ret;
- }
-
- /*
- * Append<Type> methods removes any integer promotion
- * confusion, and adds access to string with length.
- * Append methods are also added for all types for
- * convenience.
- */
-
- bool AppendInt(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendLong(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
-
- bool Append(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
-
- bool AppendFloat(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- template <typename Tvalue>
- bool Append(Tvalue value) {
- *this << value;
- return ret >= 0;
- }
-
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-};
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
deleted file mode 100644
index 8e4faeb..0000000
--- a/liblog/include/log/log_id.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <android/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * log_id_t helpers
- */
-log_id_t android_name_to_log_id(const char* logName);
-const char* android_log_id_to_name(log_id_t log_id);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
deleted file mode 100644
index 1bd1c8a..0000000
--- a/liblog/include/log/log_main.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <stdbool.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-
-__BEGIN_DECLS
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
- * work around issues with debug-only syntax errors in assertions
- * that are missing format strings. See commit
- * 19299904343daf191267564fe32e6cd5c165cd42
- */
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#endif
-
-/*
- * Use __VA_ARGS__ if running a static analyzer,
- * to avoid warnings of unused variables in __VA_ARGS__.
- * Use constexpr function in C++ mode, so these macros can be used
- * in other constexpr functions without warning.
- */
-#ifdef __clang_analyzer__
-#ifdef __cplusplus
-extern "C++" {
-template <typename... Ts>
-constexpr int __fake_use_va_args(Ts...) {
- return 0;
-}
-}
-#else
-extern int __fake_use_va_args(int, ...);
-#endif /* __cplusplus */
-#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
-#else
-#define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif /* __clang_analyzer__ */
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-#define android_writeLog(prio, tag, text) __android_log_write(prio, tag, text)
-
-#define android_printLog(prio, tag, ...) \
- __android_log_print(prio, tag, __VA_ARGS__)
-
-#define android_vprintLog(prio, cond, tag, ...) \
- __android_log_vprint(prio, tag, __VA_ARGS__)
-
-/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
- android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
- */
-
-/* Returns 2nd arg. Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...) second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...) , ##__VA_ARGS__
-
-#define android_printAssert(cond, tag, ...) \
- __android_log_assert(cond, tag, \
- __android_second(0, ##__VA_ARGS__, NULL) \
- __android_rest(__VA_ARGS__))
-
-/*
- * Log a fatal error. If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds. Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
- ((__predict_false(cond)) ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), \
- ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__))) \
- : ((void)0))
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
- (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds. Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * C/C++ logging functions. See the logging documentation for API details.
- *
- * We'd like these to be available from C code (in case we import some from
- * somewhere), so this has a C interface.
- *
- * The output will be correct when the log file is shared between multiple
- * threads and/or multiple processes so long as the operating system
- * supports O_APPEND. These calls have mutex-protected data structures
- * and so are NOT reentrant. Do not use LOG in a signal handler.
- */
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Simplified macro to send a verbose log message using the current LOG_TAG.
- */
-#ifndef ALOGV
-#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define ALOGV(...) \
- do { \
- __FAKE_USE_VA_ARGS(__VA_ARGS__); \
- if (false) { \
- __ALOGV(__VA_ARGS__); \
- } \
- } while (false)
-#else
-#define ALOGV(...) __ALOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef ALOGV_IF
-#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#else
-#define ALOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug log message using the current LOG_TAG.
- */
-#ifndef ALOGD
-#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send an info log message using the current LOG_TAG.
- */
-#ifndef ALOGI
-#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send a warning log message using the current LOG_TAG.
- */
-#ifndef ALOGW
-#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send an error log message using the current LOG_TAG.
- */
-#ifndef ALOGE
-#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * verbose priority.
- */
-#ifndef IF_ALOGV
-#if LOG_NDEBUG
-#define IF_ALOGV() if (false)
-#else
-#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
-#endif
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * debug priority.
- */
-#ifndef IF_ALOGD
-#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * info priority.
- */
-#ifndef IF_ALOGI
-#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * warn priority.
- */
-#ifndef IF_ALOGW
-#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * error priority.
- */
-#ifndef IF_ALOGE
-#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Basic log message macro.
- *
- * Example:
- * ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
- *
- * The second argument may be NULL or "" to indicate the "global" tag.
- */
-#ifndef ALOG
-#define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Conditional given a desired logging priority and tag.
- */
-#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) if (android_testLog(ANDROID_##priority, tag))
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
- * android_testLog will remain constant in its purpose as a wrapper
- * for Android logging filter policy, and can be subject to
- * change. It can be reused by the developers that override
- * IF_ALOG as a convenient means to reimplement their policy
- * over Android.
- */
-
-/*
- * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
- * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
- * any other value.
- */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
-
-#if LOG_NDEBUG /* Production */
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
- ANDROID_LOG_DEBUG) != 0)
-#else
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
- ANDROID_LOG_VERBOSE) != 0)
-#endif
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-__END_DECLS
diff --git a/liblog/include/log/log_properties.h b/liblog/include/log/log_properties.h
deleted file mode 100644
index 2a0230f..0000000
--- a/liblog/include/log/log_properties.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Returns `1` if the device is debuggable or `0` if not. */
-int __android_log_is_debuggable();
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_radio.h b/liblog/include/log/log_radio.h
deleted file mode 100644
index f5525c1..0000000
--- a/liblog/include/log/log_radio.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <android/log.h>
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-/*
- * Simplified macro to send a verbose radio log message using current LOG_TAG.
- */
-#ifndef RLOGV
-#define __RLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
-#if LOG_NDEBUG
-#define RLOGV(...) \
- do { \
- if (0) { \
- __RLOGV(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define RLOGV(...) __RLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...) ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an info radio log message using current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an error radio log message using current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
deleted file mode 100644
index 1736934..0000000
--- a/liblog/include/log/log_read.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <log/log_time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
-
-/*
- * Native log reading interface section. See logcat for sample code.
- *
- * The preferred API is an exec of logcat. Likely uses of this interface
- * are if native code suffers from exec or filtration being too costly,
- * access to raw information, or parsing is an issue.
- */
-
-struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry) */
- int32_t pid; /* generating process's pid */
- uint32_t tid; /* generating process's tid */
- uint32_t sec; /* seconds since Epoch */
- uint32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload, bottom 4 bits currently */
- uint32_t uid; /* generating process's uid */
-};
-
-/*
- * The maximum size of a log entry which can be read.
- * An attempt to read less than this amount may result
- * in read() returning EINVAL.
- */
-#define LOGGER_ENTRY_MAX_LEN (5 * 1024)
-
-struct log_msg {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry entry;
- } __attribute__((aligned(4)));
-#ifdef __cplusplus
- uint64_t nsec() const {
- return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
- }
- log_id_t id() {
- return static_cast<log_id_t>(entry.lid);
- }
- char* msg() {
- unsigned short hdr_size = entry.hdr_size;
- if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
- return nullptr;
- }
- return reinterpret_cast<char*>(buf) + hdr_size;
- }
- unsigned int len() { return entry.hdr_size + entry.len; }
-#endif
-};
-
-struct logger;
-
-log_id_t android_logger_get_id(struct logger* logger);
-
-/* Clears the given log buffer. */
-int android_logger_clear(struct logger* logger);
-/* Return the allotted size for the given log buffer. */
-long android_logger_get_log_size(struct logger* logger);
-/* Set the allotted size for the given log buffer. */
-int android_logger_set_log_size(struct logger* logger, unsigned long size);
-/* Return the actual, uncompressed size that can be read from the given log buffer. */
-long android_logger_get_log_readable_size(struct logger* logger);
-/* Return the actual, compressed size that the given log buffer is consuming. */
-long android_logger_get_log_consumed_size(struct logger* logger);
-/* Deprecated. Always returns '4' regardless of input. */
-int android_logger_get_log_version(struct logger* logger);
-
-struct logger_list;
-
-ssize_t android_logger_get_statistics(struct logger_list* logger_list,
- char* buf, size_t len);
-ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
- char* buf, size_t len);
-int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len);
-
-/* The below values are used for the `mode` argument of the below functions. */
-/* Note that 0x00000003 were previously used and should be considered reserved. */
-#define ANDROID_LOG_NONBLOCK 0x00000800
-#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_PSTORE 0x80000000
-
-struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
- pid_t pid);
-struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
- pid_t pid);
-void android_logger_list_free(struct logger_list* logger_list);
-/* In the purest sense, the following two are orthogonal interfaces */
-int android_logger_list_read(struct logger_list* logger_list,
- struct log_msg* log_msg);
-
-/* Multiple log_id_t opens */
-struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
-/* Single log_id_t open */
-struct logger_list* android_logger_list_open(log_id_t id, int mode,
- unsigned int tail, pid_t pid);
-#define android_logger_list_close android_logger_list_free
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_safetynet.h b/liblog/include/log/log_safetynet.h
deleted file mode 100644
index b2604b5..0000000
--- a/liblog/include/log/log_safetynet.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define android_errorWriteLog(tag, subTag) \
- __android_log_error_write(tag, subTag, -1, NULL, 0)
-
-#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
- __android_log_error_write(tag, subTag, uid, data, dataLen)
-
-int __android_log_error_write(int tag, const char* subTag, int32_t uid,
- const char* data, uint32_t dataLen);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_system.h b/liblog/include/log/log_system.h
deleted file mode 100644
index 6f40515..0000000
--- a/liblog/include/log/log_system.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <android/log.h>
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-/*
- * Simplified macro to send a verbose system log message using current LOG_TAG.
- */
-#ifndef SLOGV
-#define __SLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
-#if LOG_NDEBUG
-#define SLOGV(...) \
- do { \
- if (0) { \
- __SLOGV(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define SLOGV(...) __SLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef SLOGV_IF
-#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...) ((void)0)
-#else
-#define SLOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug system log message using current LOG_TAG.
- */
-#ifndef SLOGD
-#define SLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an info system log message using current LOG_TAG.
- */
-#ifndef SLOGI
-#define SLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send a warning system log message using current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an error system log message using current LOG_TAG.
- */
-#ifndef SLOGE
-#define SLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h
deleted file mode 100644
index f50764d..0000000
--- a/liblog/include/log/log_time.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 <stdint.h>
-#include <time.h>
-
-/* struct log_time is a wire-format variant of struct timespec */
-#define NS_PER_SEC 1000000000ULL
-#define US_PER_SEC 1000000ULL
-#define MS_PER_SEC 1000ULL
-
-#define LOG_TIME_SEC(t) ((t)->tv_sec)
-/* next power of two after NS_PER_SEC */
-#define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
-
-#ifdef __cplusplus
-
-extern "C" {
-
-struct log_time {
- public:
- uint32_t tv_sec = 0; /* good to Feb 5 2106 */
- uint32_t tv_nsec = 0;
-
- static constexpr timespec EPOCH = {0, 0};
-
- log_time() {}
- explicit log_time(const timespec& T)
- : tv_sec(static_cast<uint32_t>(T.tv_sec)), tv_nsec(static_cast<uint32_t>(T.tv_nsec)) {}
- explicit log_time(uint32_t sec, uint32_t nsec = 0)
- : tv_sec(sec), tv_nsec(nsec) {
- }
-#ifdef __linux__
- explicit log_time(clockid_t id) {
- timespec T;
- clock_gettime(id, &T);
- tv_sec = static_cast<uint32_t>(T.tv_sec);
- tv_nsec = static_cast<uint32_t>(T.tv_nsec);
- }
-#endif
- /* timespec */
- bool operator==(const timespec& T) const {
- return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
- }
- bool operator!=(const timespec& T) const {
- return !(*this == T);
- }
- bool operator<(const timespec& T) const {
- return (tv_sec < static_cast<uint32_t>(T.tv_sec)) ||
- ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator>=(const timespec& T) const {
- return !(*this < T);
- }
- bool operator>(const timespec& T) const {
- return (tv_sec > static_cast<uint32_t>(T.tv_sec)) ||
- ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator<=(const timespec& T) const {
- return !(*this > T);
- }
-
- /* log_time */
- bool operator==(const log_time& T) const {
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
- }
- bool operator!=(const log_time& T) const {
- return !(*this == T);
- }
- bool operator<(const log_time& T) const {
- return (tv_sec < T.tv_sec) ||
- ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
- }
- bool operator>=(const log_time& T) const {
- return !(*this < T);
- }
- bool operator>(const log_time& T) const {
- return (tv_sec > T.tv_sec) ||
- ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
- }
- bool operator<=(const log_time& T) const {
- return !(*this > T);
- }
-
- log_time operator-=(const log_time& T) {
- // No concept of negative time, clamp to EPOCH
- if (*this <= T) {
- return *this = log_time(EPOCH);
- }
-
- if (this->tv_nsec < T.tv_nsec) {
- --this->tv_sec;
- this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
- } else {
- this->tv_nsec -= T.tv_nsec;
- }
- this->tv_sec -= T.tv_sec;
-
- return *this;
- }
- log_time operator-(const log_time& T) const {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+=(const log_time& T) {
- this->tv_nsec += T.tv_nsec;
- if (this->tv_nsec >= NS_PER_SEC) {
- this->tv_nsec -= NS_PER_SEC;
- ++this->tv_sec;
- }
- this->tv_sec += T.tv_sec;
-
- return *this;
- }
- log_time operator+(const log_time& T) const {
- log_time local(*this);
- return local += T;
- }
-
- uint64_t nsec() const {
- return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
- }
- uint64_t usec() const {
- return static_cast<uint64_t>(tv_sec) * US_PER_SEC +
- tv_nsec / (NS_PER_SEC / US_PER_SEC);
- }
- uint64_t msec() const {
- return static_cast<uint64_t>(tv_sec) * MS_PER_SEC +
- tv_nsec / (NS_PER_SEC / MS_PER_SEC);
- }
-
- /* Add %#q for the fraction of a second to the standard library functions */
- char* strptime(const char* s, const char* format);
-} __attribute__((__packed__));
-}
-
-#else /* __cplusplus */
-
-typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif /* __cplusplus */
diff --git a/liblog/include/log/logprint.h b/liblog/include/log/logprint.h
deleted file mode 100644
index 7dfd914..0000000
--- a/liblog/include/log/logprint.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2006 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 <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <log/event_tag_map.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- /* Verbs */
- FORMAT_OFF = 0,
- FORMAT_BRIEF,
- FORMAT_PROCESS,
- FORMAT_TAG,
- FORMAT_THREAD,
- FORMAT_RAW,
- FORMAT_TIME,
- FORMAT_THREADTIME,
- FORMAT_LONG,
- /* Adverbs. The following are modifiers to above format verbs */
- FORMAT_MODIFIER_COLOR, /* converts priority to color */
- FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
- FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
- FORMAT_MODIFIER_YEAR, /* Adds year to date */
- FORMAT_MODIFIER_ZONE, /* Adds zone to date, + UTC */
- FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
- FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
- FORMAT_MODIFIER_UID, /* Adds uid */
- FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
- /* private, undocumented */
- FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
-} AndroidLogPrintFormat;
-
-typedef struct AndroidLogFormat_t AndroidLogFormat;
-
-typedef struct AndroidLogEntry_t {
- time_t tv_sec;
- long tv_nsec;
- android_LogPriority priority;
- int32_t uid;
- int32_t pid;
- int32_t tid;
- const char* tag;
- size_t tagLen;
- size_t messageLen;
- const char* message;
-} AndroidLogEntry;
-
-AndroidLogFormat* android_log_format_new();
-
-void android_log_format_free(AndroidLogFormat* p_format);
-
-/* currently returns 0 if format is a modifier, 1 if not */
-int android_log_setPrintFormat(AndroidLogFormat* p_format,
- AndroidLogPrintFormat format);
-
-/**
- * Returns FORMAT_OFF on invalid string
- */
-AndroidLogPrintFormat android_log_formatFromString(const char* s);
-
-/**
- * filterExpression: a single filter expression
- * eg "AT:d"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-
-int android_log_addFilterRule(AndroidLogFormat* p_format,
- const char* filterExpression);
-
-/**
- * filterString: a whitespace-separated set of filter expressions
- * eg "AT:d *:i"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-
-int android_log_addFilterString(AndroidLogFormat* p_format,
- const char* filterString);
-
-/**
- * returns 1 if this log line should be printed based on its priority
- * and tag, and 0 if it should not
- */
-int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri);
-
-/**
- * Splits a wire-format buffer into an AndroidLogEntry
- * entry allocated by caller. Pointers will point directly into buf
- *
- * Returns 0 on success and -1 on invalid wire format (entry will be
- * in unspecified state)
- */
-int android_log_processLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry);
-
-/**
- * Like android_log_processLogBuffer, but for binary logs.
- *
- * If "map" is non-NULL, it will be used to convert the log tag number
- * into a string.
- */
-int android_log_processBinaryLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry,
- const EventTagMap* map, char* messageBuf,
- int messageBufLen);
-
-/**
- * Formats a log message into a buffer
- *
- * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
- * If return value != defaultBuffer, caller must call free()
- * Returns NULL on malloc error
- */
-
-char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
- size_t defaultBufferSize,
- const AndroidLogEntry* p_line,
- size_t* p_outLength);
-
-/**
- * Either print or do not print log line, based on filter
- *
- * Assumes single threaded execution
- *
- */
-int android_log_printLogLine(AndroidLogFormat* p_format, int fd,
- const AndroidLogEntry* entry);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
deleted file mode 100644
index 166f387..0000000
--- a/liblog/include/private/android_logger.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-/* This file is used to define the internal protocol for the Android Logger */
-
-#pragma once
-
-/* Android private interfaces */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#define LOGGER_MAGIC 'l'
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-/* Header Structure to pstore */
-typedef struct __attribute__((__packed__)) {
- uint8_t magic;
- uint16_t len;
- uint16_t uid;
- uint16_t pid;
-} android_pmsg_log_header_t;
-
-/* Header Structure to logd, and second header for pstore */
-typedef struct __attribute__((__packed__)) {
- uint8_t id;
- uint16_t tid;
- log_time realtime;
-} android_log_header_t;
-
-/* Event Header Structure to logd */
-typedef struct __attribute__((__packed__)) {
- int32_t tag; // Little Endian Order
-} android_event_header_t;
-
-// Event payload EVENT_TYPE_LIST
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_LIST
- int8_t element_count;
-} android_event_list_t;
-
-// Event payload EVENT_TYPE_FLOAT
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_FLOAT
- float data;
-} android_event_float_t;
-
-/* Event payload EVENT_TYPE_INT */
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_INT
- int32_t data; // Little Endian Order
-} android_event_int_t;
-
-/* Event with single EVENT_TYPE_INT */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_int_t payload;
-} android_log_event_int_t;
-
-/* Event payload EVENT_TYPE_LONG */
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_LONG
- int64_t data; // Little Endian Order
-} android_event_long_t;
-
-/* Event with single EVENT_TYPE_LONG */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_long_t payload;
-} android_log_event_long_t;
-
-/*
- * Event payload EVENT_TYPE_STRING
- *
- * Danger: do not embed this structure into another structure.
- * This structure uses a flexible array member, and when
- * compiled using g++, __builtin_object_size(data, 1) returns
- * a bad value. This is possibly a g++ bug, or a bug due to
- * the fact that flexible array members are not supported
- * in C++.
- * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
- */
-
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
-} android_event_string_t;
-
-/* Event with single EVENT_TYPE_STRING */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
-} android_log_event_string_t;
-
-#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
-#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
-
-ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio,
- const char* filename, const char* buf,
- size_t len);
-
-#define LOG_ID_ANY ((log_id_t)-1)
-#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
-
-/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
-typedef ssize_t (*__android_log_pmsg_file_read_fn)(log_id_t logId, char prio,
- const char* filename,
- const char* buf, size_t len,
- void* arg);
-
-ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio,
- const char* prefix,
- __android_log_pmsg_file_read_fn fn,
- void* arg);
-
-int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
-int __android_log_security_bswrite(int32_t tag, const char* payload);
-int __android_log_security(); /* Device Owner is present */
-
-/* Retrieve the composed event buffer */
-int android_log_write_list_buffer(android_log_context ctx, const char** msg);
-
-#if defined(__cplusplus)
-}
-#endif
diff --git a/liblog/include_vndk/android b/liblog/include_vndk/android
deleted file mode 120000
index a3c0320..0000000
--- a/liblog/include_vndk/android
+++ /dev/null
@@ -1 +0,0 @@
-../include/android
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log.h b/liblog/include_vndk/log/log.h
deleted file mode 100644
index fee18c6..0000000
--- a/liblog/include_vndk/log/log.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*Special log.h file for VNDK linking modules*/
-
-#pragma once
-
-/* Historically vendors have depended on these headers being included. */
-#include <fcntl.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <log/log_id.h>
-#include <log/log_main.h>
-#include <log/log_radio.h>
-#include <log/log_read.h>
-#include <log/log_safetynet.h>
-#include <log/log_system.h>
-#include <log/log_time.h>
-
-/*
- * LOG_TAG is the local tag used for the following simplified
- * logging macros. You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
diff --git a/liblog/include_vndk/log/log_event_list.h b/liblog/include_vndk/log/log_event_list.h
deleted file mode 100644
index 1f3dd37..0000000
--- a/liblog/include_vndk/log/log_event_list.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2005-2016 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.
- */
-
-/* Special log_event_list.h file for VNDK linking modules */
-
-#ifndef _LIBS_LOG_EVENT_LIST_H
-#define _LIBS_LOG_EVENT_LIST_H
-
-#include <stdint.h>
-
-#include <log/log_id.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-#ifndef __android_log_context_defined
-#define __android_log_context_defined
-typedef struct android_log_context_internal* android_log_context;
-#endif
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx, const char* value,
- size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/* Reset writer context */
-int android_log_reset(android_log_context ctx);
-
-/* Reset reader context */
-int android_log_parser_reset(android_log_context ctx,
- const char* msg, size_t len);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/liblog/include_vndk/log/log_id.h b/liblog/include_vndk/log/log_id.h
deleted file mode 120000
index dce92b9..0000000
--- a/liblog/include_vndk/log/log_id.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_id.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_main.h b/liblog/include_vndk/log/log_main.h
deleted file mode 120000
index f2ec018..0000000
--- a/liblog/include_vndk/log/log_main.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_main.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_properties.h b/liblog/include_vndk/log/log_properties.h
deleted file mode 120000
index bbec426..0000000
--- a/liblog/include_vndk/log/log_properties.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_properties.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_radio.h b/liblog/include_vndk/log/log_radio.h
deleted file mode 120000
index 1e12b32..0000000
--- a/liblog/include_vndk/log/log_radio.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_radio.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_read.h b/liblog/include_vndk/log/log_read.h
deleted file mode 120000
index 01de8b9..0000000
--- a/liblog/include_vndk/log/log_read.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_read.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_safetynet.h b/liblog/include_vndk/log/log_safetynet.h
deleted file mode 120000
index a4614e7..0000000
--- a/liblog/include_vndk/log/log_safetynet.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_safetynet.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_system.h b/liblog/include_vndk/log/log_system.h
deleted file mode 120000
index d0d3904..0000000
--- a/liblog/include_vndk/log/log_system.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_system.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_time.h b/liblog/include_vndk/log/log_time.h
deleted file mode 100644
index 5a09959..0000000
--- a/liblog/include_vndk/log/log_time.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#ifndef _LIBS_LOG_LOG_TIME_H
-#define _LIBS_LOG_LOG_TIME_H
-
-#include <stdint.h>
-
-/* struct log_time is a wire-format variant of struct timespec */
-#ifndef NS_PER_SEC
-#define NS_PER_SEC 1000000000ULL
-#endif
-#ifndef US_PER_SEC
-#define US_PER_SEC 1000000ULL
-#endif
-#ifndef MS_PER_SEC
-#define MS_PER_SEC 1000ULL
-#endif
-
-#ifndef __struct_log_time_defined
-#define __struct_log_time_defined
-
-#define LOG_TIME_SEC(t) ((t)->tv_sec)
-/* next power of two after NS_PER_SEC */
-#define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
-
-typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif
-
-#endif /* _LIBS_LOG_LOG_TIME_H */
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
deleted file mode 100644
index f8d5ef0..0000000
--- a/liblog/liblog.map.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-LIBLOG {
- global:
- android_name_to_log_id; # apex llndk
- android_log_id_to_name; # llndk
- __android_log_assert;
- __android_log_buf_print;
- __android_log_buf_write;
- __android_log_print;
- __android_log_vprint;
- __android_log_write;
- local:
- *;
-};
-
-LIBLOG_L {
- global:
- android_logger_clear; # llndk
- android_logger_get_id; # llndk
- android_logger_get_log_readable_size; # llndk
- android_logger_get_log_version; # llndk
- android_logger_get_log_size; # llndk
- android_logger_list_alloc; # apex llndk
- android_logger_list_alloc_time; # apex llndk
- android_logger_list_free; # apex llndk
- android_logger_list_open; # apex llndk
- android_logger_list_read; # apex llndk
- android_logger_open; # apex llndk
- android_logger_set_log_size; # llndk
-};
-
-LIBLOG_M {
- global:
- android_logger_get_prune_list; # llndk
- android_logger_set_prune_list; # llndk
- android_logger_get_statistics; # llndk
- __android_log_error_write; # apex llndk
- __android_log_is_loggable;
- create_android_logger; # apex llndk
- android_log_destroy; # apex llndk
- android_log_write_list_begin; # apex llndk
- android_log_write_list_end; # apex llndk
- android_log_write_int32; # apex llndk
- android_log_write_int64; # apex llndk
- android_log_write_string8; # apex llndk
- android_log_write_string8_len; # apex llndk
- android_log_write_float32; # apex llndk
- android_log_write_list; # apex llndk
-
-};
-
-LIBLOG_O {
- global:
- __android_log_is_loggable_len;
- __android_log_is_debuggable; # apex llndk
-};
-
-LIBLOG_Q { # introduced=29
- global:
- __android_log_bswrite; # apex
- __android_log_btwrite; # apex
- __android_log_bwrite; # apex
- __android_log_close; # apex
- __android_log_security; # apex
- android_log_reset; # llndk
- android_log_parser_reset; # llndk
-};
-
-LIBLOG_R { # introduced=30
- global:
- __android_log_call_aborter;
- __android_log_default_aborter;
- __android_log_get_minimum_priority;
- __android_log_logd_logger;
- __android_log_security_bswrite; # apex
- __android_log_set_aborter;
- __android_log_set_default_tag;
- __android_log_set_logger;
- __android_log_set_minimum_priority;
- __android_log_stderr_logger;
- __android_log_write_log_message;
-};
-
-LIBLOG_PRIVATE {
- global:
- __android_log_pmsg_file_read;
- __android_log_pmsg_file_write;
- android_openEventTagMap;
- android_log_processBinaryLogBuffer;
- android_log_processLogBuffer;
- android_log_read_next;
- android_log_write_list_buffer;
- create_android_log_parser;
-};
diff --git a/liblog/log_event_list.cpp b/liblog/log_event_list.cpp
deleted file mode 100644
index cb70d48..0000000
--- a/liblog/log_event_list.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 2016 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 <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log_event_list.h>
-#include <private/android_logger.h>
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-enum ReadWriteFlag {
- kAndroidLoggerRead = 1,
- kAndroidLoggerWrite = 2,
-};
-
-struct android_log_context_internal {
- uint32_t tag;
- unsigned pos; /* Read/write position into buffer */
- unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
- unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
- unsigned list_nest_depth;
- unsigned len; /* Length or raw buffer. */
- bool overflow;
- bool list_stop; /* next call decrement list_nest_depth and issue a stop */
- ReadWriteFlag read_write_flag;
- uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-};
-
-static void init_context(android_log_context_internal* context, uint32_t tag) {
- context->tag = tag;
- context->read_write_flag = kAndroidLoggerWrite;
- size_t needed = sizeof(android_event_list_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- }
- /* Everything is a list */
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->list[0] = context->pos + 1;
- context->pos += needed;
-}
-
-static void init_parser_context(android_log_context_internal* context, const char* msg,
- size_t len) {
- len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
- context->len = len;
- memcpy(context->storage, msg, len);
- context->read_write_flag = kAndroidLoggerRead;
-}
-
-android_log_context create_android_logger(uint32_t tag) {
- android_log_context_internal* context;
-
- context =
- static_cast<android_log_context_internal*>(calloc(1, sizeof(android_log_context_internal)));
- if (!context) {
- return NULL;
- }
- init_context(context, tag);
-
- return (android_log_context)context;
-}
-
-android_log_context create_android_log_parser(const char* msg, size_t len) {
- android_log_context_internal* context;
-
- context =
- static_cast<android_log_context_internal*>(calloc(1, sizeof(android_log_context_internal)));
- if (!context) {
- return NULL;
- }
- init_parser_context(context, msg, len);
-
- return (android_log_context)context;
-}
-
-int android_log_destroy(android_log_context* ctx) {
- android_log_context_internal* context;
-
- context = (android_log_context_internal*)*ctx;
- if (!context) {
- return -EBADF;
- }
- memset(context, 0, sizeof(*context));
- free(context);
- *ctx = NULL;
- return 0;
-}
-
-int android_log_reset(android_log_context context) {
- uint32_t tag;
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
-
- tag = context->tag;
- memset(context, 0, sizeof(*context));
- init_context(context, tag);
-
- return 0;
-}
-
-int android_log_parser_reset(android_log_context context, const char* msg, size_t len) {
- if (!context || (kAndroidLoggerRead != context->read_write_flag)) {
- return -EBADF;
- }
-
- memset(context, 0, sizeof(*context));
- init_parser_context(context, msg, len);
-
- return 0;
-}
-
-int android_log_write_list_begin(android_log_context context) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- size_t needed = sizeof(android_event_list_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- context->list_nest_depth++;
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->overflow) {
- return -EIO;
- }
- auto* event_list = reinterpret_cast<android_event_list_t*>(&context->storage[context->pos]);
- event_list->type = EVENT_TYPE_LIST;
- event_list->element_count = 0;
- context->list[context->list_nest_depth] = context->pos + 1;
- context->count[context->list_nest_depth] = 0;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_int32(android_log_context context, int32_t value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_int_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_int = reinterpret_cast<android_event_int_t*>(&context->storage[context->pos]);
- event_int->type = EVENT_TYPE_INT;
- event_int->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_int64(android_log_context context, int64_t value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_long_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_long = reinterpret_cast<android_event_long_t*>(&context->storage[context->pos]);
- event_long->type = EVENT_TYPE_LONG;
- event_long->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_string8_len(android_log_context context, const char* value, size_t maxlen) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- if (!value) {
- value = "";
- }
- int32_t len = strnlen(value, maxlen);
- size_t needed = sizeof(android_event_string_t) + len;
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- /* Truncate string for delivery */
- len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
- if (len <= 0) {
- context->overflow = true;
- return -EIO;
- }
- }
- context->count[context->list_nest_depth]++;
- auto* event_string = reinterpret_cast<android_event_string_t*>(&context->storage[context->pos]);
- event_string->type = EVENT_TYPE_STRING;
- event_string->length = len;
- if (len) {
- memcpy(&event_string->data, value, len);
- }
- context->pos += needed;
- return len;
-}
-
-int android_log_write_string8(android_log_context ctx, const char* value) {
- return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
-}
-
-int android_log_write_float32(android_log_context context, float value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_float_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_float = reinterpret_cast<android_event_float_t*>(&context->storage[context->pos]);
- event_float->type = EVENT_TYPE_FLOAT;
- event_float->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_list_end(android_log_context context) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- context->list_nest_depth--;
- return -EOVERFLOW;
- }
- if (!context->list_nest_depth) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->list[context->list_nest_depth] <= 0) {
- context->list_nest_depth--;
- context->overflow = true;
- return -EOVERFLOW;
- }
- context->storage[context->list[context->list_nest_depth]] =
- context->count[context->list_nest_depth];
- context->list_nest_depth--;
- return 0;
-}
-
-/*
- * Logs the list of elements to the event log.
- */
-int android_log_write_list(android_log_context context, log_id_t id) {
- const char* msg;
- ssize_t len;
-
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
- return -EINVAL;
- }
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth) {
- return -EIO;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- return (id == LOG_ID_EVENTS)
- ? __android_log_bwrite(context->tag, msg, len)
- : ((id == LOG_ID_STATS) ? __android_log_stats_bwrite(context->tag, msg, len)
- : __android_log_security_bwrite(context->tag, msg, len));
-}
-
-int android_log_write_list_buffer(android_log_context context, const char** buffer) {
- const char* msg;
- ssize_t len;
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth) {
- return -EIO;
- }
- if (buffer == NULL) {
- return -EFAULT;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- *buffer = msg;
- return len;
-}
-
-/*
- * Gets the next element. Parsing errors result in an EVENT_TYPE_UNKNOWN type.
- * If there is nothing to process, the complete field is set to non-zero. If
- * an EVENT_TYPE_UNKNOWN type is returned once, and the caller does not check
- * this and continues to call this function, the behavior is undefined
- * (although it won't crash).
- */
-static android_log_list_element android_log_read_next_internal(android_log_context context,
- int peek) {
- android_log_list_element elem;
- unsigned pos;
-
- memset(&elem, 0, sizeof(elem));
-
- /* Nothing to parse from this context, so return complete. */
- if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
- (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
- (context->count[context->list_nest_depth] >=
- (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
- elem.type = EVENT_TYPE_UNKNOWN;
- if (context &&
- (context->list_stop || ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
- !context->count[context->list_nest_depth]))) {
- elem.type = EVENT_TYPE_LIST_STOP;
- }
- elem.complete = true;
- return elem;
- }
-
- /*
- * Use a different variable to update the position in case this
- * operation is a "peek".
- */
- pos = context->pos;
- if (context->list_stop) {
- elem.type = EVENT_TYPE_LIST_STOP;
- elem.complete = !context->count[0] && (!context->list_nest_depth ||
- ((context->list_nest_depth == 1) && !context->count[1]));
- if (!peek) {
- /* Suck in superfluous stop */
- if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
- context->pos = pos + 1;
- }
- if (context->list_nest_depth) {
- --context->list_nest_depth;
- if (context->count[context->list_nest_depth]) {
- context->list_stop = false;
- }
- } else {
- context->list_stop = false;
- }
- }
- return elem;
- }
- if ((pos + 1) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
-
- elem.type = static_cast<AndroidEventLogType>(context->storage[pos]);
- switch ((int)elem.type) {
- case EVENT_TYPE_FLOAT:
- /* Rely on union to translate elem.data.int32 into elem.data.float32 */
- /* FALLTHRU */
- case EVENT_TYPE_INT: {
- elem.len = sizeof(int32_t);
- if ((pos + sizeof(android_event_int_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-
- auto* event_int = reinterpret_cast<android_event_int_t*>(&context->storage[pos]);
- pos += sizeof(android_event_int_t);
- elem.data.int32 = event_int->data;
- /* common tangeable object suffix */
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_LONG: {
- elem.len = sizeof(int64_t);
- if ((pos + sizeof(android_event_long_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-
- auto* event_long = reinterpret_cast<android_event_long_t*>(&context->storage[pos]);
- pos += sizeof(android_event_long_t);
- elem.data.int64 = event_long->data;
- /* common tangeable object suffix */
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_STRING: {
- if ((pos + sizeof(android_event_string_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- auto* event_string = reinterpret_cast<android_event_string_t*>(&context->storage[pos]);
- pos += sizeof(android_event_string_t);
- // Wire format is int32_t, but elem.len is uint16_t...
- if (event_string->length >= UINT16_MAX) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- elem.len = event_string->length;
- if ((pos + elem.len) > context->len) {
- elem.len = context->len - pos; /* truncate string */
- elem.complete = true;
- if (!elem.len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- }
- elem.data.string = event_string->data;
- /* common tangeable object suffix */
- pos += elem.len;
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_LIST: {
- if ((pos + sizeof(android_event_list_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- auto* event_list = reinterpret_cast<android_event_list_t*>(&context->storage[pos]);
- pos += sizeof(android_event_list_t);
- elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
- if (peek) {
- return elem;
- }
- if (context->count[context->list_nest_depth]) {
- context->count[context->list_nest_depth]--;
- }
- context->list_stop = event_list->element_count == 0;
- context->list_nest_depth++;
- if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
- context->count[context->list_nest_depth] = event_list->element_count;
- }
- context->pos = pos;
- return elem;
- }
-
- case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
- pos++;
- if (!peek) {
- context->pos = pos;
- }
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = !context->list_nest_depth;
- if (context->list_nest_depth > 0) {
- elem.type = EVENT_TYPE_LIST_STOP;
- if (!peek) {
- context->list_nest_depth--;
- }
- }
- return elem;
-
- default:
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-}
-
-android_log_list_element android_log_read_next(android_log_context ctx) {
- return android_log_read_next_internal(ctx, 0);
-}
-
-android_log_list_element android_log_peek_next(android_log_context ctx) {
- return android_log_read_next_internal(ctx, 1);
-}
diff --git a/liblog/log_event_write.cpp b/liblog/log_event_write.cpp
deleted file mode 100644
index 39afd0c..0000000
--- a/liblog/log_event_write.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <stdint.h>
-
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#define MAX_SUBTAG_LEN 32
-
-int __android_log_error_write(int tag, const char* subTag, int32_t uid, const char* data,
- uint32_t dataLen) {
- int ret = -EINVAL;
-
- if (subTag && (data || !dataLen)) {
- android_log_context ctx = create_android_logger(tag);
-
- ret = -ENOMEM;
- if (ctx) {
- ret = android_log_write_string8_len(ctx, subTag, MAX_SUBTAG_LEN);
- if (ret >= 0) {
- ret = android_log_write_int32(ctx, uid);
- if (ret >= 0) {
- ret = android_log_write_string8_len(ctx, data, dataLen);
- if (ret >= 0) {
- ret = android_log_write_list(ctx, LOG_ID_EVENTS);
- }
- }
- }
- android_log_destroy(&ctx);
- }
- }
- return ret;
-}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
deleted file mode 100644
index 14c408c..0000000
--- a/liblog/log_time.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2014 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 <ctype.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <private/android_logger.h>
-
-// Add %#q for fractional seconds to standard strptime function
-char* log_time::strptime(const char* s, const char* format) {
- time_t now;
-#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
- now = tv_sec;
-#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
-#endif
-
- struct tm* ptm;
-#if !defined(_WIN32)
- struct tm tmBuf;
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
-
- char fmt[strlen(format) + 1];
- strcpy(fmt, format);
-
- char* ret = const_cast<char*>(s);
- char* cp;
- for (char* f = cp = fmt;; ++cp) {
- if (!*cp) {
- if (f != cp) {
- ret = ::strptime(ret, f, ptm);
- }
- break;
- }
- if (*cp != '%') {
- continue;
- }
- char* e = cp;
- ++e;
-#if (defined(__BIONIC__))
- if (*e == 's') {
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- tv_sec = 0;
- while (isdigit(*ret)) {
- tv_sec = tv_sec * 10 + *ret - '0';
- ++ret;
- }
- now = tv_sec;
-#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
- } else
-#endif
- {
- unsigned num = 0;
- while (isdigit(*e)) {
- num = num * 10 + *e - '0';
- ++e;
- }
- if (*e != 'q') {
- continue;
- }
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- unsigned long mul = NS_PER_SEC;
- if (num == 0) {
- num = INT_MAX;
- }
- tv_nsec = 0;
- while (isdigit(*ret) && num && (mul > 1)) {
- --num;
- mul /= 10;
- tv_nsec = tv_nsec + (*ret - '0') * mul;
- ++ret;
- }
- }
- f = cp = e;
- ++f;
- }
-
- if (ret) {
- tv_sec = mktime(ptm);
- return ret;
- }
-
-// Upon error, place a known value into the class, the current time.
-#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
-#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
-#endif
- return ret;
-}
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
deleted file mode 100644
index 611caed..0000000
--- a/liblog/logd_reader.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 "logd_reader.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/parseint.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-
-// Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
-// O_CLOEXEC is always set.
-static int socket_local_client(const std::string& name, int type, bool timeout) {
- sockaddr_un addr = {.sun_family = AF_LOCAL};
-
- std::string path = "/dev/socket/" + name;
- if (path.size() + 1 > sizeof(addr.sun_path)) {
- return -1;
- }
- strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
-
- int fd = socket(AF_LOCAL, type | SOCK_CLOEXEC, 0);
- if (fd == -1) {
- return -1;
- }
-
- if (timeout) {
- // Sending and receiving messages should be instantaneous, but we don't want to wait forever if
- // logd is hung, so we set a gracious 2s timeout.
- struct timeval t = {2, 0};
- if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t)) == -1) {
- return -1;
- }
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1) {
- return -1;
- }
- }
-
- if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-/* worker for sending the command to the logger */
-ssize_t SendLogdControlMessage(char* buf, size_t buf_size) {
- ssize_t ret;
- size_t len;
- char* cp;
- int errno_save = 0;
- int sock = socket_local_client("logd", SOCK_STREAM, true);
- if (sock < 0) {
- return sock;
- }
-
- len = strlen(buf) + 1;
- ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
- if (ret <= 0) {
- goto done;
- }
-
- len = buf_size;
- cp = buf;
- while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
- struct pollfd p;
-
- if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
- break;
- }
-
- len -= ret;
- cp += ret;
-
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
-
- /* Give other side 20ms to refill pipe */
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
-
- if (ret <= 0) {
- break;
- }
-
- if (!(p.revents & POLLIN)) {
- ret = 0;
- break;
- }
- }
-
- if (ret >= 0) {
- ret += buf_size - len;
- }
-
-done:
- if ((ret == -1) && errno) {
- errno_save = errno;
- }
- close(sock);
- if (errno_save) {
- errno = errno_save;
- }
- return ret;
-}
-
-static int check_log_success(char* buf, ssize_t ret) {
- if (ret < 0) {
- return ret;
- }
-
- if (strncmp(buf, "success", 7)) {
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-int android_logger_clear(struct logger* logger) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- snprintf(buf, sizeof(buf), "clear %" PRIu32, log_id);
-
- return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
-}
-
-enum class LogSizeType : uint32_t {
- kAllotted = 0,
- kReadable,
- kConsumed,
-};
-
-static long GetLogSize(struct logger* logger, LogSizeType type) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
-
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- switch (type) {
- case LogSizeType::kAllotted:
- snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
- break;
- case LogSizeType::kReadable:
- snprintf(buf, sizeof(buf), "getLogSizeReadable %" PRIu32, log_id);
- break;
- case LogSizeType::kConsumed:
- snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
- break;
- default:
- abort();
- }
-
- ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- long size;
- if (!android::base::ParseInt(buf, &size)) {
- return -1;
- }
-
- return size;
-}
-
-long android_logger_get_log_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kAllotted);
-}
-
-long android_logger_get_log_readable_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kReadable);
-}
-
-long android_logger_get_log_consumed_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kConsumed);
-}
-
-int android_logger_set_log_size(struct logger* logger, unsigned long size) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
-
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- snprintf(buf, sizeof(buf), "setLogSize %" PRIu32 " %lu", log_id, size);
-
- return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
-}
-
-int android_logger_get_log_version(struct logger*) {
- return 4;
-}
-
-ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- char* cp = buf;
- size_t remaining = len;
- size_t n;
-
- n = snprintf(cp, remaining, "getStatistics");
- n = MIN(n, remaining);
- remaining -= n;
- cp += n;
-
- for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
- if ((1 << log_id) & logger_list->log_mask) {
- n = snprintf(cp, remaining, " %zu", log_id);
- n = MIN(n, remaining);
- remaining -= n;
- cp += n;
- }
- }
-
- if (logger_list->pid) {
- snprintf(cp, remaining, " pid=%u", logger_list->pid);
- }
-
- return SendLogdControlMessage(buf, len);
-}
-ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- snprintf(buf, len, "getPruneList");
- return SendLogdControlMessage(buf, len);
-}
-
-int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- std::string cmd = "setPruneList " + std::string{buf, len};
-
- return check_log_success(cmd.data(), SendLogdControlMessage(cmd.data(), cmd.size()));
-}
-
-static int logdOpen(struct logger_list* logger_list) {
- char buffer[256], *cp, c;
- int ret, remaining, sock;
-
- sock = atomic_load(&logger_list->fd);
- if (sock > 0) {
- return sock;
- }
-
- sock = socket_local_client("logdr", SOCK_SEQPACKET, false);
- if (sock <= 0) {
- if ((sock == -1) && errno) {
- return -errno;
- }
- return sock;
- }
-
- strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
- cp = buffer + strlen(buffer);
-
- strcpy(cp, " lids");
- cp += 5;
- c = '=';
- remaining = sizeof(buffer) - (cp - buffer);
-
- for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
- if ((1 << log_id) & logger_list->log_mask) {
- ret = snprintf(cp, remaining, "%c%zu", c, log_id);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- c = ',';
- }
- }
-
- if (logger_list->tail) {
- ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
- if (logger_list->mode & ANDROID_LOG_WRAP) {
- // ToDo: alternate API to allow timeout to be adjusted.
- ret = snprintf(cp, remaining, " timeout=%u", ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
- ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, logger_list->start.tv_sec,
- logger_list->start.tv_nsec);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->pid) {
- ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
- ret = MIN(ret, remaining);
- cp += ret;
- }
-
- ret = TEMP_FAILURE_RETRY(write(sock, buffer, cp - buffer));
- int write_errno = errno;
-
- if (ret <= 0) {
- close(sock);
- if (ret == -1) {
- return -write_errno;
- }
- if (ret == 0) {
- return -EIO;
- }
- return ret;
- }
-
- ret = atomic_exchange(&logger_list->fd, sock);
- if ((ret > 0) && (ret != sock)) {
- close(ret);
- }
- return sock;
-}
-
-/* Read from the selected logs */
-int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
- int ret = logdOpen(logger_list);
- if (ret < 0) {
- return ret;
- }
-
- /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
- ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
- if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
- return -EAGAIN;
- }
-
- if (ret == -1) {
- return -errno;
- }
- return ret;
-}
-
-/* Close all the logs */
-void LogdClose(struct logger_list* logger_list) {
- int sock = atomic_exchange(&logger_list->fd, -1);
- if (sock > 0) {
- close(sock);
- }
-}
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
deleted file mode 100644
index 68eef02..0000000
--- a/liblog/logd_reader.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sys/cdefs.h>
-#include <unistd.h>
-
-#include "log/log_read.h"
-
-__BEGIN_DECLS
-
-int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg);
-void LogdClose(struct logger_list* logger_list);
-
-ssize_t SendLogdControlMessage(char* buf, size_t buf_size);
-
-__END_DECLS
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
deleted file mode 100644
index f5d19ca..0000000
--- a/liblog/logd_writer.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 "logd_writer.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-#include "uio.h"
-
-static atomic_int logd_socket;
-
-// Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
-// function is used to reconnect to logd without requiring a new socket.
-static void LogdConnect() {
- sockaddr_un un = {};
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
- TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
-}
-
-// logd_socket should only be opened once. If we see that logd_socket is uninitialized, we create a
-// new socket and attempt to exchange it into the atomic logd_socket. If the compare/exchange was
-// successful, then that will be the socket used for the duration of the program, otherwise a
-// different thread has already opened and written the socket to the atomic, so close the new socket
-// and return.
-static void GetSocket() {
- if (logd_socket != 0) {
- return;
- }
-
- int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (new_socket <= 0) {
- return;
- }
-
- int uninitialized_value = 0;
- if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) {
- close(new_socket);
- return;
- }
-
- LogdConnect();
-}
-
-// This is the one exception to the above. Zygote uses this to clean up open FD's after fork() and
-// before specialization. It is single threaded at this point and therefore this function is
-// explicitly not thread safe. It sets logd_socket to 0, so future logs will be safely initialized
-// whenever they happen.
-void LogdClose() {
- if (logd_socket > 0) {
- close(logd_socket);
- }
- logd_socket = 0;
-}
-
-int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
- ssize_t ret;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
-
- GetSocket();
-
- if (logd_socket <= 0) {
- return -EBADF;
- }
-
- /* logd, after initialization and priv drop */
- if (getuid() == AID_LOGD) {
- /*
- * ignore log messages we send to ourself (logd).
- * Such log messages are often generated by libraries we depend on
- * which use standard Android logging.
- */
- return 0;
- }
-
- header.id = logId;
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&header;
- newVec[0].iov_len = sizeof(header);
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- break;
- }
- }
-
- ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
- if (ret < 0) {
- LogdConnect();
-
- ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
- }
-
- if (ret < 0) {
- ret = -errno;
- }
-
- return ret;
-}
diff --git a/liblog/logd_writer.h b/liblog/logd_writer.h
deleted file mode 100644
index 41197b5..0000000
--- a/liblog/logd_writer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 <stddef.h>
-
-#include <android/log.h>
-
-int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-void LogdClose();
diff --git a/liblog/logger.h b/liblog/logger.h
deleted file mode 100644
index ddff19d..0000000
--- a/liblog/logger.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 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 <stdatomic.h>
-#include <sys/cdefs.h>
-
-#include <log/log.h>
-
-#include "uio.h"
-
-__BEGIN_DECLS
-
-struct logger_list {
- atomic_int fd;
- int mode;
- unsigned int tail;
- log_time start;
- pid_t pid;
- uint32_t log_mask;
-};
-
-// Format for a 'logger' entry: uintptr_t where only the bottom 32 bits are used.
-// bit 31: Set if this 'logger' is for logd.
-// bit 30: Set if this 'logger' is for pmsg
-// bits 0-2: the decimal value of the log buffer.
-// Other bits are unused.
-
-#define LOGGER_LOGD (1U << 31)
-#define LOGGER_PMSG (1U << 30)
-#define LOGGER_LOG_ID_MASK ((1U << 3) - 1)
-
-inline bool android_logger_is_logd(struct logger* logger) {
- return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
-}
-
-__END_DECLS
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
deleted file mode 100644
index e72290e..0000000
--- a/liblog/logger_name.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-** Copyright 2013-2014, 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 <string.h>
-#include <type_traits>
-
-#include <log/log.h>
-
-/* In the future, we would like to make this list extensible */
-static const char* LOG_NAME[LOG_ID_MAX] = {
- /* clang-format off */
- [LOG_ID_MAIN] = "main",
- [LOG_ID_RADIO] = "radio",
- [LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash",
- [LOG_ID_STATS] = "stats",
- [LOG_ID_SECURITY] = "security",
- [LOG_ID_KERNEL] = "kernel",
- /* clang-format on */
-};
-
-const char* android_log_id_to_name(log_id_t log_id) {
- if (log_id >= LOG_ID_MAX) {
- log_id = LOG_ID_MAIN;
- }
- return LOG_NAME[log_id];
-}
-
-static_assert(std::is_same<std::underlying_type<log_id_t>::type, uint32_t>::value,
- "log_id_t must be an uint32_t");
-
-static_assert(std::is_same<std::underlying_type<android_LogPriority>::type, uint32_t>::value,
- "log_id_t must be an uint32_t");
-
-log_id_t android_name_to_log_id(const char* logName) {
- const char* b;
- unsigned int ret;
-
- if (!logName) {
- return static_cast<log_id_t>(LOG_ID_MAX);
- }
-
- b = strrchr(logName, '/');
- if (!b) {
- b = logName;
- } else {
- ++b;
- }
-
- for (ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
- const char* l = LOG_NAME[ret];
- if (l && !strcmp(b, l)) {
- return static_cast<log_id_t>(ret);
- }
- }
-
- return static_cast<log_id_t>(LOG_ID_MAX);
-}
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
deleted file mode 100644
index 4937042..0000000
--- a/liblog/logger_read.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-** Copyright 2013-2014, 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 "log/log_read.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sched.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "logd_reader.h"
-#include "logger.h"
-#include "pmsg_reader.h"
-
-/* method for getting the associated sublog id */
-log_id_t android_logger_get_id(struct logger* logger) {
- return static_cast<log_id_t>(reinterpret_cast<uintptr_t>(logger) & LOGGER_LOG_ID_MASK);
-}
-
-static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail,
- log_time start, pid_t pid) {
- auto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));
- if (!logger_list) {
- return nullptr;
- }
-
- logger_list->mode = mode;
- logger_list->start = start;
- logger_list->tail = tail;
- logger_list->pid = pid;
-
- return logger_list;
-}
-
-struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
- return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);
-}
-
-struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
- return android_logger_list_alloc_internal(mode, 0, start, pid);
-}
-
-/* Open the named log and add it to the logger list */
-struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
- if (!logger_list || (logId >= LOG_ID_MAX)) {
- return nullptr;
- }
-
- logger_list->log_mask |= 1 << logId;
-
- uintptr_t logger = logId;
- logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;
- return reinterpret_cast<struct logger*>(logger);
-}
-
-/* Open the single named log and make it part of a new logger list */
-struct logger_list* android_logger_list_open(log_id_t logId, int mode, unsigned int tail,
- pid_t pid) {
- struct logger_list* logger_list = android_logger_list_alloc(mode, tail, pid);
-
- if (!logger_list) {
- return NULL;
- }
-
- if (!android_logger_open(logger_list, logId)) {
- android_logger_list_free(logger_list);
- return NULL;
- }
-
- return logger_list;
-}
-
-int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
- if (logger_list == nullptr || logger_list->log_mask == 0) {
- return -EINVAL;
- }
-
- int ret = 0;
-
-#ifdef __ANDROID__
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- ret = PmsgRead(logger_list, log_msg);
- } else {
- ret = LogdRead(logger_list, log_msg);
- }
-#endif
-
- if (ret <= 0) {
- return ret;
- }
-
- if (ret > LOGGER_ENTRY_MAX_LEN) {
- ret = LOGGER_ENTRY_MAX_LEN;
- }
-
- if (ret < static_cast<int>(sizeof(log_msg->entry))) {
- return -EINVAL;
- }
-
- if (log_msg->entry.hdr_size < sizeof(log_msg->entry) ||
- log_msg->entry.hdr_size >= LOGGER_ENTRY_MAX_LEN - sizeof(log_msg->entry)) {
- return -EINVAL;
- }
-
- if (log_msg->entry.len > ret - log_msg->entry.hdr_size) {
- return -EINVAL;
- }
-
- log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = '\0';
-
- return ret;
-}
-
-/* Close all the logs */
-void android_logger_list_free(struct logger_list* logger_list) {
- if (logger_list == NULL) {
- return;
- }
-
-#ifdef __ANDROID__
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- PmsgClose(logger_list);
- } else {
- LogdClose(logger_list);
- }
-#endif
-
- free(logger_list);
-}
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
deleted file mode 100644
index 22c7eca..0000000
--- a/liblog/logger_write.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 "logger_write.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-
-#ifdef __BIONIC__
-#include <android/set_abort_message.h>
-#endif
-
-#include <atomic>
-
-#include <android-base/errno_restorer.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "android/log.h"
-#include "log/log_read.h"
-#include "logger.h"
-#include "uio.h"
-
-#ifdef __ANDROID__
-#include "logd_writer.h"
-#include "pmsg_writer.h"
-#endif
-
-#if defined(__APPLE__)
-#include <pthread.h>
-#elif defined(__linux__) && !defined(__ANDROID__)
-#include <syscall.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
-using android::base::ErrnoRestorer;
-
-#define LOG_BUF_SIZE 1024
-
-#if defined(__ANDROID__)
-static int check_log_uid_permissions() {
- uid_t uid = getuid();
-
- /* Matches clientHasLogCredentials() in logd */
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- uid = geteuid();
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- gid_t gid = getgid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- gid = getegid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- int num_groups;
- gid_t* groups;
-
- num_groups = getgroups(0, NULL);
- if (num_groups <= 0) {
- return -EPERM;
- }
- groups = static_cast<gid_t*>(calloc(num_groups, sizeof(gid_t)));
- if (!groups) {
- return -ENOMEM;
- }
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- free(groups);
- if (num_groups <= 0) {
- return -EPERM;
- }
- }
- }
- }
- }
- return 0;
-}
-#endif
-
-/*
- * Release any logger resources. A new log write will immediately re-acquire.
- */
-void __android_log_close() {
-#ifdef __ANDROID__
- LogdClose();
- PmsgClose();
-#endif
-}
-
-#if defined(__GLIBC__) || defined(_WIN32)
-static const char* getprogname() {
-#if defined(__GLIBC__)
- return program_invocation_short_name;
-#elif defined(_WIN32)
- static bool first = true;
- static char progname[MAX_PATH] = {};
-
- if (first) {
- char path[PATH_MAX + 1];
- DWORD result = GetModuleFileName(nullptr, path, sizeof(path) - 1);
- if (result == 0 || result == sizeof(path) - 1) return "";
- path[PATH_MAX - 1] = 0;
-
- char* path_basename = basename(path);
-
- snprintf(progname, sizeof(progname), "%s", path_basename);
- first = false;
- }
-
- return progname;
-#endif
-}
-#endif
-
-// It's possible for logging to happen during static initialization before our globals are
-// initialized, so we place this std::string in a function such that it is initialized on the first
-// call.
-std::string& GetDefaultTag() {
- static std::string default_tag = getprogname();
- return default_tag;
-}
-
-void __android_log_set_default_tag(const char* tag) {
- GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
-}
-
-static std::atomic_int32_t minimum_log_priority = ANDROID_LOG_DEFAULT;
-int32_t __android_log_set_minimum_priority(int32_t priority) {
- return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
-}
-
-int32_t __android_log_get_minimum_priority() {
- return minimum_log_priority;
-}
-
-#ifdef __ANDROID__
-static __android_logger_function logger_function = __android_log_logd_logger;
-#else
-static __android_logger_function logger_function = __android_log_stderr_logger;
-#endif
-
-void __android_log_set_logger(__android_logger_function logger) {
- logger_function = logger;
-}
-
-void __android_log_default_aborter(const char* abort_message) {
-#ifdef __ANDROID__
- android_set_abort_message(abort_message);
-#else
- UNUSED(abort_message);
-#endif
- abort();
-}
-
-static __android_aborter_function aborter_function = __android_log_default_aborter;
-
-void __android_log_set_aborter(__android_aborter_function aborter) {
- aborter_function = aborter;
-}
-
-void __android_log_call_aborter(const char* abort_message) {
- aborter_function(abort_message);
-}
-
-#ifdef __ANDROID__
-static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
- int ret;
- struct timespec ts;
-
- if (log_id == LOG_ID_KERNEL) {
- return -EINVAL;
- }
-
- clock_gettime(CLOCK_REALTIME, &ts);
-
- if (log_id == LOG_ID_SECURITY) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- ret = check_log_uid_permissions();
- if (ret < 0) {
- return ret;
- }
- if (!__android_log_security()) {
- /* If only we could reset downstream logd counter */
- return -EPERM;
- }
- } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
- }
-
- ret = LogdWrite(log_id, &ts, vec, nr);
- PmsgWrite(log_id, &ts, vec, nr);
-
- return ret;
-}
-#else
-static int write_to_log(log_id_t, struct iovec*, size_t) {
- // Non-Android text logs should go to __android_log_stderr_logger, not here.
- // Non-Android binary logs are always dropped.
- return 1;
-}
-#endif
-
-// Copied from base/threads.cpp
-static uint64_t GetThreadId() {
-#if defined(__BIONIC__)
- return gettid();
-#elif defined(__APPLE__)
- uint64_t tid;
- pthread_threadid_np(NULL, &tid);
- return tid;
-#elif defined(__linux__)
- return syscall(__NR_gettid);
-#elif defined(_WIN32)
- return GetCurrentThreadId();
-#endif
-}
-
-void __android_log_stderr_logger(const struct __android_log_message* log_message) {
- struct tm now;
- time_t t = time(nullptr);
-
-#if defined(_WIN32)
- localtime_s(&now, &t);
-#else
- localtime_r(&t, &now);
-#endif
-
- char timestamp[32];
- strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
-
- static const char log_characters[] = "XXVDIWEF";
- static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
- "Mismatch in size of log_characters and values in android_LogPriority");
- int32_t priority =
- log_message->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : log_message->priority;
- char priority_char = log_characters[priority];
- uint64_t tid = GetThreadId();
-
- if (log_message->file != nullptr) {
- fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
- log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
- tid, log_message->file, log_message->line, log_message->message);
- } else {
- fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
- log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
- tid, log_message->message);
- }
-}
-
-void __android_log_logd_logger(const struct __android_log_message* log_message) {
- int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
-
- struct iovec vec[3];
- vec[0].iov_base =
- const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
- vec[0].iov_len = 1;
- vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
- vec[1].iov_len = strlen(log_message->tag) + 1;
- vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
- vec[2].iov_len = strlen(log_message->message) + 1;
-
- write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
-}
-
-int __android_log_write(int prio, const char* tag, const char* msg) {
- return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
-}
-
-void __android_log_write_log_message(__android_log_message* log_message) {
- ErrnoRestorer errno_restorer;
-
- if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
- log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
- log_message->buffer_id != LOG_ID_CRASH) {
- return;
- }
-
- if (log_message->tag == nullptr) {
- log_message->tag = GetDefaultTag().c_str();
- }
-
-#if __BIONIC__
- if (log_message->priority == ANDROID_LOG_FATAL) {
- android_set_abort_message(log_message->message);
- }
-#endif
-
- logger_function(log_message);
-}
-
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- __android_log_message log_message = {
- sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, msg};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...) {
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- if (fmt) {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- } else {
- /* Msg not provided, log condition. N.B. Do not use cond directly as
- * format string as it could contain spurious '%' syntax (e.g.
- * "%d" in "blocks%devs == 0").
- */
- if (cond)
- snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
- else
- strcpy(buf, "Unspecified assertion failed");
- }
-
- // Log assertion failures to stderr for the benefit of "adb shell" users
- // and gtests (http://b/23675822).
- TEMP_FAILURE_RETRY(write(2, buf, strlen(buf)));
- TEMP_FAILURE_RETRY(write(2, "\n", 1));
-
- __android_log_write(ANDROID_LOG_FATAL, tag, buf);
- __android_log_call_aborter(buf);
- abort();
-}
-
-int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 2);
-}
-
-int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_STATS, vec, 2);
-}
-
-int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 2);
-}
-
-/*
- * Like __android_log_bwrite, but takes the type as well. Doesn't work
- * for the general case where we're generating lists of stuff, but very
- * handy if we just want to dump an integer into the log.
- */
-int __android_log_btwrite(int32_t tag, char type, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[3];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = (void*)payload;
- vec[2].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 3);
-}
-
-/*
- * Like __android_log_bwrite, but used for writing strings to the
- * event log.
- */
-int __android_log_bswrite(int32_t tag, const char* payload) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 4);
-}
-
-/*
- * Like __android_log_security_bwrite, but used for writing strings to the
- * security log.
- */
-int __android_log_security_bswrite(int32_t tag, const char* payload) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 4);
-}
diff --git a/liblog/logger_write.h b/liblog/logger_write.h
deleted file mode 100644
index eee2778..0000000
--- a/liblog/logger_write.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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 <string>
-
-std::string& GetDefaultTag();
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
deleted file mode 100644
index a5c5edd..0000000
--- a/liblog/logprint.cpp
+++ /dev/null
@@ -1,1748 +0,0 @@
-/*
-**
-** Copyright 2006-2014, 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.
-*/
-
-#ifndef __MINGW32__
-#define HAVE_STRSEP
-#endif
-
-#include <log/logprint.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#ifndef __MINGW32__
-#include <pwd.h>
-#endif
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <wchar.h>
-
-#include <cutils/list.h>
-
-#include <log/log.h>
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-#define MS_PER_NSEC 1000000
-#define US_PER_NSEC 1000
-
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-typedef struct FilterInfo_t {
- char* mTag;
- android_LogPriority mPri;
- struct FilterInfo_t* p_next;
-} FilterInfo;
-
-struct AndroidLogFormat_t {
- android_LogPriority global_pri;
- FilterInfo* filters;
- AndroidLogPrintFormat format;
- bool colored_output;
- bool usec_time_output;
- bool nsec_time_output;
- bool printable_output;
- bool year_output;
- bool zone_output;
- bool epoch_output;
- bool monotonic_output;
- bool uid_output;
- bool descriptive_output;
-};
-
-/*
- * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
- * during android_log_processBinaryLogBuffer(), so we break layering.
- */
-static bool descriptive_output = false;
-
-/*
- * 8-bit color tags. See ECMA-48 Set Graphics Rendition in
- * [console_codes(4)](https://man7.org/linux/man-pages/man4/console_codes.4.html).
- *
- * The text manipulation character stream is defined as:
- * ESC [ <parameter #> m
- *
- * We use "set <color> foreground" escape sequences instead of
- * "256/24-bit foreground color". This allows colors to render
- * according to user preferences in terminal emulator settings
- */
-#define ANDROID_COLOR_BLUE 34
-#define ANDROID_COLOR_DEFAULT 39
-#define ANDROID_COLOR_GREEN 32
-#define ANDROID_COLOR_RED 31
-#define ANDROID_COLOR_YELLOW 33
-
-static FilterInfo* filterinfo_new(const char* tag, android_LogPriority pri) {
- FilterInfo* p_ret;
-
- p_ret = (FilterInfo*)calloc(1, sizeof(FilterInfo));
- p_ret->mTag = strdup(tag);
- p_ret->mPri = pri;
-
- return p_ret;
-}
-
-/* balance to above, filterinfo_free left unimplemented */
-
-/*
- * Note: also accepts 0-9 priorities
- * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
- */
-static android_LogPriority filterCharToPri(char c) {
- android_LogPriority pri;
-
- c = tolower(c);
-
- if (c >= '0' && c <= '9') {
- if (c >= ('0' + ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
- } else {
- pri = ANDROID_LOG_UNKNOWN;
- }
-
- return pri;
-}
-
-static char filterPriToChar(android_LogPriority pri) {
- switch (pri) {
- /* clang-format off */
- case ANDROID_LOG_VERBOSE: return 'V';
- case ANDROID_LOG_DEBUG: return 'D';
- case ANDROID_LOG_INFO: return 'I';
- case ANDROID_LOG_WARN: return 'W';
- case ANDROID_LOG_ERROR: return 'E';
- case ANDROID_LOG_FATAL: return 'F';
- case ANDROID_LOG_SILENT: return 'S';
-
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return '?';
- /* clang-format on */
- }
-}
-
-static int colorFromPri(android_LogPriority pri) {
- switch (pri) {
- /* clang-format off */
- case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
- case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
- case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
- case ANDROID_LOG_WARN: return ANDROID_COLOR_YELLOW;
- case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
- case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
- case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
-
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return ANDROID_COLOR_DEFAULT;
- /* clang-format on */
- }
-}
-
-static android_LogPriority filterPriForTag(AndroidLogFormat* p_format, const char* tag) {
- FilterInfo* p_curFilter;
-
- for (p_curFilter = p_format->filters; p_curFilter != NULL; p_curFilter = p_curFilter->p_next) {
- if (0 == strcmp(tag, p_curFilter->mTag)) {
- if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
- return p_format->global_pri;
- } else {
- return p_curFilter->mPri;
- }
- }
- }
-
- return p_format->global_pri;
-}
-
-/**
- * returns 1 if this log line should be printed based on its priority
- * and tag, and 0 if it should not
- */
-int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri) {
- return pri >= filterPriForTag(p_format, tag);
-}
-
-AndroidLogFormat* android_log_format_new() {
- AndroidLogFormat* p_ret;
-
- p_ret = static_cast<AndroidLogFormat*>(calloc(1, sizeof(AndroidLogFormat)));
-
- p_ret->global_pri = ANDROID_LOG_VERBOSE;
- p_ret->format = FORMAT_BRIEF;
- p_ret->colored_output = false;
- p_ret->usec_time_output = false;
- p_ret->nsec_time_output = false;
- p_ret->printable_output = false;
- p_ret->year_output = false;
- p_ret->zone_output = false;
- p_ret->epoch_output = false;
- p_ret->monotonic_output = false;
- p_ret->uid_output = false;
- p_ret->descriptive_output = false;
- descriptive_output = false;
-
- return p_ret;
-}
-
-static list_declare(convertHead);
-
-void android_log_format_free(AndroidLogFormat* p_format) {
- FilterInfo *p_info, *p_info_old;
-
- p_info = p_format->filters;
-
- while (p_info != NULL) {
- p_info_old = p_info;
- p_info = p_info->p_next;
-
- free(p_info_old);
- }
-
- free(p_format);
-
- /* Free conversion resource, can always be reconstructed */
- while (!list_empty(&convertHead)) {
- struct listnode* node = list_head(&convertHead);
- list_remove(node);
- LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list");
- free(node);
- }
-}
-
-int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
- switch (format) {
- case FORMAT_MODIFIER_COLOR:
- p_format->colored_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_USEC:
- p_format->usec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_NSEC:
- p_format->nsec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_PRINTABLE:
- p_format->printable_output = true;
- return 0;
- case FORMAT_MODIFIER_YEAR:
- p_format->year_output = true;
- return 0;
- case FORMAT_MODIFIER_ZONE:
- p_format->zone_output = !p_format->zone_output;
- return 0;
- case FORMAT_MODIFIER_EPOCH:
- p_format->epoch_output = true;
- return 0;
- case FORMAT_MODIFIER_MONOTONIC:
- p_format->monotonic_output = true;
- return 0;
- case FORMAT_MODIFIER_UID:
- p_format->uid_output = true;
- return 0;
- case FORMAT_MODIFIER_DESCRIPT:
- p_format->descriptive_output = true;
- descriptive_output = true;
- return 0;
- default:
- break;
- }
- p_format->format = format;
- return 1;
-}
-
-#ifndef __MINGW32__
-static const char tz[] = "TZ";
-static const char utc[] = "UTC";
-#endif
-
-/**
- * Returns FORMAT_OFF on invalid string
- */
-AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
- static AndroidLogPrintFormat format;
-
- /* clang-format off */
- if (!strcmp(formatString, "brief")) format = FORMAT_BRIEF;
- else if (!strcmp(formatString, "process")) format = FORMAT_PROCESS;
- else if (!strcmp(formatString, "tag")) format = FORMAT_TAG;
- else if (!strcmp(formatString, "thread")) format = FORMAT_THREAD;
- else if (!strcmp(formatString, "raw")) format = FORMAT_RAW;
- else if (!strcmp(formatString, "time")) format = FORMAT_TIME;
- else if (!strcmp(formatString, "threadtime")) format = FORMAT_THREADTIME;
- else if (!strcmp(formatString, "long")) format = FORMAT_LONG;
- else if (!strcmp(formatString, "color")) format = FORMAT_MODIFIER_COLOR;
- else if (!strcmp(formatString, "colour")) format = FORMAT_MODIFIER_COLOR;
- else if (!strcmp(formatString, "usec")) format = FORMAT_MODIFIER_TIME_USEC;
- else if (!strcmp(formatString, "nsec")) format = FORMAT_MODIFIER_TIME_NSEC;
- else if (!strcmp(formatString, "printable")) format = FORMAT_MODIFIER_PRINTABLE;
- else if (!strcmp(formatString, "year")) format = FORMAT_MODIFIER_YEAR;
- else if (!strcmp(formatString, "zone")) format = FORMAT_MODIFIER_ZONE;
- else if (!strcmp(formatString, "epoch")) format = FORMAT_MODIFIER_EPOCH;
- else if (!strcmp(formatString, "monotonic")) format = FORMAT_MODIFIER_MONOTONIC;
- else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
- else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
- /* clang-format on */
-
-#ifndef __MINGW32__
- else {
- extern char* tzname[2];
- static const char gmt[] = "GMT";
- char* cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, formatString, 1);
- /*
- * Run tzset here to determine if the timezone is legitimate. If the
- * zone is GMT, check if that is what was asked for, if not then
- * did not match any on the system; report an error to caller.
- */
- tzset();
- if (!tzname[0] ||
- ((!strcmp(tzname[0], utc) || !strcmp(tzname[0], gmt)) /* error? */
- && strcasecmp(formatString, utc) && strcasecmp(formatString, gmt))) { /* ok */
- if (cp) {
- setenv(tz, cp, 1);
- } else {
- unsetenv(tz);
- }
- tzset();
- format = FORMAT_OFF;
- } else {
- format = FORMAT_MODIFIER_ZONE;
- }
- free(cp);
- }
-#endif
-
- return format;
-}
-
-/**
- * filterExpression: a single filter expression
- * eg "AT:d"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- */
-
-int android_log_addFilterRule(AndroidLogFormat* p_format, const char* filterExpression) {
- size_t tagNameLength;
- android_LogPriority pri = ANDROID_LOG_DEFAULT;
-
- tagNameLength = strcspn(filterExpression, ":");
-
- if (tagNameLength == 0) {
- goto error;
- }
-
- if (filterExpression[tagNameLength] == ':') {
- pri = filterCharToPri(filterExpression[tagNameLength + 1]);
-
- if (pri == ANDROID_LOG_UNKNOWN) {
- goto error;
- }
- }
-
- if (0 == strncmp("*", filterExpression, tagNameLength)) {
- /*
- * This filter expression refers to the global filter
- * The default level for this is DEBUG if the priority
- * is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_DEBUG;
- }
-
- p_format->global_pri = pri;
- } else {
- /*
- * for filter expressions that don't refer to the global
- * filter, the default is verbose if the priority is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_VERBOSE;
- }
-
- char* tagName;
-
-/*
- * Presently HAVE_STRNDUP is never defined, so the second case is always taken
- * Darwin doesn't have strndup, everything else does
- */
-#ifdef HAVE_STRNDUP
- tagName = strndup(filterExpression, tagNameLength);
-#else
- /* a few extra bytes copied... */
- tagName = strdup(filterExpression);
- tagName[tagNameLength] = '\0';
-#endif /*HAVE_STRNDUP*/
-
- FilterInfo* p_fi = filterinfo_new(tagName, pri);
- free(tagName);
-
- p_fi->p_next = p_format->filters;
- p_format->filters = p_fi;
- }
-
- return 0;
-error:
- return -1;
-}
-
-#ifndef HAVE_STRSEP
-/* KISS replacement helper for below */
-static char* strsep(char** stringp, const char* delim) {
- char* token;
- char* ret = *stringp;
-
- if (!ret || !*ret) {
- return NULL;
- }
- token = strpbrk(ret, delim);
- if (token) {
- *token = '\0';
- ++token;
- } else {
- token = ret + strlen(ret);
- }
- *stringp = token;
- return ret;
-}
-#endif
-
-/**
- * filterString: a comma/whitespace-separated set of filter expressions
- *
- * eg "AT:d *:i"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-int android_log_addFilterString(AndroidLogFormat* p_format, const char* filterString) {
- char* filterStringCopy = strdup(filterString);
- char* p_cur = filterStringCopy;
- char* p_ret;
- int err;
-
- /* Yes, I'm using strsep */
- while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- /* ignore whitespace-only entries */
- if (p_ret[0] != '\0') {
- err = android_log_addFilterRule(p_format, p_ret);
-
- if (err < 0) {
- goto error;
- }
- }
- }
-
- free(filterStringCopy);
- return 0;
-error:
- free(filterStringCopy);
- return -1;
-}
-
-/**
- * Splits a wire-format buffer into an AndroidLogEntry
- * entry allocated by caller. Pointers will point directly into buf
- *
- * Returns 0 on success and -1 on invalid wire format (entry will be
- * in unspecified state)
- */
-int android_log_processLogBuffer(struct logger_entry* buf, AndroidLogEntry* entry) {
- entry->message = NULL;
- entry->messageLen = 0;
-
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
-
- /*
- * format: <priority:1><tag:N>\0<message:N>\0
- *
- * tag str
- * starts at buf + buf->hdr_size + 1
- * msg
- * starts at buf + buf->hdr_size + 1 + len(tag) + 1
- *
- * The message may have been truncated. When that happens, we must null-terminate the message
- * ourselves.
- */
- if (buf->len < 3) {
- /*
- * An well-formed entry must consist of at least a priority
- * and two null characters
- */
- fprintf(stderr, "+++ LOG: entry too small\n");
- return -1;
- }
-
- int msgStart = -1;
- int msgEnd = -1;
-
- int i;
- if (buf->hdr_size < sizeof(logger_entry)) {
- fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
- return -1;
- }
- char* msg = reinterpret_cast<char*>(buf) + buf->hdr_size;
- entry->uid = buf->uid;
-
- for (i = 1; i < buf->len; i++) {
- if (msg[i] == '\0') {
- if (msgStart == -1) {
- msgStart = i + 1;
- } else {
- msgEnd = i;
- break;
- }
- }
- }
-
- if (msgStart == -1) {
- /* +++ LOG: malformed log message, DYB */
- for (i = 1; i < buf->len; i++) {
- /* odd characters in tag? */
- if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
- msg[i] = '\0';
- msgStart = i + 1;
- break;
- }
- }
- if (msgStart == -1) {
- msgStart = buf->len - 1; /* All tag, no message, print truncates */
- }
- }
- if (msgEnd == -1) {
- /* incoming message not null-terminated; force it */
- msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
- msg[msgEnd] = '\0';
- }
-
- entry->priority = static_cast<android_LogPriority>(msg[0]);
- entry->tag = msg + 1;
- entry->tagLen = msgStart - 1;
- entry->message = msg + msgStart;
- entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
-
- return 0;
-}
-
-static bool findChar(const char** cp, size_t* len, int c) {
- while ((*len) && isspace(*(*cp))) {
- ++(*cp);
- --(*len);
- }
- if (c == INT_MAX) return *len;
- if ((*len) && (*(*cp) == c)) {
- ++(*cp);
- --(*len);
- return true;
- }
- return false;
-}
-
-/*
- * Recursively convert binary log data to printable form.
- *
- * This needs to be recursive because you can have lists of lists.
- *
- * If we run out of room, we stop processing immediately. It's important
- * for us to check for space on every output element to avoid producing
- * garbled output.
- *
- * Returns 0 on success, 1 on buffer full, -1 on failure.
- */
-enum objectType {
- TYPE_OBJECTS = '1',
- TYPE_BYTES = '2',
- TYPE_MILLISECONDS = '3',
- TYPE_ALLOCATIONS = '4',
- TYPE_ID = '5',
- TYPE_PERCENT = '6',
- TYPE_MONOTONIC = 's'
-};
-
-static int android_log_printBinaryEvent(const unsigned char** pEventData, size_t* pEventDataLen,
- char** pOutBuf, size_t* pOutBufLen, const char** fmtStr,
- size_t* fmtLen) {
- const unsigned char* eventData = *pEventData;
- size_t eventDataLen = *pEventDataLen;
- char* outBuf = *pOutBuf;
- char* outBufSave = outBuf;
- size_t outBufLen = *pOutBufLen;
- size_t outBufLenSave = outBufLen;
- unsigned char type;
- size_t outCount = 0;
- int result = 0;
- const char* cp;
- size_t len;
- int64_t lval;
-
- if (eventDataLen < 1) return -1;
-
- type = *eventData;
-
- cp = NULL;
- len = 0;
- if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
- cp = *fmtStr;
- len = *fmtLen;
- }
- /*
- * event.logtag format specification:
- *
- * Optionally, after the tag names can be put a description for the value(s)
- * of the tag. Description are in the format
- * (<name>|data type[|data unit])
- * Multiple values are separated by commas.
- *
- * The data type is a number from the following values:
- * 1: int
- * 2: long
- * 3: string
- * 4: list
- * 5: float
- *
- * The data unit is a number taken from the following list:
- * 1: Number of objects
- * 2: Number of bytes
- * 3: Number of milliseconds
- * 4: Number of allocations
- * 5: Id
- * 6: Percent
- * s: Number of seconds (monotonic time)
- * Default value for data of type int/long is 2 (bytes).
- */
- if (!cp || !findChar(&cp, &len, '(')) {
- len = 0;
- } else {
- char* outBufLastSpace = NULL;
-
- findChar(&cp, &len, INT_MAX);
- while (len && *cp && (*cp != '|') && (*cp != ')')) {
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- outBufLastSpace = isspace(*cp) ? outBuf : NULL;
- *outBuf = *cp;
- ++outBuf;
- ++cp;
- --outBufLen;
- --len;
- }
- if (outBufLastSpace) {
- outBufLen += outBuf - outBufLastSpace;
- outBuf = outBufLastSpace;
- }
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- if (outBufSave != outBuf) {
- *outBuf = '=';
- ++outBuf;
- --outBufLen;
- }
-
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- static const unsigned char typeTable[] = {EVENT_TYPE_INT, EVENT_TYPE_LONG, EVENT_TYPE_STRING,
- EVENT_TYPE_LIST, EVENT_TYPE_FLOAT};
-
- if ((*cp >= '1') && (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
- (type != typeTable[(size_t)(*cp - '1')]))
- len = 0;
-
- if (len) {
- ++cp;
- --len;
- } else {
- /* reset the format */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- }
- }
- outCount = 0;
- lval = 0;
- switch (type) {
- case EVENT_TYPE_INT:
- /* 32-bit signed int */
- {
- if (eventDataLen < sizeof(android_event_int_t)) return -1;
- auto* event_int = reinterpret_cast<const android_event_int_t*>(eventData);
- lval = event_int->data;
- eventData += sizeof(android_event_int_t);
- eventDataLen -= sizeof(android_event_int_t);
- }
- goto pr_lval;
- case EVENT_TYPE_LONG:
- /* 64-bit signed long */
- if (eventDataLen < sizeof(android_event_long_t)) {
- return -1;
- }
- {
- auto* event_long = reinterpret_cast<const android_event_long_t*>(eventData);
- lval = event_long->data;
- }
- eventData += sizeof(android_event_long_t);
- eventDataLen -= sizeof(android_event_long_t);
- pr_lval:
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
- break;
- case EVENT_TYPE_FLOAT:
- /* float */
- {
- if (eventDataLen < sizeof(android_event_float_t)) return -1;
- auto* event_float = reinterpret_cast<const android_event_float_t*>(eventData);
- float fval = event_float->data;
- eventData += sizeof(android_event_int_t);
- eventDataLen -= sizeof(android_event_int_t);
-
- outCount = snprintf(outBuf, outBufLen, "%f", fval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
- }
- break;
- case EVENT_TYPE_STRING:
- /* UTF-8 chars, not NULL-terminated */
- {
- if (eventDataLen < sizeof(android_event_string_t)) return -1;
- auto* event_string = reinterpret_cast<const android_event_string_t*>(eventData);
- unsigned int strLen = event_string->length;
- eventData += sizeof(android_event_string_t);
- eventDataLen -= sizeof(android_event_string_t);
-
- if (eventDataLen < strLen) {
- result = -1; /* mark truncated */
- strLen = eventDataLen;
- }
-
- if (cp && (strLen == 0)) {
- /* reset the format if no content */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- if (strLen < outBufLen) {
- memcpy(outBuf, eventData, strLen);
- outBuf += strLen;
- outBufLen -= strLen;
- } else {
- if (outBufLen > 0) {
- /* copy what we can */
- memcpy(outBuf, eventData, outBufLen);
- outBuf += outBufLen;
- outBufLen -= outBufLen;
- }
- if (!result) result = 1; /* if not truncated, return no room */
- }
- eventData += strLen;
- eventDataLen -= strLen;
- if (result != 0) goto bail;
- break;
- }
- case EVENT_TYPE_LIST:
- /* N items, all different types */
- {
- if (eventDataLen < sizeof(android_event_list_t)) return -1;
- auto* event_list = reinterpret_cast<const android_event_list_t*>(eventData);
-
- int8_t count = event_list->element_count;
- eventData += sizeof(android_event_list_t);
- eventDataLen -= sizeof(android_event_list_t);
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = '[';
- outBufLen--;
-
- for (int i = 0; i < count; i++) {
- result = android_log_printBinaryEvent(&eventData, &eventDataLen, &outBuf, &outBufLen,
- fmtStr, fmtLen);
- if (result != 0) goto bail;
-
- if (i < (count - 1)) {
- if (outBufLen <= 0) goto no_room;
- *outBuf++ = ',';
- outBufLen--;
- }
- }
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = ']';
- outBufLen--;
- }
- break;
- default:
- fprintf(stderr, "Unknown binary event type %d\n", type);
- return -1;
- }
- if (cp && len) {
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- switch (*cp) {
- case TYPE_OBJECTS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " objects"); */
- break;
- case TYPE_BYTES:
- if ((lval != 0) && ((lval % 1024) == 0)) {
- /* repaint with multiplier */
- static const char suffixTable[] = {'K', 'M', 'G', 'T'};
- size_t idx = 0;
- outBuf -= outCount;
- outBufLen += outCount;
- do {
- lval /= 1024;
- if ((lval % 1024) != 0) break;
- } while (++idx < ((sizeof(suffixTable) / sizeof(suffixTable[0])) - 1));
- outCount = snprintf(outBuf, outBufLen, "%" PRId64 "%cB", lval, suffixTable[idx]);
- } else {
- outCount = snprintf(outBuf, outBufLen, "B");
- }
- break;
- case TYPE_MILLISECONDS:
- if (((lval <= -1000) || (1000 <= lval)) && (outBufLen || (outBuf[-1] == '0'))) {
- /* repaint as (fractional) seconds, possibly saving space */
- if (outBufLen) outBuf[0] = outBuf[-1];
- outBuf[-1] = outBuf[-2];
- outBuf[-2] = outBuf[-3];
- outBuf[-3] = '.';
- while ((outBufLen == 0) || (*outBuf == '0')) {
- --outBuf;
- ++outBufLen;
- }
- if (*outBuf != '.') {
- ++outBuf;
- --outBufLen;
- }
- outCount = snprintf(outBuf, outBufLen, "s");
- } else {
- outCount = snprintf(outBuf, outBufLen, "ms");
- }
- break;
- case TYPE_MONOTONIC: {
- static const uint64_t minute = 60;
- static const uint64_t hour = 60 * minute;
- static const uint64_t day = 24 * hour;
-
- /* Repaint as unsigned seconds, minutes, hours ... */
- outBuf -= outCount;
- outBufLen += outCount;
- uint64_t val = lval;
- if (val >= day) {
- outCount = snprintf(outBuf, outBufLen, "%" PRIu64 "d ", val / day);
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- val = (val % day) + day;
- }
- if (val >= minute) {
- if (val >= hour) {
- outCount = snprintf(outBuf, outBufLen, "%" PRIu64 ":", (val / hour) % (day / hour));
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- }
- outCount =
- snprintf(outBuf, outBufLen, (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
- (val / minute) % (hour / minute));
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- }
- outCount = snprintf(outBuf, outBufLen, (val >= minute) ? "%02" PRIu64 : "%" PRIu64 "s",
- val % minute);
- } break;
- case TYPE_ALLOCATIONS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
- break;
- case TYPE_ID:
- outCount = 0;
- break;
- case TYPE_PERCENT:
- outCount = snprintf(outBuf, outBufLen, "%%");
- break;
- default: /* ? */
- outCount = 0;
- break;
- }
- ++cp;
- --len;
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else if (outCount) {
- /* halt output */
- goto no_room;
- }
- }
- if (!findChar(&cp, &len, ')')) len = 0;
- if (!findChar(&cp, &len, ',')) len = 0;
- }
-
-bail:
- *pEventData = eventData;
- *pEventDataLen = eventDataLen;
- *pOutBuf = outBuf;
- *pOutBufLen = outBufLen;
- if (cp) {
- *fmtStr = cp;
- *fmtLen = len;
- }
- return result;
-
-no_room:
- result = 1;
- goto bail;
-}
-
-/**
- * Convert a binary log entry to ASCII form.
- *
- * For convenience we mimic the processLogBuffer API. There is no
- * pre-defined output length for the binary data, since we're free to format
- * it however we choose, which means we can't really use a fixed-size buffer
- * here.
- */
-int android_log_processBinaryLogBuffer(
- struct logger_entry* buf, AndroidLogEntry* entry,
- [[maybe_unused]] const EventTagMap* map, /* only on !__ANDROID__ */
- char* messageBuf, int messageBufLen) {
- size_t inCount;
- uint32_t tagIndex;
- const unsigned char* eventData;
-
- entry->message = NULL;
- entry->messageLen = 0;
-
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->priority = ANDROID_LOG_INFO;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
-
- if (buf->hdr_size < sizeof(logger_entry)) {
- fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
- return -1;
- }
- eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
- if (buf->lid == LOG_ID_SECURITY) {
- entry->priority = ANDROID_LOG_WARN;
- }
- entry->uid = buf->uid;
- inCount = buf->len;
- if (inCount < sizeof(android_event_header_t)) return -1;
- auto* event_header = reinterpret_cast<const android_event_header_t*>(eventData);
- tagIndex = event_header->tag;
- eventData += sizeof(android_event_header_t);
- inCount -= sizeof(android_event_header_t);
-
- entry->tagLen = 0;
- entry->tag = NULL;
-#ifdef __ANDROID__
- if (map != NULL) {
- entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
- }
-#endif
-
- /*
- * If we don't have a map, or didn't find the tag number in the map,
- * stuff a generated tag value into the start of the output buffer and
- * shift the buffer pointers down.
- */
- if (entry->tag == NULL) {
- size_t tagLen;
-
- tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
- if (tagLen >= (size_t)messageBufLen) {
- tagLen = messageBufLen - 1;
- }
- entry->tag = messageBuf;
- entry->tagLen = tagLen;
- messageBuf += tagLen + 1;
- messageBufLen -= tagLen + 1;
- }
-
- /*
- * Format the event log data into the buffer.
- */
- const char* fmtStr = NULL;
- size_t fmtLen = 0;
-#ifdef __ANDROID__
- if (descriptive_output && map) {
- fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
- }
-#endif
-
- char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
- int result = 0;
-
- if ((inCount > 0) || fmtLen) {
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining, &fmtStr,
- &fmtLen);
- }
- if ((result == 1) && fmtStr) {
- /* We overflowed :-(, let's repaint the line w/o format dressings */
- eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
- eventData += 4;
- outBuf = messageBuf;
- outRemaining = messageBufLen - 1;
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining, NULL, NULL);
- }
- if (result < 0) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- }
- if (result) {
- if (!outRemaining) {
- /* make space to leave an indicator */
- --outBuf;
- ++outRemaining;
- }
- *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
- outRemaining--;
- /* pretend we ate all the data to prevent log stutter */
- inCount = 0;
- if (result > 0) result = 0;
- }
-
- /* eat the silly terminating '\n' */
- if (inCount == 1 && *eventData == '\n') {
- eventData++;
- inCount--;
- }
-
- if (inCount != 0) {
- fprintf(stderr, "Warning: leftover binary log data (%zu bytes)\n", inCount);
- }
-
- /*
- * Terminate the buffer. The NUL byte does not count as part of
- * entry->messageLen.
- */
- *outBuf = '\0';
- entry->messageLen = outBuf - messageBuf;
- assert(entry->messageLen == (messageBufLen - 1) - outRemaining);
-
- entry->message = messageBuf;
-
- return result;
-}
-
-/*
- * Convert to printable from message to p buffer, return string length. If p is
- * NULL, do not copy, but still return the expected string length.
- */
-size_t convertPrintable(char* p, const char* message, size_t messageLen) {
- char* begin = p;
- bool print = p != NULL;
- mbstate_t mb_state = {};
-
- while (messageLen) {
- char buf[6];
- ssize_t len = sizeof(buf) - 1;
- if ((size_t)len > messageLen) {
- len = messageLen;
- }
- len = mbrtowc(nullptr, message, len, &mb_state);
-
- if (len < 0) {
- snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(*message));
- len = 1;
- } else {
- buf[0] = '\0';
- if (len == 1) {
- if (*message == '\a') {
- strcpy(buf, "\\a");
- } else if (*message == '\b') {
- strcpy(buf, "\\b");
- } else if (*message == '\t') {
- strcpy(buf, "\t"); /* Do not escape tabs */
- } else if (*message == '\v') {
- strcpy(buf, "\\v");
- } else if (*message == '\f') {
- strcpy(buf, "\\f");
- } else if (*message == '\r') {
- strcpy(buf, "\\r");
- } else if (*message == '\\') {
- strcpy(buf, "\\\\");
- } else if ((*message < ' ') || (*message & 0x80)) {
- snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(*message));
- }
- }
- if (!buf[0]) {
- strncpy(buf, message, len);
- buf[len] = '\0';
- }
- }
- if (print) {
- strcpy(p, buf);
- }
- p += strlen(buf);
- message += len;
- messageLen -= len;
- }
- return p - begin;
-}
-
-#ifdef __ANDROID__
-static char* readSeconds(char* e, struct timespec* t) {
- unsigned long multiplier;
- char* p;
- t->tv_sec = strtoul(e, &p, 10);
- if (*p != '.') {
- return NULL;
- }
- t->tv_nsec = 0;
- multiplier = NS_PER_SEC;
- while (isdigit(*++p) && (multiplier /= 10)) {
- t->tv_nsec += (*p - '0') * multiplier;
- }
- return p;
-}
-
-static struct timespec* sumTimespec(struct timespec* left, struct timespec* right) {
- left->tv_nsec += right->tv_nsec;
- left->tv_sec += right->tv_sec;
- if (left->tv_nsec >= (long)NS_PER_SEC) {
- left->tv_nsec -= NS_PER_SEC;
- left->tv_sec += 1;
- }
- return left;
-}
-
-static struct timespec* subTimespec(struct timespec* result, struct timespec* left,
- struct timespec* right) {
- result->tv_nsec = left->tv_nsec - right->tv_nsec;
- result->tv_sec = left->tv_sec - right->tv_sec;
- if (result->tv_nsec < 0) {
- result->tv_nsec += NS_PER_SEC;
- result->tv_sec -= 1;
- }
- return result;
-}
-
-static long long nsecTimespec(struct timespec* now) {
- return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
-}
-
-static void convertMonotonic(struct timespec* result, const AndroidLogEntry* entry) {
- struct listnode* node;
- struct conversionList {
- struct listnode node; /* first */
- struct timespec time;
- struct timespec convert;
- } * list, *next;
- struct timespec time, convert;
-
- /* If we do not have a conversion list, build one up */
- if (list_empty(&convertHead)) {
- bool suspended_pending = false;
- struct timespec suspended_monotonic = {0, 0};
- struct timespec suspended_diff = {0, 0};
-
- /*
- * Read dmesg for _some_ synchronization markers and insert
- * Anything in the Android Logger before the dmesg logging span will
- * be highly suspect regarding the monotonic time calculations.
- */
- FILE* p = popen("/system/bin/dmesg", "re");
- if (p) {
- char* line = NULL;
- size_t len = 0;
- while (getline(&line, &len, p) > 0) {
- static const char suspend[] = "PM: suspend entry ";
- static const char resume[] = "PM: suspend exit ";
- static const char healthd[] = "healthd";
- static const char battery[] = ": battery ";
- static const char suspended[] = "Suspended for ";
- struct timespec monotonic;
- struct tm tm;
- char *cp, *e = line;
- bool add_entry = true;
-
- if (*e == '<') {
- while (*e && (*e != '>')) {
- ++e;
- }
- if (*e != '>') {
- continue;
- }
- }
- if (*e != '[') {
- continue;
- }
- while (*++e == ' ') {
- ;
- }
- e = readSeconds(e, &monotonic);
- if (!e || (*e != ']')) {
- continue;
- }
-
- if ((e = strstr(e, suspend))) {
- e += sizeof(suspend) - 1;
- } else if ((e = strstr(line, resume))) {
- e += sizeof(resume) - 1;
- } else if (((e = strstr(line, healthd))) &&
- ((e = strstr(e + sizeof(healthd) - 1, battery)))) {
- /* NB: healthd is roughly 150us late, worth the price to
- * deal with ntp-induced or hardware clock drift. */
- e += sizeof(battery) - 1;
- } else if ((e = strstr(line, suspended))) {
- e += sizeof(suspended) - 1;
- e = readSeconds(e, &time);
- if (!e) {
- continue;
- }
- add_entry = false;
- suspended_pending = true;
- suspended_monotonic = monotonic;
- suspended_diff = time;
- } else {
- continue;
- }
- if (add_entry) {
- /* look for "????-??-?? ??:??:??.????????? UTC" */
- cp = strstr(e, " UTC");
- if (!cp || ((cp - e) < 29) || (cp[-10] != '.')) {
- continue;
- }
- e = cp - 29;
- cp = readSeconds(cp - 10, &time);
- if (!cp) {
- continue;
- }
- cp = strptime(e, "%Y-%m-%d %H:%M:%S.", &tm);
- if (!cp) {
- continue;
- }
- cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, utc, 1);
- time.tv_sec = mktime(&tm);
- if (cp) {
- setenv(tz, cp, 1);
- free(cp);
- } else {
- unsetenv(tz);
- }
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- subTimespec(&list->convert, &time, &monotonic);
- list_add_tail(&convertHead, &list->node);
- }
- if (suspended_pending && !list_empty(&convertHead)) {
- list = node_to_item(list_tail(&convertHead), struct conversionList, node);
- if (subTimespec(&time, subTimespec(&time, &list->time, &list->convert),
- &suspended_monotonic)
- ->tv_sec > 0) {
- /* resume, what is convert factor before? */
- subTimespec(&convert, &list->convert, &suspended_diff);
- } else {
- /* suspend */
- convert = list->convert;
- }
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just before sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_tail(&convertHead, &list->node);
- /* breakpoint just after sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_tail(&convertHead, &list->node);
- suspended_pending = false;
- }
- }
- pclose(p);
- }
- /* last entry is our current time conversion */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- clock_gettime(CLOCK_REALTIME, &list->time);
- clock_gettime(CLOCK_MONOTONIC, &convert);
- clock_gettime(CLOCK_MONOTONIC, &time);
- /* Correct for instant clock_gettime latency (syscall or ~30ns) */
- subTimespec(&time, &convert, subTimespec(&time, &time, &convert));
- /* Calculate conversion factor */
- subTimespec(&list->convert, &list->time, &time);
- list_add_tail(&convertHead, &list->node);
- if (suspended_pending) {
- /* manufacture a suspend @ point before */
- subTimespec(&convert, &list->convert, &suspended_diff);
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just after sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_head(&convertHead, &list->node);
- /* breakpoint just before sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_head(&convertHead, &list->node);
- }
- }
-
- /* Find the breakpoint in the conversion list */
- list = node_to_item(list_head(&convertHead), struct conversionList, node);
- next = NULL;
- list_for_each(node, &convertHead) {
- next = node_to_item(node, struct conversionList, node);
- if (entry->tv_sec < next->time.tv_sec) {
- break;
- } else if (entry->tv_sec == next->time.tv_sec) {
- if (entry->tv_nsec < next->time.tv_nsec) {
- break;
- }
- }
- list = next;
- }
-
- /* blend time from one breakpoint to the next */
- convert = list->convert;
- if (next) {
- unsigned long long total, run;
-
- total = nsecTimespec(subTimespec(&time, &next->time, &list->time));
- time.tv_sec = entry->tv_sec;
- time.tv_nsec = entry->tv_nsec;
- run = nsecTimespec(subTimespec(&time, &time, &list->time));
- if (run < total) {
- long long crun;
-
- float f = nsecTimespec(subTimespec(&time, &next->convert, &convert));
- f *= run;
- f /= total;
- crun = f;
- convert.tv_sec += crun / (long long)NS_PER_SEC;
- if (crun < 0) {
- convert.tv_nsec -= (-crun) % NS_PER_SEC;
- if (convert.tv_nsec < 0) {
- convert.tv_nsec += NS_PER_SEC;
- convert.tv_sec -= 1;
- }
- } else {
- convert.tv_nsec += crun % NS_PER_SEC;
- if (convert.tv_nsec >= (long)NS_PER_SEC) {
- convert.tv_nsec -= NS_PER_SEC;
- convert.tv_sec += 1;
- }
- }
- }
- }
-
- /* Apply the correction factor */
- result->tv_sec = entry->tv_sec;
- result->tv_nsec = entry->tv_nsec;
- subTimespec(result, result, &convert);
-}
-#endif
-
-/**
- * Formats a log message into a buffer
- *
- * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
- * If return value != defaultBuffer, caller must call free()
- * Returns NULL on malloc error
- */
-
-char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
- size_t defaultBufferSize, const AndroidLogEntry* entry,
- size_t* p_outLength) {
-#if !defined(_WIN32)
- struct tm tmBuf;
-#endif
- struct tm* ptm;
- /* good margin, 23+nul for msec, 26+nul for usec, 29+nul to nsec */
- char timeBuf[64];
- char prefixBuf[128], suffixBuf[128];
- char priChar;
- int prefixSuffixIsHeaderFooter = 0;
- char* ret;
- time_t now;
- unsigned long nsec;
-
- priChar = filterPriToChar(entry->priority);
- size_t prefixLen = 0, suffixLen = 0;
- size_t len;
-
- /*
- * Get the current date/time in pretty form
- *
- * It's often useful when examining a log with "less" to jump to
- * a specific point in the file by searching for the date/time stamp.
- * For this reason it's very annoying to have regexp meta characters
- * in the time stamp. Don't use forward slashes, parenthesis,
- * brackets, asterisks, or other special chars here.
- *
- * The caller may have affected the timezone environment, this is
- * expected to be sensitive to that.
- */
- now = entry->tv_sec;
- nsec = entry->tv_nsec;
-#if __ANDROID__
- if (p_format->monotonic_output) {
- struct timespec time;
- convertMonotonic(&time, entry);
- now = time.tv_sec;
- nsec = time.tv_nsec;
- }
-#endif
- if (now < 0) {
- nsec = NS_PER_SEC - nsec;
- }
- if (p_format->epoch_output || p_format->monotonic_output) {
- ptm = NULL;
- snprintf(timeBuf, sizeof(timeBuf), p_format->monotonic_output ? "%6lld" : "%19lld",
- (long long)now);
- } else {
-#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
- strftime(timeBuf, sizeof(timeBuf), &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3], ptm);
- }
- len = strlen(timeBuf);
- if (p_format->nsec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%09ld", nsec);
- } else if (p_format->usec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%06ld", nsec / US_PER_NSEC);
- } else {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%03ld", nsec / MS_PER_NSEC);
- }
- if (p_format->zone_output && ptm) {
- strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm);
- }
-
- /*
- * Construct a buffer containing the log header and log message.
- */
- if (p_format->colored_output) {
- prefixLen =
- snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[%dm", colorFromPri(entry->priority));
- prefixLen = MIN(prefixLen, sizeof(prefixBuf));
-
- const char suffixContents[] = "\x1B[0m";
- strcpy(suffixBuf, suffixContents);
- suffixLen = strlen(suffixContents);
- }
-
- char uid[16];
- uid[0] = '\0';
- if (p_format->uid_output) {
- if (entry->uid >= 0) {
-/*
- * This code is Android specific, bionic guarantees that
- * calls to non-reentrant getpwuid() are thread safe.
- */
-#ifdef __ANDROID__
- struct passwd* pwd = getpwuid(entry->uid);
- if (pwd && (strlen(pwd->pw_name) <= 5)) {
- snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
- } else
-#endif
- {
- /* Not worth parsing package list, names all longer than 5 */
- snprintf(uid, sizeof(uid), "%5d:", entry->uid);
- }
- } else {
- snprintf(uid, sizeof(uid), " ");
- }
- }
-
- switch (p_format->format) {
- case FORMAT_TAG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8.*s: ", priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_PROCESS:
- len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen, " (%.*s)\n",
- (int)entry->tagLen, entry->tag);
- suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%s%5d) ", priChar,
- uid, entry->pid);
- break;
- case FORMAT_THREAD:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%s%5d:%5d) ",
- priChar, uid, entry->pid, entry->tid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_RAW:
- prefixBuf[prefixLen] = 0;
- len = 0;
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_TIME:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar, (int)entry->tagLen, entry->tag, uid,
- entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_THREADTIME:
- ret = strchr(uid, ':');
- if (ret) {
- *ret = ' ';
- }
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid, entry->tid, priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_LONG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "[ %s %s%5d:%5d %c/%-8.*s ]\n", timeBuf, uid, entry->pid, entry->tid, priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n\n");
- suffixLen += 2;
- prefixSuffixIsHeaderFooter = 1;
- break;
- case FORMAT_BRIEF:
- default:
- len =
- snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag, uid, entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- }
-
- /* snprintf has a weird return value. It returns what would have been
- * written given a large enough buffer. In the case that the prefix is
- * longer then our buffer(128), it messes up the calculations below
- * possibly causing heap corruption. To avoid this we double check and
- * set the length at the maximum (size minus null byte)
- */
- prefixLen += len;
- if (prefixLen >= sizeof(prefixBuf)) {
- prefixLen = sizeof(prefixBuf) - 1;
- prefixBuf[sizeof(prefixBuf) - 1] = '\0';
- }
- if (suffixLen >= sizeof(suffixBuf)) {
- suffixLen = sizeof(suffixBuf) - 1;
- suffixBuf[sizeof(suffixBuf) - 2] = '\n';
- suffixBuf[sizeof(suffixBuf) - 1] = '\0';
- }
-
- /* the following code is tragically unreadable */
-
- size_t numLines;
- char* p;
- size_t bufferSize;
- const char* pm;
-
- if (prefixSuffixIsHeaderFooter) {
- /* we're just wrapping message with a header/footer */
- numLines = 1;
- } else {
- pm = entry->message;
- numLines = 0;
-
- /*
- * The line-end finding here must match the line-end finding
- * in for ( ... numLines...) loop below
- */
- while (pm < (entry->message + entry->messageLen)) {
- if (*pm++ == '\n') numLines++;
- }
- /* plus one line for anything not newline-terminated at the end */
- if (pm > entry->message && *(pm - 1) != '\n') numLines++;
- }
-
- /*
- * this is an upper bound--newlines in message may be counted
- * extraneously
- */
- bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
- if (p_format->printable_output) {
- /* Calculate extra length to convert non-printable to printable */
- bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
- } else {
- bufferSize += entry->messageLen;
- }
-
- if (defaultBufferSize >= bufferSize) {
- ret = defaultBuffer;
- } else {
- ret = (char*)malloc(bufferSize);
-
- if (ret == NULL) {
- return ret;
- }
- }
-
- ret[0] = '\0'; /* to start strcat off */
-
- p = ret;
- pm = entry->message;
-
- if (prefixSuffixIsHeaderFooter) {
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, entry->message, entry->messageLen);
- } else {
- strncat(p, entry->message, entry->messageLen);
- p += entry->messageLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
- } else {
- do {
- const char* lineStart;
- size_t lineLen;
- lineStart = pm;
-
- /* Find the next end-of-line in message */
- while (pm < (entry->message + entry->messageLen) && *pm != '\n') pm++;
- lineLen = pm - lineStart;
-
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, lineStart, lineLen);
- } else {
- strncat(p, lineStart, lineLen);
- p += lineLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
-
- if (*pm == '\n') pm++;
- } while (pm < (entry->message + entry->messageLen));
- }
-
- if (p_outLength != NULL) {
- *p_outLength = p - ret;
- }
-
- return ret;
-}
-
-/**
- * Either print or do not print log line, based on filter
- *
- * Returns count bytes written
- */
-
-int android_log_printLogLine(AndroidLogFormat* p_format, int fd, const AndroidLogEntry* entry) {
- int ret;
- char defaultBuffer[512];
- char* outBuffer = NULL;
- size_t totalLen;
-
- outBuffer =
- android_log_formatLogLine(p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);
-
- if (!outBuffer) return -1;
-
- do {
- ret = write(fd, outBuffer, totalLen);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0) {
- fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
- ret = 0;
- goto done;
- }
-
- if (((size_t)ret) < totalLen) {
- fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret, (int)totalLen);
- goto done;
- }
-
-done:
- if (outBuffer != defaultBuffer) {
- free(outBuffer);
- }
-
- return ret;
-}
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
deleted file mode 100644
index 5640900..0000000
--- a/liblog/pmsg_reader.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 "pmsg_reader.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <cutils/list.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-
-int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg) {
- ssize_t ret;
- off_t current, next;
- struct __attribute__((__packed__)) {
- android_pmsg_log_header_t p;
- android_log_header_t l;
- uint8_t prio;
- } buf;
- static uint8_t preread_count;
-
- memset(log_msg, 0, sizeof(*log_msg));
-
- if (atomic_load(&logger_list->fd) <= 0) {
- int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
-
- if (fd < 0) {
- return -errno;
- }
- if (fd == 0) { /* Argggg */
- fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
- close(0);
- if (fd < 0) {
- return -errno;
- }
- }
- i = atomic_exchange(&logger_list->fd, fd);
- if ((i > 0) && (i != fd)) {
- close(i);
- }
- preread_count = 0;
- }
-
- while (1) {
- int fd;
-
- if (preread_count < sizeof(buf)) {
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, &buf.p.magic + preread_count, sizeof(buf) - preread_count));
- if (ret < 0) {
- return -errno;
- }
- preread_count += ret;
- }
- if (preread_count != sizeof(buf)) {
- return preread_count ? -EIO : -EAGAIN;
- }
- if ((buf.p.magic != LOGGER_MAGIC) || (buf.p.len <= sizeof(buf)) ||
- (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) || (buf.l.id >= LOG_ID_MAX) ||
- (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
- ((buf.l.id != LOG_ID_EVENTS) && (buf.l.id != LOG_ID_SECURITY) &&
- ((buf.prio == ANDROID_LOG_UNKNOWN) || (buf.prio == ANDROID_LOG_DEFAULT) ||
- (buf.prio >= ANDROID_LOG_SILENT)))) {
- do {
- memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
- } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
- continue;
- }
- preread_count = 0;
-
- if ((logger_list->log_mask & (1 << buf.l.id)) &&
- ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
- ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
- ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
- (logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
- (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
- char* msg = reinterpret_cast<char*>(&log_msg->entry) + sizeof(log_msg->entry);
- *msg = buf.prio;
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, msg + sizeof(buf.prio), buf.p.len - sizeof(buf)));
- if (ret < 0) {
- return -errno;
- }
- if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
-
- log_msg->entry.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
- log_msg->entry.hdr_size = sizeof(log_msg->entry);
- log_msg->entry.pid = buf.p.pid;
- log_msg->entry.tid = buf.l.tid;
- log_msg->entry.sec = buf.l.realtime.tv_sec;
- log_msg->entry.nsec = buf.l.realtime.tv_nsec;
- log_msg->entry.lid = buf.l.id;
- log_msg->entry.uid = buf.p.uid;
-
- return ret + sizeof(buf.prio) + log_msg->entry.hdr_size;
- }
-
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
- if (current < 0) {
- return -errno;
- }
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- next = TEMP_FAILURE_RETRY(lseek(fd, (off_t)(buf.p.len - sizeof(buf)), SEEK_CUR));
- if (next < 0) {
- return -errno;
- }
- if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
- }
-}
-
-void PmsgClose(struct logger_list* logger_list) {
- int fd = atomic_exchange(&logger_list->fd, 0);
- if (fd > 0) {
- close(fd);
- }
-}
-
-static void* realloc_or_free(void* ptr, size_t new_size) {
- void* result = realloc(ptr, new_size);
- if (!result) {
- free(ptr);
- }
- return result;
-}
-
-ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
- __android_log_pmsg_file_read_fn fn, void* arg) {
- ssize_t ret;
- struct logger_list logger_list;
- struct content {
- struct listnode node;
- struct logger_entry entry;
- } * content;
- struct names {
- struct listnode node;
- struct listnode content;
- log_id_t id;
- char prio;
- char name[];
- } * names;
- struct listnode name_list;
- struct listnode *node, *n;
- size_t len, prefix_len;
-
- if (!fn) {
- return -EINVAL;
- }
-
- /* Add just enough clues in logger_list and transp to make API function */
- memset(&logger_list, 0, sizeof(logger_list));
-
- logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
- logger_list.log_mask = (unsigned)-1;
- if (logId != LOG_ID_ANY) {
- logger_list.log_mask = (1 << logId);
- }
- logger_list.log_mask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
- if (!logger_list.log_mask) {
- return -EINVAL;
- }
-
- /* Initialize name list */
- list_init(&name_list);
-
- ret = SSIZE_MAX;
-
- /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
- prefix_len = 0;
- if (prefix) {
- const char *prev = NULL, *last = NULL, *cp = prefix;
- while ((cp = strpbrk(cp, "/:"))) {
- prev = last;
- last = cp;
- cp = cp + 1;
- }
- if (prev) {
- prefix = prev + 1;
- }
- prefix_len = strlen(prefix);
- }
-
- /* Read the file content */
- log_msg log_msg;
- while (PmsgRead(&logger_list, &log_msg) > 0) {
- const char* cp;
- size_t hdr_size = log_msg.entry.hdr_size;
-
- char* msg = (char*)&log_msg + hdr_size;
- const char* split = NULL;
-
- if (hdr_size != sizeof(log_msg.entry)) {
- continue;
- }
- /* Check for invalid sequence number */
- if (log_msg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE ||
- (log_msg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
- ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
- continue;
- }
-
- /* Determine if it has <dirbase>:<filebase> format for tag */
- len = log_msg.entry.len - sizeof(prio);
- for (cp = msg + sizeof(prio); *cp && isprint(*cp) && !isspace(*cp) && --len; ++cp) {
- if (*cp == ':') {
- if (split) {
- break;
- }
- split = cp;
- }
- }
- if (*cp || !split) {
- continue;
- }
-
- /* Filters */
- if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
- size_t offset;
- /*
- * Allow : to be a synonym for /
- * Things we do dealing with const char * and do not alloc
- */
- split = strchr(prefix, ':');
- if (split) {
- continue;
- }
- split = strchr(prefix, '/');
- if (!split) {
- continue;
- }
- offset = split - prefix;
- if ((msg[offset + sizeof(prio)] != ':') || strncmp(msg + sizeof(prio), prefix, offset)) {
- continue;
- }
- ++offset;
- if ((prefix_len > offset) &&
- strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
- continue;
- }
- }
-
- if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
- continue;
- }
-
- /* check if there is an existing entry */
- list_for_each(node, &name_list) {
- names = node_to_item(node, struct names, node);
- if (!strcmp(names->name, msg + sizeof(prio)) && names->id == log_msg.entry.lid &&
- names->prio == *msg) {
- break;
- }
- }
-
- /* We do not have an existing entry, create and add one */
- if (node == &name_list) {
- static const char numbers[] = "0123456789";
- unsigned long long nl;
-
- len = strlen(msg + sizeof(prio)) + 1;
- names = static_cast<struct names*>(calloc(1, sizeof(*names) + len));
- if (!names) {
- ret = -ENOMEM;
- break;
- }
- strcpy(names->name, msg + sizeof(prio));
- names->id = static_cast<log_id_t>(log_msg.entry.lid);
- names->prio = *msg;
- list_init(&names->content);
- /*
- * Insert in reverse numeric _then_ alpha sorted order as
- * representative of log rotation:
- *
- * log.10
- * klog.10
- * . . .
- * log.2
- * klog.2
- * log.1
- * klog.1
- * log
- * klog
- *
- * thus when we present the content, we are provided the oldest
- * first, which when 'refreshed' could spill off the end of the
- * pmsg FIFO but retaining the newest data for last with best
- * chances to survive.
- */
- nl = 0;
- cp = strpbrk(names->name, numbers);
- if (cp) {
- nl = strtoull(cp, NULL, 10);
- }
- list_for_each_reverse(node, &name_list) {
- struct names* a_name = node_to_item(node, struct names, node);
- const char* r = a_name->name;
- int compare = 0;
-
- unsigned long long nr = 0;
- cp = strpbrk(r, numbers);
- if (cp) {
- nr = strtoull(cp, NULL, 10);
- }
- if (nr != nl) {
- compare = (nl > nr) ? 1 : -1;
- }
- if (compare == 0) {
- compare = strcmp(names->name, r);
- }
- if (compare <= 0) {
- break;
- }
- }
- list_add_head(node, &names->node);
- }
-
- /* Remove any file fragments that match our sequence number */
- list_for_each_safe(node, n, &names->content) {
- content = node_to_item(node, struct content, node);
- if (log_msg.entry.nsec == content->entry.nsec) {
- list_remove(&content->node);
- free(content);
- }
- }
-
- /* Add content */
- content = static_cast<struct content*>(
- calloc(1, sizeof(content->node) + hdr_size + log_msg.entry.len));
- if (!content) {
- ret = -ENOMEM;
- break;
- }
- memcpy(&content->entry, &log_msg.entry, hdr_size + log_msg.entry.len);
-
- /* Insert in sequence number sorted order, to ease reconstruction */
- list_for_each_reverse(node, &names->content) {
- if ((node_to_item(node, struct content, node))->entry.nsec < log_msg.entry.nsec) {
- break;
- }
- }
- list_add_head(node, &content->node);
- }
- PmsgClose(&logger_list);
-
- /* Progress through all the collected files */
- list_for_each_safe(node, n, &name_list) {
- struct listnode *content_node, *m;
- char* buf;
- size_t sequence, tag_len;
-
- names = node_to_item(node, struct names, node);
-
- /* Construct content into a linear buffer */
- buf = NULL;
- len = 0;
- sequence = 0;
- tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
- list_for_each_safe(content_node, m, &names->content) {
- ssize_t add_len;
-
- content = node_to_item(content_node, struct content, node);
- add_len = content->entry.len - tag_len - sizeof(prio);
- if (add_len <= 0) {
- list_remove(content_node);
- free(content);
- continue;
- }
-
- if (!buf) {
- buf = static_cast<char*>(malloc(sizeof(char)));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- *buf = '\0';
- }
-
- /* Missing sequence numbers */
- while (sequence < content->entry.nsec) {
- /* plus space for enforced nul */
- buf = static_cast<char*>(realloc_or_free(buf, len + sizeof(char) + sizeof(char)));
- if (!buf) {
- break;
- }
- buf[len] = '\f'; /* Mark missing content with a form feed */
- buf[++len] = '\0';
- sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
- }
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- /* plus space for enforced nul */
- buf = static_cast<char*>(realloc_or_free(buf, len + add_len + sizeof(char)));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- memcpy(buf + len, (char*)&content->entry + content->entry.hdr_size + tag_len + sizeof(prio),
- add_len);
- len += add_len;
- buf[len] = '\0'; /* enforce trailing hidden nul */
- sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
-
- list_remove(content_node);
- free(content);
- }
- if (buf) {
- if (len) {
- /* Buffer contains enforced trailing nul just beyond length */
- ssize_t r;
- *strchr(names->name, ':') = '/'; /* Convert back to filename */
- r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
- if ((ret >= 0) && (r > 0)) {
- if (ret == SSIZE_MAX) {
- ret = r;
- } else {
- ret += r;
- }
- } else if (r < ret) {
- ret = r;
- }
- }
- free(buf);
- }
- list_remove(node);
- free(names);
- }
- return (ret == SSIZE_MAX) ? -ENOENT : ret;
-}
diff --git a/liblog/pmsg_reader.h b/liblog/pmsg_reader.h
deleted file mode 100644
index b784f9f..0000000
--- a/liblog/pmsg_reader.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2019 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 <sys/cdefs.h>
-#include <unistd.h>
-
-#include "log/log_read.h"
-
-__BEGIN_DECLS
-
-int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg);
-void PmsgClose(struct logger_list* logger_list);
-
-__END_DECLS
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
deleted file mode 100644
index 8e676bd..0000000
--- a/liblog/pmsg_writer.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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 "pmsg_writer.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <log/log_properties.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-#include "uio.h"
-
-static atomic_int pmsg_fd;
-
-// pmsg_fd should only beopened once. If we see that pmsg_fd is uninitialized, we open "/dev/pmsg0"
-// then attempt to compare/exchange it into pmsg_fd. If the compare/exchange was successful, then
-// that will be the fd used for the duration of the program, otherwise a different thread has
-// already opened and written the fd to the atomic, so close the new fd and return.
-static void GetPmsgFd() {
- if (pmsg_fd != 0) {
- return;
- }
-
- int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (new_fd <= 0) {
- return;
- }
-
- int uninitialized_value = 0;
- if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
- close(new_fd);
- return;
- }
-}
-
-void PmsgClose() {
- if (pmsg_fd > 0) {
- close(pmsg_fd);
- }
- pmsg_fd = 0;
-}
-
-int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
- static const unsigned headerLength = 2;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- android_pmsg_log_header_t pmsgHeader;
- size_t i, payloadSize;
- ssize_t ret;
-
- if (!__android_log_is_debuggable()) {
- if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
- return -1;
- }
-
- if (logId == LOG_ID_EVENTS) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
- return -EPERM;
- }
- }
- }
-
- GetPmsgFd();
-
- if (pmsg_fd <= 0) {
- return -EBADF;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsgHeader;
- * // what we provide to file
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- pmsgHeader.magic = LOGGER_MAGIC;
- pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
- pmsgHeader.uid = getuid();
- pmsgHeader.pid = getpid();
-
- header.id = logId;
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&pmsgHeader;
- newVec[0].iov_len = sizeof(pmsgHeader);
- newVec[1].iov_base = (unsigned char*)&header;
- newVec[1].iov_len = sizeof(header);
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
- break;
- }
- }
- pmsgHeader.len += payloadSize;
-
- ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
- if (ret < 0) {
- ret = errno ? -errno : -ENOTCONN;
- }
-
- if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
- ret -= sizeof(header) - sizeof(pmsgHeader);
- }
-
- return ret;
-}
-
-/*
- * Virtual pmsg filesystem
- *
- * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
- * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
- * file.
- *
- * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
- */
-
-static inline const char* strnrchr(const char* buf, size_t len, char c) {
- const char* cp = buf + len;
- while ((--cp > buf) && (*cp != c))
- ;
- if (cp <= buf) {
- return buf + len;
- }
- return cp;
-}
-
-/* Write a buffer as filename references (tag = <basedir>:<basename>) */
-ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
- const char* buf, size_t len) {
- size_t length, packet_len;
- const char* tag;
- char *cp, *slash;
- struct timespec ts;
- struct iovec vec[3];
-
- /* Make sure the logId value is not a bad idea */
- if ((logId == LOG_ID_KERNEL) || /* Verbotten */
- (logId == LOG_ID_EVENTS) || /* Do not support binary content */
- (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
- ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
- return -EINVAL;
- }
-
- clock_gettime(CLOCK_REALTIME, &ts);
-
- cp = strdup(filename);
- if (!cp) {
- return -ENOMEM;
- }
-
- tag = cp;
- slash = strrchr(cp, '/');
- if (slash) {
- *slash = ':';
- slash = strrchr(cp, '/');
- if (slash) {
- tag = slash + 1;
- }
- }
-
- length = strlen(tag) + 1;
- packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
-
- vec[0].iov_base = &prio;
- vec[0].iov_len = sizeof(char);
- vec[1].iov_base = (unsigned char*)tag;
- vec[1].iov_len = length;
-
- for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
- ssize_t ret;
- size_t transfer;
-
- if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
- len -= length;
- break;
- }
-
- transfer = length;
- if (transfer > packet_len) {
- transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
- if ((transfer < length) && (buf[transfer] == '\n')) {
- ++transfer;
- }
- }
-
- vec[2].iov_base = (unsigned char*)buf;
- vec[2].iov_len = transfer;
-
- ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
-
- if (ret <= 0) {
- free(cp);
- return ret ? ret : (len - length);
- }
- length -= transfer;
- buf += transfer;
- }
- free(cp);
- return len;
-}
diff --git a/liblog/pmsg_writer.h b/liblog/pmsg_writer.h
deleted file mode 100644
index d5e1a1c..0000000
--- a/liblog/pmsg_writer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 <stddef.h>
-
-#include <android/log.h>
-
-int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-void PmsgClose();
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
deleted file mode 100644
index 88f0bf1..0000000
--- a/liblog/properties.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
-** Copyright 2014, 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 <log/log_properties.h>
-
-#include <ctype.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <private/android_logger.h>
-
-#include "logger_write.h"
-
-#ifdef __ANDROID__
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
-
-static int lock() {
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- /*
- * Any contention, and we can turn around and use the non-cached method
- * in less time than the system call associated with a mutex to deal with
- * the contention.
- */
- return pthread_mutex_trylock(&lock_loggable);
-}
-
-static void unlock() {
- pthread_mutex_unlock(&lock_loggable);
-}
-
-struct cache {
- const prop_info* pinfo;
- uint32_t serial;
-};
-
-struct cache_char {
- struct cache cache;
- unsigned char c;
-};
-
-static int check_cache(struct cache* cache) {
- return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
-}
-
-#define BOOLEAN_TRUE 0xFF
-#define BOOLEAN_FALSE 0xFE
-
-static void refresh_cache(struct cache_char* cache, const char* key) {
- char buf[PROP_VALUE_MAX];
-
- if (!cache->cache.pinfo) {
- cache->cache.pinfo = __system_property_find(key);
- if (!cache->cache.pinfo) {
- return;
- }
- }
- cache->cache.serial = __system_property_serial(cache->cache.pinfo);
- __system_property_read(cache->cache.pinfo, 0, buf);
- switch (buf[0]) {
- case 't':
- case 'T':
- cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
- break;
- case 'f':
- case 'F':
- cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
- break;
- default:
- cache->c = buf[0];
- }
-}
-
-static int __android_log_level(const char* tag, size_t len) {
- /* sizeof() is used on this array below */
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
-
- if (tag == nullptr || len == 0) {
- auto& tag_string = GetDefaultTag();
- tag = tag_string.c_str();
- len = tag_string.size();
- }
-
- /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + len];
- char* kp;
- size_t i;
- char c = 0;
- /*
- * Single layer cache of four properties. Priorities are:
- * log.tag.<tag>
- * persist.log.tag.<tag>
- * log.tag
- * persist.log.tag
- * Where the missing tag matches all tags and becomes the
- * system global default. We do not support ro.log.tag* .
- */
- static char* last_tag;
- static size_t last_tag_len;
- static uint32_t global_serial;
- /* some compilers erroneously see uninitialized use. !not_locked */
- uint32_t current_global_serial = 0;
- static struct cache_char tag_cache[2];
- static struct cache_char global_cache[2];
- int change_detected;
- int global_change_detected;
- int not_locked;
-
- strcpy(key, log_namespace);
-
- global_change_detected = change_detected = not_locked = lock();
-
- if (!not_locked) {
- /*
- * check all known serial numbers to changes.
- */
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- if (check_cache(&tag_cache[i].cache)) {
- change_detected = 1;
- }
- }
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- if (check_cache(&global_cache[i].cache)) {
- global_change_detected = 1;
- }
- }
-
- current_global_serial = __system_property_area_serial();
- if (current_global_serial != global_serial) {
- change_detected = 1;
- global_change_detected = 1;
- }
- }
-
- if (len) {
- int local_change_detected = change_detected;
- if (!not_locked) {
- if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
- strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {
- /* invalidate log.tag.<tag> cache */
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- tag_cache[i].cache.pinfo = NULL;
- tag_cache[i].c = '\0';
- }
- if (last_tag) last_tag[0] = '\0';
- local_change_detected = 1;
- }
- if (!last_tag || !last_tag[0]) {
- if (!last_tag) {
- last_tag = static_cast<char*>(calloc(1, len + 1));
- last_tag_len = 0;
- if (last_tag) last_tag_len = len + 1;
- } else if (len >= last_tag_len) {
- last_tag = static_cast<char*>(realloc(last_tag, len + 1));
- last_tag_len = 0;
- if (last_tag) last_tag_len = len + 1;
- }
- if (last_tag) {
- strncpy(last_tag, tag, len);
- last_tag[len] = '\0';
- }
- }
- }
- strncpy(key + sizeof(log_namespace) - 1, tag, len);
- key[sizeof(log_namespace) - 1 + len] = '\0';
-
- kp = key;
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- struct cache_char* cache = &tag_cache[i];
- struct cache_char temp_cache;
-
- if (not_locked) {
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- cache = &temp_cache;
- }
- if (local_change_detected) {
- refresh_cache(cache, kp);
- }
-
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
- }
- }
-
- switch (toupper(c)) { /* if invalid, resort to global */
- case 'V':
- case 'D':
- case 'I':
- case 'W':
- case 'E':
- case 'F': /* Not officially supported */
- case 'A':
- case 'S':
- case BOOLEAN_FALSE: /* Not officially supported */
- break;
- default:
- /* clear '.' after log.tag */
- key[sizeof(log_namespace) - 2] = '\0';
-
- kp = key;
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- struct cache_char* cache = &global_cache[i];
- struct cache_char temp_cache;
-
- if (not_locked) {
- temp_cache = *cache;
- if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- }
- cache = &temp_cache;
- }
- if (global_change_detected) {
- refresh_cache(cache, kp);
- }
-
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
- }
- break;
- }
-
- if (!not_locked) {
- global_serial = current_global_serial;
- unlock();
- }
-
- switch (toupper(c)) {
- /* clang-format off */
- case 'V': return ANDROID_LOG_VERBOSE;
- case 'D': return ANDROID_LOG_DEBUG;
- case 'I': return ANDROID_LOG_INFO;
- case 'W': return ANDROID_LOG_WARN;
- case 'E': return ANDROID_LOG_ERROR;
- case 'F': /* FALLTHRU */ /* Not officially supported */
- case 'A': return ANDROID_LOG_FATAL;
- case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
- case 'S': return ANDROID_LOG_SILENT;
- /* clang-format on */
- }
- return -1;
-}
-
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
- int minimum_log_priority = __android_log_get_minimum_priority();
- int property_log_level = __android_log_level(tag, len);
-
- if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
- return prio >= std::min(property_log_level, minimum_log_priority);
- } else if (property_log_level >= 0) {
- return prio >= property_log_level;
- } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
- return prio >= minimum_log_priority;
- } else {
- return prio >= default_prio;
- }
-}
-
-int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
- auto len = tag ? strlen(tag) : 0;
- return __android_log_is_loggable_len(prio, tag, len, default_prio);
-}
-
-int __android_log_is_debuggable() {
- static int is_debuggable = [] {
- char value[PROP_VALUE_MAX] = {};
- return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
- }();
-
- return is_debuggable;
-}
-
-/*
- * For properties that are read often, but generally remain constant.
- * Since a change is rare, we will accept a trylock failure gracefully.
- * Use a separate lock from is_loggable to keep contention down b/25563384.
- */
-struct cache2_char {
- pthread_mutex_t lock;
- uint32_t serial;
- const char* key_persist;
- struct cache_char cache_persist;
- const char* key_ro;
- struct cache_char cache_ro;
- unsigned char (*const evaluate)(const struct cache2_char* self);
-};
-
-static inline unsigned char do_cache2_char(struct cache2_char* self) {
- uint32_t current_serial;
- int change_detected;
- unsigned char c;
-
- if (pthread_mutex_trylock(&self->lock)) {
- /* We are willing to accept some race in this context */
- return self->evaluate(self);
- }
-
- change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
- current_serial = __system_property_area_serial();
- if (current_serial != self->serial) {
- change_detected = 1;
- }
- if (change_detected) {
- refresh_cache(&self->cache_persist, self->key_persist);
- refresh_cache(&self->cache_ro, self->key_ro);
- self->serial = current_serial;
- }
- c = self->evaluate(self);
-
- pthread_mutex_unlock(&self->lock);
-
- return c;
-}
-
-/*
- * Security state generally remains constant, but the DO must be able
- * to turn off logging should it become spammy after an attack is detected.
- */
-static unsigned char evaluate_security(const struct cache2_char* self) {
- unsigned char c = self->cache_ro.c;
-
- return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
-}
-
-int __android_log_security() {
- static struct cache2_char security = {
- PTHREAD_MUTEX_INITIALIZER, 0,
- "persist.logd.security", {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
- "ro.organization_owned", {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
- evaluate_security};
-
- return do_cache2_char(&security);
-}
-
-#else
-
-int __android_log_is_loggable(int prio, const char*, int) {
- int minimum_priority = __android_log_get_minimum_priority();
- if (minimum_priority == ANDROID_LOG_DEFAULT) {
- minimum_priority = ANDROID_LOG_INFO;
- }
- return prio >= minimum_priority;
-}
-
-int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
- return __android_log_is_loggable(prio, nullptr, def);
-}
-
-int __android_log_is_debuggable() {
- return 1;
-}
-
-#endif
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
deleted file mode 100644
index 171aafd..0000000
--- a/liblog/tests/Android.bp
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Copyright (C) 2013-2014 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.
-//
-
-// -----------------------------------------------------------------------------
-// Benchmarks.
-// -----------------------------------------------------------------------------
-
-// Build benchmarks for the device. Run with:
-// adb shell liblog-benchmarks
-cc_benchmark {
- name: "liblog-benchmarks",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
- shared_libs: [
- "libm",
- "libbase",
- "libcutils",
- ],
- static_libs: ["liblog"],
- srcs: ["liblog_benchmark.cpp"],
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-cc_defaults {
- name: "liblog-tests-defaults",
-
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
- srcs: [
- "libc_test.cpp",
- "liblog_default_tag.cpp",
- "liblog_global_state.cpp",
- "liblog_test.cpp",
- "log_id_test.cpp",
- "log_radio_test.cpp",
- "log_read_test.cpp",
- "log_system_test.cpp",
- "log_time_test.cpp",
- "log_wrap_test.cpp",
- "logd_writer_test.cpp",
- "logprint_test.cpp",
- ],
- shared_libs: [
- "libcutils",
- "libbase",
- ],
- static_libs: ["liblog"],
- isolated: true,
- require_root: true,
-}
-
-// Build tests for the device (with .so). Run with:
-// adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
-cc_test {
- name: "liblog-unit-tests",
- defaults: ["liblog-tests-defaults"],
-}
-
-cc_test {
- name: "CtsLiblogTestCases",
- defaults: ["liblog-tests-defaults"],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- cflags: ["-DNO_PSTORE"],
- test_suites: [
- "cts",
- "device-tests",
- ],
-}
-
-cc_test_host {
- name: "liblog-host-test",
- static_libs: ["liblog"],
- shared_libs: ["libbase"],
- srcs: [
- "liblog_host_test.cpp",
- "liblog_default_tag.cpp",
- "liblog_global_state.cpp",
- ],
- isolated: true,
-}
diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml
deleted file mode 100644
index fcb46b1..0000000
--- a/liblog/tests/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<configuration description="Config for CTS Logging Library test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="systems" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsLiblogTestCases" />
- <option name="runtime-hint" value="65s" />
- </test>
-</configuration>
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
deleted file mode 100644
index 1f26263..0000000
--- a/liblog/tests/libc_test.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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 <gtest/gtest.h>
-
-#include <errno.h>
-#include <stdio.h>
-
-TEST(libc, __pstore_append) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- if (access("/dev/pmsg0", W_OK) != 0) {
- GTEST_SKIP() << "pmsg0 not found, skipping test";
- }
-
- FILE* fp;
- ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "ae")));
- static const char message[] = "libc.__pstore_append\n";
- ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
- int fflushReturn = fflush(fp);
- int fflushErrno = fflushReturn ? errno : 0;
- ASSERT_EQ(0, fflushReturn);
- ASSERT_EQ(0, fflushErrno);
- int fcloseReturn = fclose(fp);
- int fcloseErrno = fcloseReturn ? errno : 0;
- ASSERT_EQ(0, fcloseReturn);
- ASSERT_EQ(0, fcloseErrno);
- if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver "
- "configured\n");
- }
- if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
- fprintf(stderr,
- "Reboot, ensure string libc.__pstore_append is in "
- "/sys/fs/pstore/pmsg-ramoops-0\n");
- }
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
deleted file mode 100644
index d2f12d6..0000000
--- a/liblog/tests/liblog_benchmark.cpp
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <benchmark/benchmark.h>
-#include <cutils/sockets.h>
-#include <log/event_tag_map.h>
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-BENCHMARK_MAIN();
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are benchmarking, or using this in the emergency
-// signal to stuff a terminating code, we do NOT want to introduce
-// a syscall or usleep on EAGAIN retry.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-/*
- * Measure the fastest rate we can reliabley stuff print messages into
- * the log at high pressure. Expect this to be less than double the process
- * wakeup time (2ms?)
- */
-static void BM_log_maximum_retry(benchmark::State& state) {
- while (state.KeepRunning()) {
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_INFO, "BM_log_maximum_retry", "%" PRIu64,
- state.iterations()));
- }
-}
-BENCHMARK(BM_log_maximum_retry);
-
-/*
- * Measure the fastest rate we can stuff print messages into the log
- * at high pressure. Expect this to be less than double the process wakeup
- * time (2ms?)
- */
-static void BM_log_maximum(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_print(ANDROID_LOG_INFO, "BM_log_maximum", "%" PRIu64, state.iterations());
- }
-}
-BENCHMARK(BM_log_maximum);
-
-/*
- * Measure the time it takes to collect the time using
- * discrete acquisition (state.PauseTiming() to state.ResumeTiming())
- * under light load. Expect this to be a syscall period (2us) or
- * data read time if zero-syscall.
- *
- * vdso support in the kernel and the library can allow
- * clock_gettime to be zero-syscall, but there there does remain some
- * benchmarking overhead to pause and resume; assumptions are both are
- * covered.
- */
-static void BM_clock_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- state.PauseTiming();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_clock_overhead);
-
-static void do_clock_overhead(benchmark::State& state, clockid_t clk_id) {
- timespec t;
- while (state.KeepRunning()) {
- clock_gettime(clk_id, &t);
- }
-}
-
-static void BM_time_clock_gettime_REALTIME(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_REALTIME);
-}
-BENCHMARK(BM_time_clock_gettime_REALTIME);
-
-static void BM_time_clock_gettime_MONOTONIC(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_MONOTONIC);
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC);
-
-static void BM_time_clock_gettime_MONOTONIC_syscall(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC_syscall);
-
-static void BM_time_clock_gettime_MONOTONIC_RAW(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_MONOTONIC_RAW);
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC_RAW);
-
-static void BM_time_clock_gettime_BOOTTIME(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_BOOTTIME);
-}
-BENCHMARK(BM_time_clock_gettime_BOOTTIME);
-
-static void BM_time_clock_getres_MONOTONIC(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- clock_getres(CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_getres_MONOTONIC);
-
-static void BM_time_clock_getres_MONOTONIC_syscall(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- syscall(__NR_clock_getres, CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_getres_MONOTONIC_syscall);
-
-static void BM_time_time(benchmark::State& state) {
- while (state.KeepRunning()) {
- time_t now;
- now = time(&now);
- }
-}
-BENCHMARK(BM_time_time);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- */
-static void BM_pmsg_short(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- android_pmsg_log_header_t pmsg_header;
- pmsg_header.magic = LOGGER_MAGIC;
- pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- pmsg_header.uid = getuid();
- pmsg_header.pid = getpid();
-
- android_log_header_t header;
- header.tid = gettid();
- header.realtime.tv_sec = ts.tv_sec;
- header.realtime.tv_nsec = ts.tv_nsec;
-
- static const unsigned nr = 1;
- static const unsigned header_length = 2;
- struct iovec newVec[nr + header_length];
-
- newVec[0].iov_base = (unsigned char*)&pmsg_header;
- newVec[0].iov_len = sizeof(pmsg_header);
- newVec[1].iov_base = (unsigned char*)&header;
- newVec[1].iov_len = sizeof(header);
-
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = 0;
- buffer.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer.payload.data = snapshot;
-
- newVec[2].iov_base = &buffer;
- newVec[2].iov_len = sizeof(buffer);
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer.payload.data = snapshot;
- writev(pstore_fd, newVec, nr);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_short_aligned(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short_aligned);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_short_unaligned1(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short_unaligned1);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_long_aligned(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_long_aligned);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_long_unaligned1(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_long_unaligned1);
-
-/*
- * Measure the time it takes to form sprintf plus time using
- * discrete acquisition under light load. Expect this to be a syscall period
- * (2us) or sprintf time if zero-syscall time.
- */
-/* helper function */
-static void test_print(const char* fmt, ...) {
- va_list ap;
- char buf[1024];
-
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-}
-
-#define logd_yield() sched_yield() // allow logd to catch up
-#define logd_sleep() usleep(50) // really allow logd to catch up
-
-/* performance test */
-static void BM_sprintf_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- test_print("BM_sprintf_overhead:%" PRIu64, state.iterations());
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_sprintf_overhead);
-
-/*
- * Measure the time it takes to submit the android printing logging call
- * using discrete acquisition discrete acquisition under light load. Expect
- * this to be a dozen or so syscall periods (40us) plus time to run *printf
- */
-static void BM_log_print_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_print(ANDROID_LOG_INFO, "BM_log_overhead", "%" PRIu64, state.iterations());
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_print_overhead);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under light load. Expect this to be a long path
- * to logger to convert the unknown tag (0) into a tagname (less than 200us).
- */
-static void BM_log_event_overhead(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- // log tag number 0 is not known, nor shall it ever be known
- __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_event_overhead);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under light load with a known logtag. Expect
- * this to be a dozen or so syscall periods (less than 40us)
- */
-static void BM_log_event_overhead_42(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- // In system/core/logcat/event.logtags:
- // # These are used for testing, do not modify without updating
- // # tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
- // # system/core/liblog/tests/liblog_benchmark.cpp
- // # system/core/liblog/tests/liblog_test.cpp
- // 42 answer (to life the universe etc|3)
- __android_log_btwrite(42, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_event_overhead_42);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under very-light load (<1% CPU utilization).
- */
-static void BM_log_light_overhead(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- usleep(10000);
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_light_overhead);
-
-static void caught_latency(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-static unsigned long long caught_convert(char* cp) {
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
- return l;
-}
-
-static const int alarm_time = 3;
-
-/*
- * Measure the time it takes for the logd posting call to acquire the
- * timestamp to place into the internal record. Expect this to be less than
- * 4 syscalls (3us). This test uses manual injection of timing because it is
- * comparing the timestamp at send, and then picking up the corresponding log
- * end-to-end long path from logd to see what actual timestamp was submitted.
- */
-static void BM_log_latency(benchmark::State& state) {
- pid_t pid = getpid();
-
- struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
-
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- signal(SIGALRM, caught_latency);
- alarm(alarm_time);
-
- for (size_t j = 0; state.KeepRunning() && j < 10 * state.iterations(); ++j) {
- retry: // We allow transitory errors (logd overloaded) to be retried.
- log_time ts;
- LOG_FAILURE_RETRY((ts = log_time(CLOCK_REALTIME),
- android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
-
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
-
- if (ret <= 0) {
- state.SkipWithError("android_logger_list_read");
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char* eventData = log_msg.msg();
-
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
- if (ts != *tx) {
- if (0xDEADBEEFA55A5AA5ULL == caught_convert(eventData + 4 + 1)) {
- state.SkipWithError("signal");
- break;
- }
- continue;
- }
-
- uint64_t start = ts.nsec();
- uint64_t end = log_msg.nsec();
- if (end < start) goto retry;
- state.SetIterationTime((end - start) / (double)NS_PER_SEC);
- break;
- }
- }
-
- signal(SIGALRM, SIG_DFL);
- alarm(0);
-
- android_logger_list_free(logger_list);
-}
-// Default gets out of hand for this test, so we set a reasonable number of
-// iterations for a timely result.
-BENCHMARK(BM_log_latency)->UseManualTime()->Iterations(200);
-
-static void caught_delay(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-/*
- * Measure the time it takes for the logd posting call to make it into
- * the logs. Expect this to be less than double the process wakeup time (2ms).
- */
-static void BM_log_delay(benchmark::State& state) {
- pid_t pid = getpid();
-
- struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
-
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- signal(SIGALRM, caught_delay);
- alarm(alarm_time);
-
- while (state.KeepRunning()) {
- log_time ts(CLOCK_REALTIME);
-
- LOG_FAILURE_RETRY(android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
-
- if (ret <= 0) {
- state.SkipWithError("android_logger_list_read");
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char* eventData = log_msg.msg();
-
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
- if (ts != *tx) {
- if (0xDEADBEEFA55A5AA6ULL == caught_convert(eventData + 4 + 1)) {
- state.SkipWithError("signal");
- break;
- }
- continue;
- }
-
- break;
- }
- }
- state.PauseTiming();
-
- signal(SIGALRM, SIG_DFL);
- alarm(0);
-
- android_logger_list_free(logger_list);
-}
-BENCHMARK(BM_log_delay);
-
-/*
- * Measure the time it takes for __android_log_is_loggable.
- */
-static void BM_is_loggable(benchmark::State& state) {
- static const char logd[] = "logd";
-
- while (state.KeepRunning()) {
- __android_log_is_loggable_len(ANDROID_LOG_WARN, logd, strlen(logd),
- ANDROID_LOG_VERBOSE);
- }
-}
-BENCHMARK(BM_is_loggable);
-
-/*
- * Measure the time it takes for __android_log_security.
- */
-static void BM_security(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_security();
- }
-}
-BENCHMARK(BM_security);
-
-// Keep maps around for multiple iterations
-static std::unordered_set<uint32_t> set;
-static EventTagMap* map;
-
-static bool prechargeEventMap() {
- if (map) return true;
-
- fprintf(stderr, "Precharge: start\n");
-
- map = android_openEventTagMap(NULL);
- for (uint32_t tag = 1; tag < USHRT_MAX; ++tag) {
- size_t len;
- if (android_lookupEventTag_len(map, &len, tag) == NULL) continue;
- set.insert(tag);
- }
-
- fprintf(stderr, "Precharge: stop %zu\n", set.size());
-
- return true;
-}
-
-/*
- * Measure the time it takes for android_lookupEventTag_len
- */
-static void BM_lookupEventTag(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventTag_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventTag);
-
-/*
- * Measure the time it takes for android_lookupEventTag_len
- */
-static uint32_t notTag = 1;
-
-static void BM_lookupEventTag_NOT(benchmark::State& state) {
- prechargeEventMap();
-
- while (set.find(notTag) != set.end()) {
- ++notTag;
- if (notTag >= USHRT_MAX) notTag = 1;
- }
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventTag_len(map, &len, notTag);
- }
-
- ++notTag;
- if (notTag >= USHRT_MAX) notTag = 1;
-}
-BENCHMARK(BM_lookupEventTag_NOT);
-
-/*
- * Measure the time it takes for android_lookupEventFormat_len
- */
-static void BM_lookupEventFormat(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventFormat_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventFormat);
-
-// Must be functionally identical to liblog internal SendLogdControlMessage()
-static void send_to_control(char* buf, size_t len) {
- int sock =
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
- if (sock < 0) return;
- size_t writeLen = strlen(buf) + 1;
-
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, buf, writeLen));
- if (ret <= 0) {
- close(sock);
- return;
- }
- while ((ret = read(sock, buf, len)) > 0) {
- if (((size_t)ret == len) || (len < PAGE_SIZE)) {
- break;
- }
- len -= ret;
- buf += ret;
-
- struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
-
- ret = poll(&p, 1, 20);
- if ((ret <= 0) || !(p.revents & POLLIN)) {
- break;
- }
- }
- close(sock);
-}
-
-static void BM_lookupEventTagNum_logd_new(benchmark::State& state) {
- fprintf(stderr,
- "WARNING: "
- "This test can cause logd to grow in size and hit DOS limiter\n");
- // Make copies
- static const char empty_event_log_tags[] = "# content owned by logd\n";
- static const char dev_event_log_tags_path[] = "/dev/event-log-tags";
- std::string dev_event_log_tags;
- if (android::base::ReadFileToString(dev_event_log_tags_path,
- &dev_event_log_tags) &&
- (dev_event_log_tags.length() == 0)) {
- dev_event_log_tags = empty_event_log_tags;
- }
- static const char data_event_log_tags_path[] =
- "/data/misc/logd/event-log-tags";
- std::string data_event_log_tags;
- if (android::base::ReadFileToString(data_event_log_tags_path,
- &data_event_log_tags) &&
- (data_event_log_tags.length() == 0)) {
- data_event_log_tags = empty_event_log_tags;
- }
-
- while (state.KeepRunning()) {
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- log_time now(CLOCK_MONOTONIC);
- char name[64];
- snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
- name);
- state.ResumeTiming();
- send_to_control(buffer, sizeof(buffer));
- state.PauseTiming();
- }
-
- // Restore copies (logd still know about them, until crash or reboot)
- if (dev_event_log_tags.length() &&
- !android::base::WriteStringToFile(dev_event_log_tags,
- dev_event_log_tags_path)) {
- fprintf(stderr,
- "WARNING: "
- "failed to restore %s\n",
- dev_event_log_tags_path);
- }
- if (data_event_log_tags.length() &&
- !android::base::WriteStringToFile(data_event_log_tags,
- data_event_log_tags_path)) {
- fprintf(stderr,
- "WARNING: "
- "failed to restore %s\n",
- data_event_log_tags_path);
- }
- fprintf(stderr,
- "WARNING: "
- "Restarting logd to make it forget what we just did\n");
- system("stop logd ; start logd");
-}
-BENCHMARK(BM_lookupEventTagNum_logd_new);
-
-static void BM_lookupEventTagNum_logd_existing(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- const char* name = android_lookupEventTag_len(map, &len, (*it));
- std::string Name(name, len);
- const char* format = android_lookupEventFormat_len(map, &len, (*it));
- std::string Format(format, len);
-
- char buffer[256];
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"%s\"",
- Name.c_str(), Format.c_str());
-
- state.ResumeTiming();
- send_to_control(buffer, sizeof(buffer));
- state.PauseTiming();
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventTagNum_logd_existing);
-
-static void BM_log_verbose_overhead(benchmark::State& state) {
- std::string test_log_tag = "liblog_verbose_tag";
- android::base::SetProperty("log.tag." + test_log_tag, "I");
- for (auto _ : state) {
- __android_log_print(ANDROID_LOG_VERBOSE, test_log_tag.c_str(), "%s test log message %d %d",
- "test test", 123, 456);
- }
- android::base::SetProperty("log.tag." + test_log_tag, "");
-}
-BENCHMARK(BM_log_verbose_overhead);
diff --git a/liblog/tests/liblog_default_tag.cpp b/liblog/tests/liblog_default_tag.cpp
deleted file mode 100644
index 31b7467..0000000
--- a/liblog/tests/liblog_default_tag.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.
- */
-
-// LOG_TAG must be unset for android-base's logging to use a default tag.
-#undef LOG_TAG
-
-#include <stdlib.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <android/log.h>
-
-#include <gtest/gtest.h>
-
-#ifndef __ANDROID__
-static const char* getprogname() {
- return program_invocation_short_name;
-}
-#endif
-
-TEST(liblog_default_tag, no_default_tag_libbase_write_first) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- expected_tag = getprogname();
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, no_default_tag_liblog_write_first) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- expected_tag = getprogname();
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, libbase_sets_default_tag) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "libbase_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- SetDefaultTag(expected_tag);
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, liblog_sets_default_tag) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "liblog_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- __android_log_set_default_tag(expected_tag.c_str());
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, default_tag_plus_log_severity) {
-#ifdef __ANDROID__
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "liblog_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- __android_log_set_default_tag(expected_tag.c_str());
-
- auto log_tag_property = "log.tag." + expected_tag;
- SetProperty(log_tag_property, "V");
- auto reset_tag_property_guard = make_scope_guard([=] { SetProperty(log_tag_property, ""); });
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(VERBOSE) << "message";
- EXPECT_TRUE(message_seen);
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
-
-TEST(liblog_default_tag, generated_default_tag_plus_log_severity) {
-#ifdef __ANDROID__
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = getprogname();
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- // Even without any calls to SetDefaultTag(), the first message that attempts to log, will
- // generate a default tag from getprogname() and check log.tag.<default tag> for loggability. This
- // case checks that we can log a Verbose message when log.tag.<getprogname()> is set to 'V'.
- auto log_tag_property = "log.tag." + expected_tag;
- SetProperty(log_tag_property, "V");
- auto reset_tag_property_guard = make_scope_guard([=] { SetProperty(log_tag_property, ""); });
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(VERBOSE) << "message";
- EXPECT_TRUE(message_seen);
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
\ No newline at end of file
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
deleted file mode 100644
index 1d7ff9f..0000000
--- a/liblog/tests/liblog_global_state.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "global_state_test_tag"
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android/log.h>
-
-#include <gtest/gtest.h>
-
-TEST(liblog_global_state, libbase_logs_with_libbase_SetLogger) {
- using namespace android::base;
- bool message_seen = false;
- LogSeverity expected_severity = WARNING;
- std::string expected_file = Basename(__FILE__);
- unsigned int expected_line;
- std::string expected_message = "libbase test message";
-
- auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
- unsigned int line, const char* message) {
- message_seen = true;
- EXPECT_EQ(DEFAULT, log_id);
- EXPECT_EQ(expected_severity, severity);
- EXPECT_STREQ(LOG_TAG, tag);
- EXPECT_EQ(expected_file, file);
- EXPECT_EQ(expected_line, line);
- EXPECT_EQ(expected_message, message);
- };
-
- SetLogger(LoggerFunction);
-
- expected_line = __LINE__ + 1;
- LOG(expected_severity) << expected_message;
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, libbase_logs_with_liblog_set_logger) {
- using namespace android::base;
- // These must be static since they're used by the liblog logger function, which only accepts
- // lambdas without captures. The items used by the libbase logger are explicitly not static, to
- // ensure that lambdas with captures do work there.
- static bool message_seen = false;
- static std::string expected_file = Basename(__FILE__);
- static unsigned int expected_line;
- static std::string expected_message = "libbase test message";
-
- auto liblog_logger_function = [](const struct __android_log_message* log_message) {
- message_seen = true;
- EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
- EXPECT_EQ(LOG_ID_DEFAULT, log_message->buffer_id);
- EXPECT_EQ(ANDROID_LOG_WARN, log_message->priority);
- EXPECT_STREQ(LOG_TAG, log_message->tag);
- EXPECT_EQ(expected_file, log_message->file);
- EXPECT_EQ(expected_line, log_message->line);
- EXPECT_EQ(expected_message, log_message->message);
- };
-
- __android_log_set_logger(liblog_logger_function);
-
- expected_line = __LINE__ + 1;
- LOG(WARNING) << expected_message;
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, liblog_logs_with_libbase_SetLogger) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_message = "libbase test message";
-
- auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
- unsigned int line, const char* message) {
- message_seen = true;
- EXPECT_EQ(MAIN, log_id);
- EXPECT_EQ(WARNING, severity);
- EXPECT_STREQ(LOG_TAG, tag);
- EXPECT_EQ(nullptr, file);
- EXPECT_EQ(0U, line);
- EXPECT_EQ(expected_message, message);
- };
-
- SetLogger(LoggerFunction);
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, LOG_TAG, expected_message.c_str());
- EXPECT_TRUE(message_seen);
- message_seen = false;
-}
-
-TEST(liblog_global_state, liblog_logs_with_liblog_set_logger) {
- using namespace android::base;
- // These must be static since they're used by the liblog logger function, which only accepts
- // lambdas without captures. The items used by the libbase logger are explicitly not static, to
- // ensure that lambdas with captures do work there.
- static bool message_seen = false;
- static int expected_buffer_id = LOG_ID_MAIN;
- static int expected_priority = ANDROID_LOG_WARN;
- static std::string expected_message = "libbase test message";
-
- auto liblog_logger_function = [](const struct __android_log_message* log_message) {
- message_seen = true;
- EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
- EXPECT_EQ(expected_buffer_id, log_message->buffer_id);
- EXPECT_EQ(expected_priority, log_message->priority);
- EXPECT_STREQ(LOG_TAG, log_message->tag);
- EXPECT_STREQ(nullptr, log_message->file);
- EXPECT_EQ(0U, log_message->line);
- EXPECT_EQ(expected_message, log_message->message);
- };
-
- __android_log_set_logger(liblog_logger_function);
-
- __android_log_buf_write(expected_buffer_id, expected_priority, LOG_TAG, expected_message.c_str());
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, SetAborter_with_liblog) {
- using namespace android::base;
-
- std::string expected_message = "libbase test message";
- static bool message_seen = false;
- auto aborter_function = [&](const char* message) {
- message_seen = true;
- EXPECT_EQ(expected_message, message);
- };
-
- SetAborter(aborter_function);
- LOG(FATAL) << expected_message;
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- static std::string expected_message_static = "libbase test message";
- auto liblog_aborter_function = [](const char* message) {
- message_seen = true;
- EXPECT_EQ(expected_message_static, message);
- };
- __android_log_set_aborter(liblog_aborter_function);
- LOG(FATAL) << expected_message_static;
- EXPECT_TRUE(message_seen);
- message_seen = false;
-}
-
-static std::string UniqueLogTag() {
- std::string tag = LOG_TAG;
- tag += "-" + std::to_string(getpid());
- return tag;
-}
-
-TEST(liblog_global_state, is_loggable_both_default) {
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-}
-
-TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-}
-
-TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
-#ifdef __ANDROID__
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- auto log_tag_property = std::string("log.tag.") + tag;
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
-
-TEST(liblog_global_state, is_loggable_both_set) {
-#ifdef __ANDROID__
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // When both a tag and a minimum priority are set, we use the lower value of the two.
-
- // tag = warning, minimum_priority = debug, expect 'debug'
- auto log_tag_property = std::string("log.tag.") + tag;
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
- EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = warning, minimum_priority = warning, expect 'warning'
- EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = debug, minimum_priority = warning, expect 'debug'
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = debug, minimum_priority = debug, expect 'debug'
- EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
diff --git a/liblog/tests/liblog_host_test.cpp b/liblog/tests/liblog_host_test.cpp
deleted file mode 100644
index ec186d4..0000000
--- a/liblog/tests/liblog_host_test.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2019 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 <log/log.h>
-#include <private/android_logger.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <regex>
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-
-using android::base::InitLogging;
-using android::base::StderrLogger;
-using android::base::StringPrintf;
-
-static std::string MakeLogPattern(int priority, const char* tag, const char* message) {
- static const char log_characters[] = "XXVDIWEF";
- static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
- "Mismatch in size of log_characters and values in android_LogPriority");
- priority = priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : priority;
- char log_char = log_characters[priority];
-
- return StringPrintf("%s %c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s", tag, log_char,
- message);
-}
-
-static void CheckMessage(bool expected, const std::string& output, int priority, const char* tag,
- const char* message) {
- std::regex message_regex(MakeLogPattern(priority, tag, message));
- EXPECT_EQ(expected, std::regex_search(output, message_regex)) << message;
-}
-
-static void GenerateLogContent() {
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, "tag", "verbose main");
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO, "tag", "info main");
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_ERROR, "tag", "error main");
-
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, "tag", "info radio");
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, "tag", "error radio");
-
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, "tag", "verbose system");
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, "tag", "info system");
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, "tag", "error system");
-
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_INFO, "tag", "info crash");
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-std::string GetPidString() {
- int pid = getpid();
- return StringPrintf("%5d", pid);
-}
-
-TEST(liblog, default_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, verbose_write) {
- setenv("ANDROID_LOG_TAGS", "*:v", true);
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, error_write) {
- setenv("ANDROID_LOG_TAGS", "*:e", true);
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, kernel_no_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
- __android_log_buf_print(LOG_ID_KERNEL, ANDROID_LOG_ERROR, "tag", "kernel error");
- EXPECT_EQ("", captured_stderr.str());
-}
-
-TEST(liblog, binary_no_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
- __android_log_buf_print(LOG_ID_EVENTS, ANDROID_LOG_ERROR, "tag", "error events");
- __android_log_buf_print(LOG_ID_STATS, ANDROID_LOG_ERROR, "tag", "error stats");
- __android_log_buf_print(LOG_ID_SECURITY, ANDROID_LOG_ERROR, "tag", "error security");
-
- __android_log_bswrite(0x12, "events");
- __android_log_stats_bwrite(0x34, "stats", strlen("stats"));
- __android_log_security_bswrite(0x56, "security");
-
- EXPECT_EQ("", captured_stderr.str());
-}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
deleted file mode 100644
index c49d87b..0000000
--- a/liblog/tests/liblog_test.cpp
+++ /dev/null
@@ -1,2770 +0,0 @@
-/*
- * Copyright (C) 2013-2016 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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/scopeguard.h>
-#include <android-base/stringprintf.h>
-#ifdef __ANDROID__ // includes sys/properties.h which does not exist outside
-#include <cutils/properties.h>
-#endif
-#include <gtest/gtest.h>
-#include <log/log_event_list.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-using android::base::make_scope_guard;
-
-// #define ENABLE_FLAKY_TESTS
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are only using this in the emergency of
-// a signal to stuff a terminating code into the logs, we will spin rather
-// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-// std::unique_ptr doesn't let you provide a pointer to a deleter (android_logger_list_close()) if
-// the type (struct logger_list) is an incomplete type, so we create ListCloser instead.
-struct ListCloser {
- void operator()(struct logger_list* list) { android_logger_list_close(list); }
-};
-
-// This function is meant to be used for most log tests, it does the following:
-// 1) Open the log_buffer with a blocking reader
-// 2) Write the messages via write_messages
-// 3) Set an alarm for 2 seconds as a timeout
-// 4) Read until check_message returns true, which should be used to indicate the target message
-// is found
-// 5) Open log_buffer with a non_blocking reader and dump all messages
-// 6) Count the number of times check_messages returns true for these messages and assert it's
-// only 1.
-template <typename FWrite, typename FCheck>
-static void RunLogTests(log_id_t log_buffer, FWrite write_messages, FCheck check_message) {
- pid_t pid = getpid();
-
- auto logger_list = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(log_buffer, 0, 1000, pid)};
- ASSERT_TRUE(logger_list);
-
- write_messages();
-
- alarm(2);
- auto alarm_guard = android::base::make_scope_guard([] { alarm(0); });
- bool found = false;
- while (!found) {
- log_msg log_msg;
- ASSERT_GT(android_logger_list_read(logger_list.get(), &log_msg), 0);
-
- ASSERT_EQ(log_buffer, log_msg.id());
- ASSERT_EQ(pid, log_msg.entry.pid);
-
- ASSERT_NE(nullptr, log_msg.msg());
-
- check_message(log_msg, &found);
- }
-
- auto logger_list_non_block = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(log_buffer, ANDROID_LOG_NONBLOCK, 1000, pid)};
- ASSERT_TRUE(logger_list_non_block);
-
- size_t count = 0;
- while (true) {
- log_msg log_msg;
- auto ret = android_logger_list_read(logger_list_non_block.get(), &log_msg);
- if (ret == -EAGAIN) {
- break;
- }
- ASSERT_GT(ret, 0);
-
- ASSERT_EQ(log_buffer, log_msg.id());
- ASSERT_EQ(pid, log_msg.entry.pid);
-
- ASSERT_NE(nullptr, log_msg.msg());
-
- found = false;
- check_message(log_msg, &found);
- if (found) {
- ++count;
- }
- }
-
- EXPECT_EQ(1U, count);
-}
-
-TEST(liblog, __android_log_btwrite) {
- int intBuf = 0xDEADBEEF;
- EXPECT_LT(0,
- __android_log_btwrite(0, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)));
- long long longBuf = 0xDEADBEEFA55A5AA5;
- EXPECT_LT(
- 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)));
- char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
- EXPECT_LT(0,
- __android_log_btwrite(0, EVENT_TYPE_STRING, Buf, sizeof(Buf) - 1));
-}
-
-#if defined(__ANDROID__)
-static std::string popenToString(const std::string& command) {
- std::string ret;
-
- FILE* fp = popen(command.c_str(), "re");
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
- pclose(fp);
- }
- return ret;
-}
-
-static bool isPmsgActive() {
- pid_t pid = getpid();
-
- std::string myPidFds =
- popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true; // guess it is?
-
- return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
-}
-
-static bool isLogdwActive() {
- std::string logdwSignature =
- popenToString("grep -a /dev/socket/logdw /proc/net/unix");
- size_t beginning = logdwSignature.find(' ');
- if (beginning == std::string::npos) return true;
- beginning = logdwSignature.find(' ', beginning + 1);
- if (beginning == std::string::npos) return true;
- size_t end = logdwSignature.find(' ', beginning + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- std::string allLogdwEndpoints = popenToString(
- "grep -a ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
- " ' /proc/net/unix | " +
- "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
- if (allLogdwEndpoints.length() == 0) return true;
-
- // NB: allLogdwEndpoints has some false positives in it, but those
- // strangers do not overlap with the simplistic activities inside this
- // test suite.
-
- pid_t pid = getpid();
-
- std::string myPidFds =
- popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true;
-
- // NB: fgrep with multiple strings is broken in Android
- for (beginning = 0;
- (end = allLogdwEndpoints.find('\n', beginning)) != std::string::npos;
- beginning = end + 1) {
- if (myPidFds.find(allLogdwEndpoints.substr(beginning, end - beginning)) !=
- std::string::npos)
- return true;
- }
- return false;
-}
-
-static bool tested__android_log_close;
-#endif
-
-TEST(liblog, __android_log_btwrite__android_logger_list_read) {
-#ifdef __ANDROID__
- log_time ts(CLOCK_MONOTONIC);
- log_time ts1(ts);
-
- bool has_pstore = access("/dev/pmsg0", W_OK) == 0;
-
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- // Check that we can close and reopen the logger
- bool logdwActiveAfter__android_log_btwrite;
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- }
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- __android_log_close();
- if (getuid() == AID_ROOT) {
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- }
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- }
-
- ts1 = log_time(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
- if (getuid() == AID_ROOT) {
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- }
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- }
- };
-
- int count = 0;
- int second_count = 0;
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- return;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- return;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&eventData->payload.data);
- if (ts == *tx) {
- ++count;
- } else if (ts1 == *tx) {
- ++second_count;
- }
-
- if (count == 1 && second_count == 1) {
- count = 0;
- second_count = 0;
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_write__android_logger_list_read) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- std::string buf = android::base::StringPrintf("pid=%u ts=%ld.%09ld", pid, ts.tv_sec, ts.tv_nsec);
- static const char tag[] = "liblog.__android_log_write__android_logger_list_read";
- static const char prio = ANDROID_LOG_DEBUG;
-
- std::string expected_message =
- std::string(&prio, sizeof(prio)) + tag + std::string("", 1) + buf + std::string("", 1);
-
- auto write_function = [&] { ASSERT_LT(0, __android_log_write(prio, tag, buf.c_str())); };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if (log_msg.entry.len != expected_message.length()) {
- return;
- }
-
- if (expected_message != std::string(log_msg.msg(), log_msg.entry.len)) {
- return;
- }
-
- *found = true;
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-static void bswrite_test(const char* message) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- size_t num_lines = 1, size = 0, length = 0, total = 0;
- const char* cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++cp;
- ++total;
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
- break;
- }
- }
- while (*cp) {
- ++cp;
- ++total;
- }
-
- auto write_function = [&] { EXPECT_LT(0, __android_log_bswrite(0, message)); };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len != (sizeof(android_log_event_string_t) + length) ||
- log_msg.id() != LOG_ID_EVENTS) {
- return;
- }
-
- android_log_event_string_t* eventData;
- eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
-
- if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
- return;
- }
-
- size_t len = eventData->length;
- if (len == total) {
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- if (length != total) {
- fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
- }
- int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
- &log_msg.entry, &entry, nullptr, msgBuf, sizeof(msgBuf));
- EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
- if ((processBinaryLogBuffer == 0) || entry.message) {
- size_t line_overhead = 20;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- fflush(stderr);
- if (processBinaryLogBuffer) {
- EXPECT_GT((int)((line_overhead * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- } else {
- EXPECT_EQ((int)((line_overhead * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- }
- android_log_format_free(logformat);
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_bswrite_and_print) {
- bswrite_test("Hello World");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__empty_string) {
- bswrite_test("");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
- bswrite_test("\nHello World\n");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
- bswrite_test("\n Hello World \n");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
- bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
-}
-
-static void buf_write_test(const char* message) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- static const char tag[] = "TEST__android_log_buf_write";
-
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO, tag, message));
- };
- size_t num_lines = 1, size = 0, length = 0;
- const char* cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
- break;
- }
- ++cp;
- }
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2) || log_msg.id() != LOG_ID_MAIN) {
- return;
- }
-
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry, &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- size_t line_overhead = 11;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- fflush(stderr);
- EXPECT_EQ((int)(((line_overhead + sizeof(tag)) * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- android_log_format_free(logformat);
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_buf_write_and_print__empty) {
- buf_write_test("");
-}
-
-TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
- buf_write_test("\nHello World\n");
-}
-
-TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
- buf_write_test("\n Hello World \n");
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-#ifdef __ANDROID__
-static unsigned signaled;
-static log_time signal_time;
-
-/*
- * Strictly, we are not allowed to log messages in a signal context, but we
- * do make an effort to keep the failure surface minimized, and this in-effect
- * should catch any regressions in that effort. The odds of a logged message
- * in a signal handler causing a lockup problem should be _very_ small.
- */
-static void caught_blocking_signal(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
-
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-// Fill in current process user and system time in 10ms increments
-static void get_ticks(unsigned long long* uticks, unsigned long long* sticks) {
- *uticks = *sticks = 0;
-
- pid_t pid = getpid();
-
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
-
- FILE* fp = fopen(buffer, "re");
- if (!fp) {
- return;
- }
-
- char* cp = fgets(buffer, sizeof(buffer), fp);
- fclose(fp);
- if (!cp) {
- return;
- }
-
- pid_t d;
- char s[sizeof(buffer)];
- char c;
- long long ll;
- unsigned long long ull;
-
- if (15 != sscanf(buffer,
- "%d %s %c %lld %lld %lld %lld %lld %llu %llu %llu %llu %llu "
- "%llu %llu ",
- &d, s, &c, &ll, &ll, &ll, &ll, &ll, &ull, &ull, &ull, &ull,
- &ull, uticks, sticks)) {
- *uticks = *sticks = 0;
- }
-}
-#endif
-
-TEST(liblog, android_logger_list_read__cpu_signal) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
-
- int count = 0;
-
- int signals = 0;
-
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
-
- const unsigned alarm_time = 10;
-
- memset(&signal_time, 0, sizeof(signal_time));
-
- signal(SIGALRM, caught_blocking_signal);
- alarm(alarm_time);
-
- signaled = 0;
-
- do {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- alarm(alarm_time);
-
- ++count;
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
-
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- EXPECT_LE(1, count);
-
- EXPECT_EQ(1, signals);
-
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-#ifdef __ANDROID__
-/*
- * Strictly, we are not allowed to log messages in a signal context, the
- * correct way to handle this is to ensure the messages are constructed in
- * a thread; the signal handler should only unblock the thread.
- */
-static sem_t thread_trigger;
-
-static void caught_blocking_thread(int /*signum*/) {
- sem_post(&thread_trigger);
-}
-
-static void* running_thread(void*) {
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
-
- struct timespec timeout;
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_sec += 55;
- sem_timedwait(&thread_trigger, &timeout);
-
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- return NULL;
-}
-
-static int start_thread() {
- sem_init(&thread_trigger, 0, 0);
-
- pthread_attr_t attr;
- if (pthread_attr_init(&attr)) {
- return -1;
- }
-
- struct sched_param param;
-
- memset(¶m, 0, sizeof(param));
- pthread_attr_setschedparam(&attr, ¶m);
- pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
-
- if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
- pthread_t thread;
- if (pthread_create(&thread, &attr, running_thread, NULL)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
- pthread_attr_destroy(&attr);
- return 0;
-}
-#endif
-
-TEST(liblog, android_logger_list_read__cpu_thread) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
-
- int count = 0;
-
- int signals = 0;
-
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
-
- const unsigned alarm_time = 10;
-
- memset(&signal_time, 0, sizeof(signal_time));
-
- signaled = 0;
- EXPECT_EQ(0, start_thread());
-
- signal(SIGALRM, caught_blocking_thread);
- alarm(alarm_time);
-
- do {
- log_msg log_msg;
- if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
- break;
- }
-
- alarm(alarm_time);
-
- ++count;
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
-
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- EXPECT_LE(1, count);
-
- EXPECT_EQ(1, signals);
-
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-static const char max_payload_buf[] =
- "LEONATO\n\
-I learn in this letter that Don Peter of Arragon\n\
-comes this night to Messina\n\
-MESSENGER\n\
-He is very near by this: he was not three leagues off\n\
-when I left him\n\
-LEONATO\n\
-How many gentlemen have you lost in this action?\n\
-MESSENGER\n\
-But few of any sort, and none of name\n\
-LEONATO\n\
-A victory is twice itself when the achiever brings\n\
-home full numbers. I find here that Don Peter hath\n\
-bestowed much honour on a young Florentine called Claudio\n\
-MESSENGER\n\
-Much deserved on his part and equally remembered by\n\
-Don Pedro: he hath borne himself beyond the\n\
-promise of his age, doing, in the figure of a lamb,\n\
-the feats of a lion: he hath indeed better\n\
-bettered expectation than you must expect of me to\n\
-tell you how\n\
-LEONATO\n\
-He hath an uncle here in Messina will be very much\n\
-glad of it.\n\
-MESSENGER\n\
-I have already delivered him letters, and there\n\
-appears much joy in him; even so much that joy could\n\
-not show itself modest enough without a badge of\n\
-bitterness.\n\
-LEONATO\n\
-Did he break out into tears?\n\
-MESSENGER\n\
-In great measure.\n\
-LEONATO\n\
-A kind overflow of kindness: there are no faces\n\
-truer than those that are so washed. How much\n\
-better is it to weep at joy than to joy at weeping!\n\
-BEATRICE\n\
-I pray you, is Signior Mountanto returned from the\n\
-wars or no?\n\
-MESSENGER\n\
-I know none of that name, lady: there was none such\n\
-in the army of any sort.\n\
-LEONATO\n\
-What is he that you ask for, niece?\n\
-HERO\n\
-My cousin means Signior Benedick of Padua.\n\
-MESSENGER\n\
-O, he's returned; and as pleasant as ever he was.\n\
-BEATRICE\n\
-He set up his bills here in Messina and challenged\n\
-Cupid at the flight; and my uncle's fool, reading\n\
-the challenge, subscribed for Cupid, and challenged\n\
-him at the bird-bolt. I pray you, how many hath he\n\
-killed and eaten in these wars? But how many hath\n\
-he killed? for indeed I promised to eat all of his killing.\n\
-LEONATO\n\
-Faith, niece, you tax Signior Benedick too much;\n\
-but he'll be meet with you, I doubt it not.\n\
-MESSENGER\n\
-He hath done good service, lady, in these wars.\n\
-BEATRICE\n\
-You had musty victual, and he hath holp to eat it:\n\
-he is a very valiant trencherman; he hath an\n\
-excellent stomach.\n\
-MESSENGER\n\
-And a good soldier too, lady.\n\
-BEATRICE\n\
-And a good soldier to a lady: but what is he to a lord?\n\
-MESSENGER\n\
-A lord to a lord, a man to a man; stuffed with all\n\
-honourable virtues.\n\
-BEATRICE\n\
-It is so, indeed; he is no less than a stuffed man:\n\
-but for the stuffing,--well, we are all mortal.\n\
-LEONATO\n\
-You must not, sir, mistake my niece. There is a\n\
-kind of merry war betwixt Signior Benedick and her:\n\
-they never meet but there's a skirmish of wit\n\
-between them.\n\
-BEATRICE\n\
-Alas! he gets nothing by that. In our last\n\
-conflict four of his five wits went halting off, and\n\
-now is the whole man governed with one: so that if\n\
-he have wit enough to keep himself warm, let him\n\
-bear it for a difference between himself and his\n\
-horse; for it is all the wealth that he hath left,\n\
-to be known a reasonable creature. Who is his\n\
-companion now? He hath every month a new sworn brother.\n\
-MESSENGER\n\
-Is't possible?\n\
-BEATRICE\n\
-Very easily possible: he wears his faith but as\n\
-the fashion of his hat; it ever changes with the\n\
-next block.\n\
-MESSENGER\n\
-I see, lady, the gentleman is not in your books.\n\
-BEATRICE\n\
-No; an he were, I would burn my study. But, I pray\n\
-you, who is his companion? Is there no young\n\
-squarer now that will make a voyage with him to the devil?\n\
-MESSENGER\n\
-He is most in the company of the right noble Claudio.\n\
-BEATRICE\n\
-O Lord, he will hang upon him like a disease: he\n\
-is sooner caught than the pestilence, and the taker\n\
-runs presently mad. God help the noble Claudio! if\n\
-he have caught the Benedick, it will cost him a\n\
-thousand pound ere a' be cured.\n\
-MESSENGER\n\
-I will hold friends with you, lady.\n\
-BEATRICE\n\
-Do, good friend.\n\
-LEONATO\n\
-You will never run mad, niece.\n\
-BEATRICE\n\
-No, not till a hot January.\n\
-MESSENGER\n\
-Don Pedro is approached.\n\
-Enter DON PEDRO, DON JOHN, CLAUDIO, BENEDICK, and BALTHASAR\n\
-\n\
-DON PEDRO\n\
-Good Signior Leonato, you are come to meet your\n\
-trouble: the fashion of the world is to avoid\n\
-cost, and you encounter it\n\
-LEONATO\n\
-Never came trouble to my house in the likeness of your grace,\n\
-for trouble being gone, comfort should remain, but\n\
-when you depart from me, sorrow abides and happiness\n\
-takes his leave.";
-
-TEST(liblog, max_payload) {
-#ifdef __ANDROID__
- static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
-#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(max_payload_tag) - 1)
-
- pid_t pid = getpid();
- char tag[sizeof(max_payload_tag)];
- memcpy(tag, max_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
-
- auto write_function = [&] {
- LOG_FAILURE_RETRY(
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, tag, max_payload_buf));
- };
-
- ssize_t max_len = 0;
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- return;
- }
-
- data += strlen(data) + 1;
-
- const char* left = data;
- const char* right = max_payload_buf;
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- if (max_len <= (left - data)) {
- max_len = left - data + 1;
- }
-
- if (max_len > 512) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_SYSTEM, write_function, check_function);
-
- EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_buf_print__maxtag) {
-#ifdef __ANDROID__
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO, max_payload_buf,
- max_payload_buf));
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len < LOGGER_ENTRY_MAX_PAYLOAD) {
- return;
- }
-
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry, &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- fflush(stderr);
- int printLogLine =
- android_log_printLogLine(logformat, fileno(stderr), &entry);
- // Legacy tag truncation
- EXPECT_LE(128, printLogLine);
- // Measured maximum if we try to print part of the tag as message
- EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
- }
- android_log_format_free(logformat);
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-// Note: This test is tautological. android_logger_list_read() calls recv() with
-// LOGGER_ENTRY_MAX_PAYLOAD as its size argument, so it's not possible for this test to read a
-// payload larger than that size.
-TEST(liblog, too_big_payload) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
- static const char big_payload_tag[] = "TEST_big_payload_XXXX";
- char tag[sizeof(big_payload_tag)];
- memcpy(tag, big_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
-
- std::string longString(3266519, 'x');
- ssize_t ret;
-
- auto write_function = [&] {
- ret = LOG_FAILURE_RETRY(
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, tag, longString.c_str()));
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- return;
- }
-
- data += strlen(data) + 1;
-
- const char* left = data;
- const char* right = longString.c_str();
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- ssize_t len = left - data + 1;
- // Check that we don't see any entries larger than the max payload.
- EXPECT_LE(static_cast<size_t>(len), LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag));
-
- // Once we've found our expected entry, break.
- if (len == LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag)) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_SYSTEM, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, dual_reader) {
-#ifdef __ANDROID__
- static const int expected_count1 = 25;
- static const int expected_count2 = 25;
-
- pid_t pid = getpid();
-
- auto logger_list1 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, 0, expected_count1, pid)};
- ASSERT_TRUE(logger_list1);
-
- auto logger_list2 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, 0, expected_count2, pid)};
- ASSERT_TRUE(logger_list2);
-
- for (int i = 25; i > 0; --i) {
- static const char fmt[] = "dual_reader %02d";
- char buffer[sizeof(fmt) + 8];
- snprintf(buffer, sizeof(buffer), fmt, i);
- LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "liblog", buffer));
- }
-
- alarm(2);
- auto alarm_guard = android::base::make_scope_guard([] { alarm(0); });
-
- // Wait until we see all messages with the blocking reader.
- int count1 = 0;
- int count2 = 0;
-
- while (count1 != expected_count2 || count2 != expected_count2) {
- log_msg log_msg;
- if (count1 < expected_count1) {
- ASSERT_GT(android_logger_list_read(logger_list1.get(), &log_msg), 0);
- count1++;
- }
- if (count2 < expected_count2) {
- ASSERT_GT(android_logger_list_read(logger_list2.get(), &log_msg), 0);
- count2++;
- }
- }
-
- // Test again with the nonblocking reader.
- auto logger_list_non_block1 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count1, pid)};
- ASSERT_TRUE(logger_list_non_block1);
-
- auto logger_list_non_block2 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count2, pid)};
- ASSERT_TRUE(logger_list_non_block2);
- count1 = 0;
- count2 = 0;
- bool done1 = false;
- bool done2 = false;
-
- while (!done1 || !done2) {
- log_msg log_msg;
-
- if (!done1) {
- if (android_logger_list_read(logger_list_non_block1.get(), &log_msg) <= 0) {
- done1 = true;
- } else {
- ++count1;
- }
- }
-
- if (!done2) {
- if (android_logger_list_read(logger_list_non_block2.get(), &log_msg) <= 0) {
- done2 = true;
- } else {
- ++count2;
- }
- }
- }
-
- EXPECT_EQ(expected_count1, count1);
- EXPECT_EQ(expected_count2, count2);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-static bool checkPriForTag(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri) {
- return android_log_shouldPrintLine(p_format, tag, pri) &&
- !android_log_shouldPrintLine(p_format, tag,
- (android_LogPriority)(pri - 1));
-}
-
-TEST(liblog, filterRule) {
- static const char tag[] = "random";
-
- AndroidLogFormat* p_format = android_log_format_new();
-
- android_log_addFilterRule(p_format, "*:i");
-
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
- android_log_addFilterRule(p_format, "*");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:v");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:i");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- android_log_addFilterRule(p_format, tag);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:v");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:d");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:w");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- android_log_addFilterRule(p_format, "crap:*");
- EXPECT_TRUE(checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(
- android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
-
- // invalid expression
- EXPECT_TRUE(android_log_addFilterRule(p_format, "random:z") < 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- // Issue #550946
- EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
-
- // note trailing space
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
-
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
-
-#if 0 // bitrot, seek update
- char defaultBuffer[512];
-
- android_log_formatLogLine(p_format,
- defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
- 123, 123, tag, "nofile", strlen("Hello"), "Hello", NULL);
-
- fprintf(stderr, "%s\n", defaultBuffer);
-#endif
-
- android_log_format_free(p_format);
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-TEST(liblog, is_loggable) {
-#ifdef __ANDROID__
- static const char tag[] = "is_loggable";
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
- // sizeof("string") = strlen("string") + 1
- char key[sizeof(log_namespace) + sizeof(tag) - 1];
- char hold[4][PROP_VALUE_MAX];
- static const struct {
- int level;
- char type;
- } levels[] = {
- {ANDROID_LOG_VERBOSE, 'v'}, {ANDROID_LOG_DEBUG, 'd'},
- {ANDROID_LOG_INFO, 'i'}, {ANDROID_LOG_WARN, 'w'},
- {ANDROID_LOG_ERROR, 'e'}, {ANDROID_LOG_FATAL, 'a'},
- {ANDROID_LOG_SILENT, 's'}, {-2, 'g'}, // Illegal value, resort to default
- };
-
- // Set up initial test condition
- memset(hold, 0, sizeof(hold));
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- property_get(key, hold[0], "");
- property_set(key, "");
- property_get(key + base_offset, hold[1], "");
- property_set(key + base_offset, "");
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_get(key, hold[2], "");
- property_set(key, "");
- property_get(key, hold[3], "");
- property_set(key + base_offset, "");
-
- // All combinations of level and defaults
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- if (levels[j].level == -2) {
- continue;
- }
- fprintf(stderr, "i=%zu j=%zu\r", i, j);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1)) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- }
- }
- }
-
- // All combinations of level and tag and global properties
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
-
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- property_set(key, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
- }
- }
-
- // All combinations of level and tag properties, but with global set to INFO
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- usleep(20000);
- property_set(key, "I");
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
- }
- }
-
- // reset parms
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- usleep(20000);
- property_set(key, hold[0]);
- property_set(key + base_offset, hold[1]);
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_set(key, hold[2]);
- property_set(key + base_offset, hold[3]);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-#ifdef ENABLE_FLAKY_TESTS
-// Following tests the specific issues surrounding error handling wrt logd.
-// Kills logd and toss all collected data, equivalent to logcat -b all -c,
-// except we also return errors to the logging callers.
-#ifdef __ANDROID__
-// helper to liblog.enoent to count end-to-end matching logging messages.
-static int count_matching_ts(log_time ts) {
- usleep(1000000);
-
- pid_t pid = getpid();
-
- struct logger_list* logger_list =
- android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_NONBLOCK, 1000, pid);
-
- int count = 0;
- if (logger_list == NULL) return count;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
- if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
- if (log_msg.id() != LOG_ID_EVENTS) continue;
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData) continue;
- if (eventData->payload.type != EVENT_TYPE_LONG) continue;
-
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts != tx) continue;
-
- // found event message with matching timestamp signature in payload
- ++count;
- }
- android_logger_list_close(logger_list);
-
- return count;
-}
-
-TEST(liblog, enoent) {
-#ifdef __ANDROID__
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
-
- log_time ts(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
-
- // This call will fail unless we are root, beware of any
- // test prior to this one playing with setuid and causing interference.
- // We need to run before these tests so that they do not interfere with
- // this test.
- //
- // Stopping the logger can affect some other test's expectations as they
- // count on the log buffers filled with existing content, and this
- // effectively does a logcat -c emptying it. So we want this test to be
- // as near as possible to the bottom of the file. For example
- // liblog.android_logger_get_ is one of those tests that has no recourse
- // and that would be adversely affected by emptying the log if it was run
- // right after this test.
- system("stop logd");
- usleep(1000000);
-
- // A clean stop like we are testing returns -ENOENT, but in the _real_
- // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
- // Alas we can not test these other return values; accept that they
- // are treated equally within the open-retry logic in liblog.
- ts = log_time(CLOCK_MONOTONIC);
- int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- std::string content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, (ret <= 0) ? strerror(-ret) : "(content sent)");
- EXPECT_TRUE(ret == -ENOENT || ret == -ENOTCONN || ret == -ECONNREFUSED) << content;
- ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, (ret <= 0) ? strerror(-ret) : "(content sent)");
- EXPECT_TRUE(ret == -ENOENT || ret == -ENOTCONN || ret == -ECONNREFUSED) << content;
- EXPECT_EQ(0, count_matching_ts(ts));
-
- system("start logd");
- usleep(1000000);
-
- EXPECT_EQ(0, count_matching_ts(ts));
-
- ts = log_time(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // __ANDROID__
-#endif // ENABLE_FLAKY_TESTS
-
-// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
-
-#ifdef ENABLE_FLAKY_TESTS
-// Do not retest properties, and cannot log into LOG_ID_SECURITY
-TEST(liblog, __security) {
-#ifdef __ANDROID__
- static const char persist_key[] = "persist.logd.security";
- static const char readonly_key[] = "ro.organization_owned";
- // A silly default value that can never be in readonly_key so
- // that it can be determined the property is not set.
- static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
- char persist[PROP_VALUE_MAX];
- char persist_hold[PROP_VALUE_MAX];
- char readonly[PROP_VALUE_MAX];
-
- // First part of this test requires the test itself to have the appropriate
- // permissions. If we do not have them, we can not override them, so we
- // bail rather than give a failing grade.
- property_get(persist_key, persist, "");
- fprintf(stderr, "INFO: getprop %s -> %s\n", persist_key, persist);
- strncpy(persist_hold, persist, PROP_VALUE_MAX);
- property_get(readonly_key, readonly, nothing_val);
- fprintf(stderr, "INFO: getprop %s -> %s\n", readonly_key, readonly);
-
- if (!strcmp(readonly, nothing_val)) {
- // Lets check if we can set the value (we should not be allowed to do so)
- EXPECT_FALSE(__android_log_security());
- fprintf(stderr, "WARNING: setting ro.organization_owned to a domain\n");
- static const char domain[] = "com.google.android.SecOps.DeviceOwner";
- EXPECT_NE(0, property_set(readonly_key, domain));
- useconds_t total_time = 0;
- static const useconds_t seconds = 1000000;
- static const useconds_t max_time = 5 * seconds; // not going to happen
- static const useconds_t rest = 20 * 1000;
- for (; total_time < max_time; total_time += rest) {
- usleep(rest); // property system does not guarantee performance.
- property_get(readonly_key, readonly, nothing_val);
- if (!strcmp(readonly, domain)) {
- if (total_time > rest) {
- fprintf(stderr, "INFO: took %u.%06u seconds to set property\n",
- (unsigned)(total_time / seconds),
- (unsigned)(total_time % seconds));
- }
- break;
- }
- }
- EXPECT_STRNE(domain, readonly);
- }
-
- if (!strcasecmp(readonly, "false") || !readonly[0] ||
- !strcmp(readonly, nothing_val)) {
- // not enough permissions to run tests surrounding persist.logd.security
- EXPECT_FALSE(__android_log_security());
- return;
- }
-
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "TRUE");
- property_get(persist_key, persist, "");
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool perm = (gid == AID_ROOT) || (uid == AID_ROOT);
- EXPECT_STREQ(perm ? "TRUE" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "FALSE");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "FALSE" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "true");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "true" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "false");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "false" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, persist_hold);
- property_get(persist_key, persist, "");
- EXPECT_STREQ(persist_hold, persist);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __security_buffer) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- android_event_long_t buffer;
-
- static const char persist_key[] = "persist.logd.security";
- char persist[PROP_VALUE_MAX];
- bool set_persist = false;
- bool allow_security = false;
-
- if (__android_log_security()) {
- allow_security = true;
- } else {
- property_get(persist_key, persist, "");
- if (strcasecmp(persist, "true")) {
- property_set(persist_key, "TRUE");
- if (__android_log_security()) {
- allow_security = true;
- set_persist = true;
- } else {
- property_set(persist_key, persist);
- }
- }
- }
-
- if (!allow_security) {
- fprintf(stderr,
- "WARNING: "
- "security buffer disabled, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- /* Matches clientHasLogCredentials() in logd */
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool clientHasLogCredentials = true;
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG) &&
- (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- uid_t euid = geteuid();
- if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
- gid_t egid = getegid();
- if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
- int num_groups = getgroups(0, NULL);
- if (num_groups > 0) {
- gid_t groups[num_groups];
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- }
- if (num_groups <= 0) {
- clientHasLogCredentials = false;
- }
- }
- }
- }
- if (!clientHasLogCredentials) {
- fprintf(stderr,
- "WARNING: "
- "not in system context, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- EXPECT_EQ(0, setuid(AID_SYSTEM)); // only one that can read security buffer
-
- uid = getuid();
- gid = getgid();
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_SECURITY, ANDROID_LOG_NONBLOCK,
- 1000, pid)));
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_SECURITY)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts == tx) {
- ++count;
- }
- }
-
- if (set_persist) {
- property_set(persist_key, persist);
- }
-
- android_logger_list_close(logger_list);
-
- bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
- if (!clientHasSecurityCredentials) {
- fprintf(stderr,
- "WARNING: "
- "not system, content submitted but can not check end-to-end\n");
- }
- EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-#ifdef __ANDROID__
-static void android_errorWriteWithInfoLog_helper(int tag, const char* subtag, int uid,
- const char* payload, int data_len) {
- auto write_function = [&] {
- int ret = android_errorWriteWithInfoLog(tag, subtag, uid, payload, data_len);
- ASSERT_LT(0, ret);
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* event_data = log_msg.msg();
- char* original = event_data;
-
- // Tag
- auto* event_header = reinterpret_cast<android_event_header_t*>(event_data);
- event_data += sizeof(android_event_header_t);
- if (event_header->tag != tag) {
- return;
- }
-
- // List type
- auto* event_list = reinterpret_cast<android_event_list_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_LIST, event_list->type);
- ASSERT_EQ(3, event_list->element_count);
- event_data += sizeof(android_event_list_t);
-
- // Element #1: string type for subtag
- auto* event_string_subtag = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_subtag->type);
- int32_t subtag_len = strlen(subtag);
- if (subtag_len > 32) {
- subtag_len = 32;
- }
- ASSERT_EQ(subtag_len, event_string_subtag->length);
- if (memcmp(subtag, &event_string_subtag->data, subtag_len)) {
- return;
- }
- event_data += sizeof(android_event_string_t) + subtag_len;
-
- // Element #2: int type for uid
- auto* event_int_uid = reinterpret_cast<android_event_int_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_INT, event_int_uid->type);
- ASSERT_EQ(uid, event_int_uid->data);
- event_data += sizeof(android_event_int_t);
-
- // Element #3: string type for data
- auto* event_string_data = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_data->type);
- int32_t message_data_len = event_string_data->length;
- if (data_len < 512) {
- ASSERT_EQ(data_len, message_data_len);
- }
- if (memcmp(payload, &event_string_data->data, message_data_len) != 0) {
- return;
- }
- event_data += sizeof(android_event_string_t);
-
- if (data_len >= 512) {
- event_data += message_data_len;
- // 4 bytes for the tag, and max_payload_buf should be truncated.
- ASSERT_LE(4 + 512, event_data - original); // worst expectations
- ASSERT_GT(4 + data_len, event_data - original); // must be truncated
- }
- *found = true;
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-}
-#endif
-
-// Make multiple tests and re-tests orthogonal to prevent falsing.
-#ifdef TEST_LOGGER
-#define UNIQUE_TAG(X) \
- (0x12340000 + (((X) + sizeof(int) + sizeof(void*)) << 8) + TEST_LOGGER)
-#else
-#define UNIQUE_TAG(X) \
- (0x12340000 + (((X) + sizeof(int) + sizeof(void*)) << 8) + 0xBA)
-#endif
-
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(UNIQUE_TAG(1), "test-subtag", -1, max_payload_buf, 200);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(UNIQUE_TAG(2), "test-subtag", -1, max_payload_buf,
- sizeof(max_payload_buf));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-#ifdef __ANDROID__
- int retval_android_errorWriteWithinInfoLog =
- android_errorWriteWithInfoLog(UNIQUE_TAG(3), "test-subtag", -1, nullptr, 200);
- ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(
- UNIQUE_TAG(4), "abcdefghijklmnopqrstuvwxyz now i know my abc", -1, max_payload_buf, 200);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_bswrite_and_print___max) {
- bswrite_test(max_payload_buf);
-}
-
-TEST(liblog, __android_log_buf_write_and_print__max) {
- buf_write_test(max_payload_buf);
-}
-
-TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-#ifdef __ANDROID__
- int kTag = UNIQUE_TAG(5);
- const char* kSubTag = "test-subtag";
-
- auto write_function = [&] {
- int retval_android_errorWriteLog = android_errorWriteLog(kTag, kSubTag);
- ASSERT_LT(0, retval_android_errorWriteLog);
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* event_data = log_msg.msg();
-
- // Tag
- auto* event_header = reinterpret_cast<android_event_header_t*>(event_data);
- event_data += sizeof(android_event_header_t);
- if (event_header->tag != kTag) {
- return;
- }
-
- // List type
- auto* event_list = reinterpret_cast<android_event_list_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_LIST, event_list->type);
- ASSERT_EQ(3, event_list->element_count);
- event_data += sizeof(android_event_list_t);
-
- // Element #1: string type for subtag
- auto* event_string_subtag = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_subtag->type);
- int32_t subtag_len = strlen(kSubTag);
- ASSERT_EQ(subtag_len, event_string_subtag->length);
- if (memcmp(kSubTag, &event_string_subtag->data, subtag_len) == 0) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-#ifdef __ANDROID__
- EXPECT_LT(android_errorWriteLog(UNIQUE_TAG(6), nullptr), 0);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-// Do not retest logger list handling
-#ifdef __ANDROID__
-static int is_real_element(int type) {
- return ((type == EVENT_TYPE_INT) || (type == EVENT_TYPE_LONG) ||
- (type == EVENT_TYPE_STRING) || (type == EVENT_TYPE_FLOAT));
-}
-
-static int android_log_buffer_to_string(const char* msg, size_t len,
- char* strOut, size_t strOutLen) {
- android_log_context context = create_android_log_parser(msg, len);
- android_log_list_element elem;
- bool overflow = false;
- /* Reserve 1 byte for null terminator. */
- size_t origStrOutLen = strOutLen--;
-
- if (!context) {
- return -EBADF;
- }
-
- memset(&elem, 0, sizeof(elem));
-
- size_t outCount;
-
- do {
- elem = android_log_read_next(context);
- switch ((int)elem.type) {
- case EVENT_TYPE_LIST:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = '[';
- strOutLen--;
- }
- break;
-
- case EVENT_TYPE_LIST_STOP:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ']';
- strOutLen--;
- }
- break;
-
- case EVENT_TYPE_INT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%" PRId32, elem.data.int32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- case EVENT_TYPE_LONG:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%" PRId64, elem.data.int64);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- case EVENT_TYPE_FLOAT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- default:
- elem.complete = true;
- break;
-
- case EVENT_TYPE_UNKNOWN:
-#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
- if (elem.complete) {
- break;
- }
-#endif
- elem.data.string = const_cast<char*>("<unknown>");
- elem.len = strlen(elem.data.string);
- FALLTHROUGH_INTENDED;
- case EVENT_TYPE_STRING:
- if (elem.len <= strOutLen) {
- memcpy(strOut, elem.data.string, elem.len);
- strOut += elem.len;
- strOutLen -= elem.len;
- } else if (strOutLen > 0) {
- /* copy what we can */
- memcpy(strOut, elem.data.string, strOutLen);
- strOut += strOutLen;
- strOutLen = 0;
- overflow = true;
- }
- break;
- }
-
- if (elem.complete) {
- break;
- }
- /* Determine whether to put a comma or not. */
- if (!overflow &&
- (is_real_element(elem.type) || (elem.type == EVENT_TYPE_LIST_STOP))) {
- android_log_list_element next = android_log_peek_next(context);
- if (!next.complete &&
- (is_real_element(next.type) || (next.type == EVENT_TYPE_LIST))) {
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ',';
- strOutLen--;
- }
- }
- }
- } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
-
- android_log_destroy(&context);
-
- if (overflow) {
- if (strOutLen < origStrOutLen) {
- /* leave an indicator */
- *(strOut - 1) = '!';
- } else {
- /* nothing was written at all */
- *strOut++ = '!';
- }
- }
- *strOut++ = '\0';
-
- if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- return -EINVAL;
- }
-
- return 0;
-}
-#endif // __ANDROID__
-
-#ifdef __ANDROID__
-static const char* event_test_int32(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
-
- return "1076895760";
-}
-
-static const char* event_test_int64(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t);
-
- return "-9191740941672636400";
-}
-
-static const char* event_test_list_int64(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint64_t);
-
- return "[-9191740941672636400]";
-}
-
-static const char* event_test_simple_automagic_list(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- // The convenience API where we allow a simple list to be
- // created without explicit begin or end calls.
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint64_t);
-
- return "[1076895760,-9191740941672636400]";
-}
-
-static const char* event_test_list_empty(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t);
-
- return "[]";
-}
-
-static const char* event_test_complex_nested_list(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
-
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
- EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
- EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
-
- //
- // This one checks for the automagic list creation because a list
- // begin and end was missing for it! This is actually an <oops> corner
- // case, and not the behavior we morally support. The automagic API is to
- // allow for a simple case of a series of objects in a single list. e.g.
- // int32,int32,int32,string -> [int32,int32,int32,string]
- //
- EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
-
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint8_t) +
- 4 * (sizeof(uint8_t) + sizeof(uint32_t)) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof("dlroW olleH") - 1;
-
- return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW "
- "olleH]";
-}
-
-static const char* event_test_7_level_prefix(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 7));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + 7 * (sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t));
-
- return "[[[[[[[1],2],3],4],5],6],7]";
-}
-
-static const char* event_test_7_level_suffix(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + 6 * (sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t));
-
- return "[1,[2,[3,[4,[5,[6]]]]]]";
-}
-
-static const char* event_test_android_log_error_write(uint32_t tag,
- size_t& expected_len) {
- EXPECT_LE(
- 0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
-
- return "[Hello World,42,dlroW olleH]";
-}
-
-static const char* event_test_android_log_error_write_null(uint32_t tag,
- size_t& expected_len) {
- EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof("") - 1;
-
- return "[Hello World,42,]";
-}
-
-// make sure all user buffers are flushed
-static void print_barrier() {
- std::cout.flush();
- fflush(stdout);
- std::cerr.flush();
- fflush(stderr); // everything else is paranoia ...
-}
-
-static void create_android_logger(const char* (*fn)(uint32_t tag,
- size_t& expected_len)) {
- size_t expected_len;
- const char* expected_string;
- auto write_function = [&] {
- expected_string = (*fn)(1005, expected_len);
- ASSERT_NE(nullptr, expected_string);
- };
-
- pid_t pid = getpid();
- auto check_function = [&](log_msg log_msg, bool* found) {
- if (static_cast<size_t>(log_msg.entry.len) != expected_len) {
- return;
- }
-
- char* eventData = log_msg.msg();
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- int processBinaryLogBuffer =
- android_log_processBinaryLogBuffer(&log_msg.entry, &entry, nullptr, msgBuf, sizeof(msgBuf));
- EXPECT_EQ(0, processBinaryLogBuffer);
- if (processBinaryLogBuffer == 0) {
- int line_overhead = 20;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- print_barrier();
- int printLogLine =
- android_log_printLogLine(logformat, fileno(stderr), &entry);
- print_barrier();
- EXPECT_EQ(line_overhead + (int)strlen(expected_string), printLogLine);
- }
- android_log_format_free(logformat);
-
- // test buffer reading API
- int buffer_to_string = -1;
- if (eventData) {
- auto* event_header = reinterpret_cast<android_event_header_t*>(eventData);
- eventData += sizeof(android_event_header_t);
- snprintf(msgBuf, sizeof(msgBuf), "I/[%" PRId32 "]", event_header->tag);
- print_barrier();
- fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
- memset(msgBuf, 0, sizeof(msgBuf));
- buffer_to_string =
- android_log_buffer_to_string(eventData, log_msg.entry.len, msgBuf, sizeof(msgBuf));
- fprintf(stderr, "%s\n", msgBuf);
- print_barrier();
- }
- EXPECT_EQ(0, buffer_to_string);
- EXPECT_STREQ(expected_string, msgBuf);
- *found = true;
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-}
-#endif
-
-TEST(liblog, create_android_logger_int32) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int32);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int64);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_list_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_int64);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_simple_automagic_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_simple_automagic_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_list_empty) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_empty);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_complex_nested_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_complex_nested_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_7_level_prefix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_prefix);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_7_level_suffix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_suffix);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_android_log_error_write) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_android_log_error_write_null) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write_null);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_overflow) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
- if (ctx) {
- for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- }
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- /* One more for good measure, must be permanently unhappy */
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
- }
-
- ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
- for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, i));
- }
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- /* One more for good measure, must be permanently unhappy */
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_destroy(&ctx));
- ASSERT_TRUE(NULL == ctx);
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
-static const char __pmsg_file[] =
- "/data/william-shakespeare/MuchAdoAboutNothing.txt";
-#endif /* NO_PSTORE */
-#endif
-
-TEST(liblog, __android_log_pmsg_file_write) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
- LOG_ID_CRASH, ANDROID_LOG_VERBOSE, __pmsg_file, max_payload_buf,
- sizeof(max_payload_buf));
- EXPECT_LT(0, return__android_log_pmsg_file_write);
- if (return__android_log_pmsg_file_write == -ENOMEM) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver "
- "configured\n");
- } else if (!return__android_log_pmsg_file_write) {
- fprintf(stderr,
- "Reboot, ensure file %s matches\n"
- "with liblog.__android_log_msg_file_read test\n",
- __pmsg_file);
- }
- bool pmsgActiveAfter__android_pmsg_file_write;
- bool logdwActiveAfter__android_pmsg_file_write;
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
- }
- EXPECT_LT(
- 0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_pmsg_file_write", "main"));
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
- bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
- EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
- }
- EXPECT_LT(0, __android_log_pmsg_file_write(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, max_payload_buf,
- sizeof(max_payload_buf)));
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
- }
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
-static ssize_t __pmsg_fn(log_id_t logId, char prio, const char* filename,
- const char* buf, size_t len, void* arg) {
- EXPECT_TRUE(NULL == arg);
- EXPECT_EQ(LOG_ID_CRASH, logId);
- EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
- EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
- EXPECT_EQ(len, sizeof(max_payload_buf));
- EXPECT_STREQ(max_payload_buf, buf);
-
- ++signaled;
- if ((len != sizeof(max_payload_buf)) || strcmp(max_payload_buf, buf)) {
- fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
- }
- return arg || (LOG_ID_CRASH != logId) || (ANDROID_LOG_VERBOSE != prio) ||
- !strstr(__pmsg_file, filename) ||
- (len != sizeof(max_payload_buf)) ||
- !!strcmp(max_payload_buf, buf)
- ? -ENOEXEC
- : 1;
-}
-#endif /* NO_PSTORE */
-#endif
-
-TEST(liblog, __android_log_pmsg_file_read) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- signaled = 0;
-
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
-
- ssize_t ret = __android_log_pmsg_file_read(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, __pmsg_fn, NULL);
-
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
- bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
- EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
- }
-
- if (ret == -ENOENT) {
- fprintf(stderr,
- "No pre-boot results of liblog.__android_log_mesg_file_write to "
- "compare with,\n"
- "false positive test result.\n");
- return;
- }
-
- EXPECT_LT(0, ret);
- EXPECT_EQ(1U, signaled);
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
deleted file mode 100644
index 9fb5a2c..0000000
--- a/liblog/tests/log_id_test.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_id.h>
-
-// We do not want to include <android/log.h> to acquire ANDROID_LOG_INFO for
-// include file API purity. We do however want to allow the _option_ that
-// log/log_id.h could include this file, or related content, in the future.
-#ifndef __android_LogPriority_defined
-#define ANDROID_LOG_INFO 4
-#endif
-
-TEST(liblog, log_id) {
- int count = 0;
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- const char* name = android_log_id_to_name(id);
- if (id != android_name_to_log_id(name)) {
- continue;
- }
- ++count;
- fprintf(stderr, "log buffer %s\r", name);
- }
- ASSERT_EQ(LOG_ID_MAX, count);
-}
-
-TEST(liblog, __android_log_buf_print) {
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "radio"));
- usleep(1000);
- EXPECT_LT(0,
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "main"));
- usleep(1000);
-}
-
-TEST(liblog, __android_log_buf_write) {
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "radio"));
- usleep(1000);
- EXPECT_LT(0,
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "main"));
- usleep(1000);
-}
-
-static void* ConcurrentPrintFn(void* arg) {
- int ret = __android_log_buf_print(
- LOG_ID_MAIN, ANDROID_LOG_INFO, "TEST__android_log_print",
- "Concurrent %" PRIuPTR, reinterpret_cast<uintptr_t>(arg));
- return reinterpret_cast<void*>(ret);
-}
-
-#define NUM_CONCURRENT 64
-#define _concurrent_name(a, n) a##__concurrent##n
-#define concurrent_name(a, n) _concurrent_name(a, n)
-
-TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
- pthread_t t[NUM_CONCURRENT];
- int i;
- for (i = 0; i < NUM_CONCURRENT; i++) {
- ASSERT_EQ(0, pthread_create(&t[i], NULL, ConcurrentPrintFn,
- reinterpret_cast<void*>(i)));
- }
- int ret = 1;
- for (i = 0; i < NUM_CONCURRENT; i++) {
- void* result;
- ASSERT_EQ(0, pthread_join(t[i], &result));
- int this_result = reinterpret_cast<uintptr_t>(result);
- if ((0 < ret) && (ret != this_result)) {
- ret = this_result;
- }
- }
- ASSERT_LT(0, ret);
-}
diff --git a/liblog/tests/log_radio_test.cpp b/liblog/tests/log_radio_test.cpp
deleted file mode 100644
index fa1255e..0000000
--- a/liblog/tests/log_radio_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_radio.h>
-
-TEST(liblog, RLOG) {
- static const char content[] = "log_radio.h";
- static const char content_false[] = "log_radio.h false";
-
-// ratelimit content to 10/s to keep away from spam filters
-// do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV_IF(true, content);
- usleep(100000);
- RLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD_IF(true, content);
- usleep(100000);
- RLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI_IF(true, content);
- usleep(100000);
- RLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW_IF(true, content);
- usleep(100000);
- RLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE_IF(true, content);
- usleep(100000);
- RLOGE_IF(false, content_false);
-
-#ifdef __ANDROID__
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b radio --pid=%u -d -s"
- " TEST__RLOGV TEST__RLOGD TEST__RLOGI TEST__RLOGW TEST__RLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "re");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
- ++pos) {
- ++count;
- }
- for (size_t pos = 0;
- (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
- }
- EXPECT_EQ(0, count_false);
-#if LOG_NDEBUG
- ASSERT_EQ(8, count);
-#else
- ASSERT_EQ(10, count);
-#endif
-
-#else
- GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
-#endif
-}
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
deleted file mode 100644
index 7acd363..0000000
--- a/liblog/tests/log_read_test.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android/log.h> // minimal logging API
-#include <gtest/gtest.h>
-#include <log/log_properties.h>
-// Test the APIs in this standalone include file
-#include <log/log_read.h>
-// Do not use anything in log/log_time.h despite side effects of the above.
-#include <private/android_logger.h>
-
-using android::base::GetBoolProperty;
-
-TEST(liblog, android_logger_get_) {
-#ifdef __ANDROID__
- // This test assumes the log buffers are filled with noise from
- // normal operations. It will fail if done immediately after a
- // logcat -c.
- struct logger_list* logger_list = android_logger_list_alloc(0, 0, 0);
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- std::string name = android_log_id_to_name(id);
- fprintf(stderr, "log buffer %s\r", name.c_str());
- struct logger* logger;
- EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
- EXPECT_EQ(id, android_logger_get_id(logger));
- ssize_t get_log_size = android_logger_get_log_size(logger);
- /* security buffer is allowed to be denied */
- if (name != "security") {
- EXPECT_GT(get_log_size, 0);
- // crash buffer is allowed to be empty, that is actually healthy!
- // stats buffer is no longer in use.
- if (name == "crash" || name == "stats") {
- continue;
- }
-
- // kernel buffer is empty if ro.logd.kernel is false
- if (name == "kernel" && !GetBoolProperty("ro.logd.kernel", false)) {
- continue;
- }
-
- EXPECT_LE(0, android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_NE(0, get_log_size);
- if (get_log_size < 0) {
- EXPECT_GT(0, android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_LE(0, android_logger_get_log_readable_size(logger));
- }
- }
- }
-
- android_logger_list_close(logger_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/log_system_test.cpp b/liblog/tests/log_system_test.cpp
deleted file mode 100644
index 13f026d..0000000
--- a/liblog/tests/log_system_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_system.h>
-
-TEST(liblog, SLOG) {
- static const char content[] = "log_system.h";
- static const char content_false[] = "log_system.h false";
-
-// ratelimit content to 10/s to keep away from spam filters
-// do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV_IF(true, content);
- usleep(100000);
- SLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD_IF(true, content);
- usleep(100000);
- SLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI_IF(true, content);
- usleep(100000);
- SLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW_IF(true, content);
- usleep(100000);
- SLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE_IF(true, content);
- usleep(100000);
- SLOGE_IF(false, content_false);
-
-#ifdef __ANDROID__
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b system --pid=%u -d -s"
- " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "re");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
- ++pos) {
- ++count;
- }
- for (size_t pos = 0;
- (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
- }
- EXPECT_EQ(0, count_false);
-#if LOG_NDEBUG
- ASSERT_EQ(8, count);
-#else
- ASSERT_EQ(10, count);
-#endif
-
-#else
- GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
-#endif
-}
diff --git a/liblog/tests/log_time_test.cpp b/liblog/tests/log_time_test.cpp
deleted file mode 100644
index 47fe594..0000000
--- a/liblog/tests/log_time_test.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 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 <time.h>
-
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_time.h>
-
-TEST(liblog, log_time) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- log_time tl(ts);
-
- EXPECT_EQ(tl, ts);
- EXPECT_GE(tl, ts);
- EXPECT_LE(tl, ts);
-}
diff --git a/liblog/tests/log_wrap_test.cpp b/liblog/tests/log_wrap_test.cpp
deleted file mode 100644
index 755898a..0000000
--- a/liblog/tests/log_wrap_test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/stringprintf.h>
-#include <android/log.h> // minimal logging API
-#include <gtest/gtest.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <log/log_time.h>
-
-#ifdef __ANDROID__
-static void read_with_wrap() {
- // Read the last line in the log to get a starting timestamp. We're assuming
- // the log is not empty.
- const int mode = ANDROID_LOG_NONBLOCK;
- struct logger_list* logger_list =
- android_logger_list_open(LOG_ID_MAIN, mode, 1000, 0);
-
- ASSERT_NE(logger_list, nullptr);
-
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- android_logger_list_close(logger_list);
- ASSERT_GT(ret, 0);
-
- log_time start(log_msg.entry.sec, log_msg.entry.nsec);
- ASSERT_NE(start, log_time());
-
- logger_list =
- android_logger_list_alloc_time(mode | ANDROID_LOG_WRAP, start, 0);
- ASSERT_NE(logger_list, nullptr);
-
- struct logger* logger = android_logger_open(logger_list, LOG_ID_MAIN);
- EXPECT_NE(logger, nullptr);
- if (logger) {
- android_logger_list_read(logger_list, &log_msg);
- }
-
- android_logger_list_close(logger_list);
-}
-#endif
-
-// b/64143705 confirm fixed
-TEST(liblog, wrap_mode_blocks) {
-#ifdef __ANDROID__
- // The read call is expected to take up to 2 hours in the happy case. There was a previous bug
- // where it would take only 30 seconds due to an alarm() in logd_reader.cpp. That alarm has been
- // removed, so we check here that the read call blocks for a reasonable amount of time (5s).
-
- struct sigaction ignore = {.sa_handler = [](int) { _exit(0); }};
- struct sigaction old_sigaction;
- sigaction(SIGALRM, &ignore, &old_sigaction);
- alarm(5);
-
- android::base::Timer timer;
- read_with_wrap();
-
- FAIL() << "read_with_wrap() should not return before the alarm is triggered.";
-
- alarm(0);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/logd_writer_test.cpp b/liblog/tests/logd_writer_test.cpp
deleted file mode 100644
index b8e4726..0000000
--- a/liblog/tests/logd_writer_test.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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 <sys/un.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-
-using android::base::StringPrintf;
-using android::base::unique_fd;
-
-// logd_writer takes advantage of the fact that connect() can be called multiple times for a DGRAM
-// socket. This tests for that behavior.
-TEST(liblog, multi_connect_dgram_socket) {
-#ifdef __ANDROID__
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
- auto temp_dir = TemporaryDir();
- auto socket_path = StringPrintf("%s/test_socket", temp_dir.path);
-
- unique_fd server_socket;
-
- auto open_server_socket = [&] {
- server_socket.reset(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)));
- ASSERT_TRUE(server_socket.ok());
-
- sockaddr_un server_sockaddr = {};
- server_sockaddr.sun_family = AF_UNIX;
- strlcpy(server_sockaddr.sun_path, socket_path.c_str(), sizeof(server_sockaddr.sun_path));
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(bind(server_socket, reinterpret_cast<sockaddr*>(&server_sockaddr),
- sizeof(server_sockaddr))));
- };
-
- // Open the server socket.
- open_server_socket();
-
- // Open the client socket.
- auto client_socket =
- unique_fd{TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0))};
- ASSERT_TRUE(client_socket.ok());
- sockaddr_un client_sockaddr = {};
- client_sockaddr.sun_family = AF_UNIX;
- strlcpy(client_sockaddr.sun_path, socket_path.c_str(), sizeof(client_sockaddr.sun_path));
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
- sizeof(client_sockaddr))));
-
- // Ensure that communication works.
- constexpr static char kSmoke[] = "smoke test";
- ssize_t smoke_len = sizeof(kSmoke);
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- char read_buf[512];
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
- ASSERT_STREQ(kSmoke, read_buf);
-
- // Close the server socket.
- server_socket.reset();
- ASSERT_EQ(0, unlink(socket_path.c_str())) << strerror(errno);
-
- // Ensure that write() from the client returns an error since the server is closed.
- ASSERT_EQ(-1, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- ASSERT_EQ(errno, ECONNREFUSED) << strerror(errno);
-
- // Open the server socket again.
- open_server_socket();
-
- // Reconnect the same client socket.
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
- sizeof(client_sockaddr))))
- << strerror(errno);
-
- // Ensure that communication works.
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
- ASSERT_STREQ(kSmoke, read_buf);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
\ No newline at end of file
diff --git a/liblog/tests/logprint_test.cpp b/liblog/tests/logprint_test.cpp
deleted file mode 100644
index 72e53f9..0000000
--- a/liblog/tests/logprint_test.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2019 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 <log/logprint.h>
-
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <log/log_read.h>
-
-size_t convertPrintable(char* p, const char* message, size_t messageLen);
-
-TEST(liblog, convertPrintable_ascii) {
- auto input = "easy string, output same";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
- EXPECT_STREQ(input, output);
-}
-
-TEST(liblog, convertPrintable_escapes) {
- // Note that \t is not escaped.
- auto input = "escape\a\b\t\v\f\r\\";
- auto expected_output = "escape\\a\\b\t\\v\\f\\r\\\\";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, convertPrintable_validutf8) {
- auto input = u8"¢ह€𐍈";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
- EXPECT_STREQ(input, output);
-}
-
-TEST(liblog, convertPrintable_invalidutf8) {
- auto input = "\x80\xC2\x01\xE0\xA4\x06\xE0\x06\xF0\x90\x8D\x06\xF0\x90\x06\xF0\x0E";
- auto expected_output =
- "\\x80\\xC2\\x01\\xE0\\xA4\\x06\\xE0\\x06\\xF0\\x90\\x8D\\x06\\xF0\\x90\\x06\\xF0\\x0E";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, convertPrintable_mixed) {
- auto input =
- u8"\x80\xC2¢ह€𐍈\x01\xE0\xA4\x06¢ह€𐍈\xE0\x06\a\b\xF0\x90¢ह€𐍈\x8D\x06\xF0\t\t\x90\x06\xF0\x0E";
- auto expected_output =
- u8"\\x80\\xC2¢ह€𐍈\\x01\\xE0\\xA4\\x06¢ह€𐍈\\xE0\\x06\\a\\b\\xF0\\x90¢ह€𐍈\\x8D\\x06\\xF0\t\t"
- u8"\\x90\\x06\\xF0\\x0E";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, log_print_different_header_size) {
- constexpr int32_t kPid = 123;
- constexpr uint32_t kTid = 456;
- constexpr uint32_t kSec = 1000;
- constexpr uint32_t kNsec = 999;
- constexpr uint32_t kLid = LOG_ID_MAIN;
- constexpr uint32_t kUid = 987;
- constexpr char kPriority = ANDROID_LOG_ERROR;
-
- auto create_buf = [](char* buf, size_t len, uint16_t hdr_size) {
- memset(buf, 0, len);
- logger_entry* header = reinterpret_cast<logger_entry*>(buf);
- header->hdr_size = hdr_size;
- header->pid = kPid;
- header->tid = kTid;
- header->sec = kSec;
- header->nsec = kNsec;
- header->lid = kLid;
- header->uid = kUid;
- char* message = buf + header->hdr_size;
- uint16_t message_len = 0;
- message[message_len++] = kPriority;
- message[message_len++] = 'T';
- message[message_len++] = 'a';
- message[message_len++] = 'g';
- message[message_len++] = '\0';
- message[message_len++] = 'm';
- message[message_len++] = 's';
- message[message_len++] = 'g';
- message[message_len++] = '!';
- message[message_len++] = '\0';
- header->len = message_len;
- };
-
- auto check_entry = [&](const AndroidLogEntry& entry) {
- EXPECT_EQ(kSec, static_cast<uint32_t>(entry.tv_sec));
- EXPECT_EQ(kNsec, static_cast<uint32_t>(entry.tv_nsec));
- EXPECT_EQ(kPriority, entry.priority);
- EXPECT_EQ(kUid, static_cast<uint32_t>(entry.uid));
- EXPECT_EQ(kPid, entry.pid);
- EXPECT_EQ(kTid, static_cast<uint32_t>(entry.tid));
- EXPECT_STREQ("Tag", entry.tag);
- EXPECT_EQ(4U, entry.tagLen); // Apparently taglen includes the nullptr?
- EXPECT_EQ(4U, entry.messageLen);
- EXPECT_STREQ("msg!", entry.message);
- };
- alignas(logger_entry) char buf[LOGGER_ENTRY_MAX_LEN];
- create_buf(buf, sizeof(buf), sizeof(logger_entry));
-
- AndroidLogEntry entry_normal_size;
- ASSERT_EQ(0,
- android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_normal_size));
- check_entry(entry_normal_size);
-
- create_buf(buf, sizeof(buf), sizeof(logger_entry) + 3);
- AndroidLogEntry entry_odd_size;
- ASSERT_EQ(0, android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_odd_size));
- check_entry(entry_odd_size);
-}
\ No newline at end of file
diff --git a/liblog/uio.h b/liblog/uio.h
deleted file mode 100644
index c85893c..0000000
--- a/liblog/uio.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2019 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
-
-#if defined(_WIN32)
-#include <stddef.h>
-struct iovec {
- void* iov_base;
- size_t iov_len;
-};
-#else
-#include <sys/uio.h>
-#endif
diff --git a/logcat b/logcat
new file mode 120000
index 0000000..6c27286
--- /dev/null
+++ b/logcat
@@ -0,0 +1 @@
+../logging/logcat
\ No newline at end of file
diff --git a/logcat/Android.bp b/logcat/Android.bp
deleted file mode 100644
index 61fba59..0000000
--- a/logcat/Android.bp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (C) 2006 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.
-//
-
-cc_defaults {
- name: "logcat_defaults",
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
- ],
- shared_libs: [
- "libbase",
- "libprocessgroup",
- ],
- static_libs: ["liblog"],
- logtags: ["event.logtags"],
-}
-
-cc_binary {
- name: "logcat",
-
- defaults: ["logcat_defaults"],
- srcs: [
- "logcat.cpp",
- ],
-}
-
-sh_binary {
- name: "logcatd",
- src: "logcatd",
-}
-
-sh_binary {
- name: "logpersist.start",
- src: "logpersist",
- init_rc: ["logcatd.rc"],
- required: ["logcatd"],
- symlinks: [
- "logpersist.stop",
- "logpersist.cat",
- ],
-}
diff --git a/logcat/MODULE_LICENSE_APACHE2 b/logcat/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/logcat/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/logcat/NOTICE b/logcat/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/logcat/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/logcat/OWNERS b/logcat/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/logcat/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/logcat/event.logtags b/logcat/event.logtags
deleted file mode 100644
index 93c3d6d..0000000
--- a/logcat/event.logtags
+++ /dev/null
@@ -1,159 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-# 5: float
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-# These are used for testing, do not modify without updating
-# tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
-# system/core/liblog/tests/liblog_benchmark.cpp
-# system/core/liblog/tests/liblog_test.cpp
-42 answer (to life the universe etc|3)
-314 pi
-2718 e
-
-# "account" is the java hash of the account name
-2720 sync (id|3),(event|1|5),(source|1|5),(account|1|5)
-
-# This event is logged when the location service uploads location data.
-2740 location_controller
-# This event is logged when someone is deciding to force a garbage collection
-2741 force_gc (reason|3)
-# This event is logged on each tickle
-2742 tickle (authority|3)
-
-# contacts aggregation: time and number of contacts.
-# count is negative for query phase, positive for merge phase
-2747 contacts_aggregation (aggregation time|2|3), (count|1|1)
-
-# Device boot timings. We include monotonic clock values because the
-# intrinsic event log times are wall-clock.
-#
-# Runtime starts:
-3000 boot_progress_start (time|2|3)
-# ZygoteInit class preloading starts:
-3020 boot_progress_preload_start (time|2|3)
-# ZygoteInit class preloading ends:
-3030 boot_progress_preload_end (time|2|3)
-
-# Dalvik VM / ART
-20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)
-20004 art_hidden_api_access (access_method|1),(flags|1),(class|3),(member|3),(type_signature|3)
-
-75000 sqlite_mem_alarm_current (current|1|2)
-75001 sqlite_mem_alarm_max (max|1|2)
-75002 sqlite_mem_alarm_alloc_attempt (attempts|1|4)
-75003 sqlite_mem_released (Memory released|1|2)
-75004 sqlite_db_corrupt (Database file corrupt|3)
-
-50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
-50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
-
-# HSM wifi state change
-# Hierarchical state class name (as defined in WifiStateTracker.java)
-# Logged on every state change in the hierarchical state machine
-50021 wifi_state_changed (wifi_state|3)
-# HSM wifi event
-# [31-16] Reserved for future use
-# [15 - 0] HSM event (as defined in WifiStateTracker.java)
-# Logged when an event is handled in a hierarchical state
-50022 wifi_event_handled (wifi_event|1|5)
-# Supplicant state change
-# [31-13] Reserved for future use
-# [8 - 0] Supplicant state (as defined in SupplicantState.java)
-# Logged when the supplicant switches to a new state
-50023 wifi_supplicant_state_changed (supplicant_state|1|5)
-
-# Database operation samples.
-# db: the filename of the database
-# sql: the executed query (without query args)
-# time: cpu time millis (not wall time), including lock acquisition
-# blocking_package: if this is on a main thread, the package name, otherwise ""
-# sample_percent: the percent likelihood this query was logged
-52000 db_sample (db|3),(sql|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
-
-# http request/response stats
-52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2)
-60000 viewroot_draw (Draw time|1|3)
-60001 viewroot_layout (Layout time|1|3)
-60002 view_build_drawing_cache (View created drawing cache|1|5)
-60003 view_use_drawing_cache (View drawn using bitmap cache|1|5)
-
-# graphics timestamp
-# 60100 - 60199 reserved for surfaceflinger
-
-# audio
-# 61000 - 61199 reserved for audioserver
-
-# input
-# 62000 - 62199 reserved for inputflinger
-
-# com.android.server.policy
-# 70000 - 70199 reserved for PhoneWindowManager and other policies
-
-# aggregation service
-70200 aggregation (aggregation time|2|3)
-70201 aggregation_test (field1|1|2),(field2|1|2),(field3|1|2),(field4|1|2),(field5|1|2)
-
-# gms refuses to register this log tag, b/30156345
-70220 gms_unknown
-
-# libc failure logging
-80100 bionic_event_memcpy_buffer_overflow (uid|1)
-80105 bionic_event_strcat_buffer_overflow (uid|1)
-80110 bionic_event_memmov_buffer_overflow (uid|1)
-80115 bionic_event_strncat_buffer_overflow (uid|1)
-80120 bionic_event_strncpy_buffer_overflow (uid|1)
-80125 bionic_event_memset_buffer_overflow (uid|1)
-80130 bionic_event_strcpy_buffer_overflow (uid|1)
-
-80200 bionic_event_strcat_integer_overflow (uid|1)
-80205 bionic_event_strncat_integer_overflow (uid|1)
-
-80300 bionic_event_resolver_old_response (uid|1)
-80305 bionic_event_resolver_wrong_server (uid|1)
-80310 bionic_event_resolver_wrong_query (uid|1)
-
-# libcore failure logging
-90100 exp_det_cert_pin_failure (certs|4)
-
-# 150000 - 160000 reserved for Android Automotive builds
-
-1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
-
-# for events that go to stats log buffer
-1937006964 stats_log (atom_id|1|5),(data|4)
-
-# NOTE - the range 1000000-2000000 is reserved for partners and others who
-# want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
deleted file mode 100644
index 6b7e016..0000000
--- a/logcat/logcat.cpp
+++ /dev/null
@@ -1,1212 +0,0 @@
-/*
- * Copyright (C) 2006-2017 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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <math.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <memory>
-#include <regex>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <android/log.h>
-#include <log/event_tag_map.h>
-#include <log/log_id.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
-#include <system/thread_defs.h>
-
-#define DEFAULT_MAX_ROTATED_LOGS 4
-
-using android::base::Join;
-using android::base::ParseByteCount;
-using android::base::ParseUint;
-using android::base::Split;
-using android::base::StringPrintf;
-using android::base::WriteFully;
-
-class Logcat {
- public:
- int Run(int argc, char** argv);
-
- private:
- void RotateLogs();
- void ProcessBuffer(struct log_msg* buf);
- void PrintDividers(log_id_t log_id, bool print_dividers);
- void SetupOutputAndSchedulingPolicy(bool blocking);
- int SetLogFormat(const char* format_string);
-
- // Used for all options
- android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
- std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
- android_log_format_new(), &android_log_format_free};
-
- // For logging to a file and log rotation
- const char* output_file_name_ = nullptr;
- size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
- size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
- size_t out_byte_count_ = 0;
-
- // For binary log buffers
- int print_binary_ = 0;
- std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
- nullptr, &android_closeEventTagMap};
- bool has_opened_event_tag_map_ = false;
-
- // For the related --regex, --max-count, --print
- std::unique_ptr<std::regex> regex_;
- size_t max_count_ = 0; // 0 means "infinite"
- size_t print_count_ = 0;
- bool print_it_anyways_ = false;
-
- // For PrintDividers()
- log_id_t last_printed_id_ = LOG_ID_MAX;
- bool printed_start_[LOG_ID_MAX] = {};
-
- bool debug_ = false;
-};
-
-#ifndef F2FS_IOC_SET_PIN_FILE
-#define F2FS_IOCTL_MAGIC 0xf5
-#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
-#endif
-
-static int openLogFile(const char* pathname, size_t sizeKB) {
- int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
- if (fd < 0) {
- return fd;
- }
-
- // no need to check errors
- __u32 set = 1;
- ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
- fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
- return fd;
-}
-
-static void closeLogFile(const char* pathname) {
- int fd = open(pathname, O_WRONLY | O_CLOEXEC);
- if (fd == -1) {
- return;
- }
-
- // no need to check errors
- __u32 set = 0;
- ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
- close(fd);
-}
-
-void Logcat::RotateLogs() {
- // Can't rotate logs if we're not outputting to a file
- if (!output_file_name_) return;
-
- output_fd_.reset();
-
- // Compute the maximum number of digits needed to count up to
- // maxRotatedLogs in decimal. eg:
- // maxRotatedLogs == 30
- // -> log10(30) == 1.477
- // -> maxRotationCountDigits == 2
- int max_rotation_count_digits =
- max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
-
- for (int i = max_rotated_logs_; i > 0; i--) {
- std::string file1 =
- StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
-
- std::string file0;
- if (!(i - 1)) {
- file0 = output_file_name_;
- } else {
- file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
- }
-
- if (!file0.length() || !file1.length()) {
- perror("while rotating log files");
- break;
- }
-
- closeLogFile(file0.c_str());
-
- int err = rename(file0.c_str(), file1.c_str());
-
- if (err < 0 && errno != ENOENT) {
- perror("while rotating log files");
- }
- }
-
- output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
-
- if (!output_fd_.ok()) {
- error(EXIT_FAILURE, errno, "Couldn't open output file");
- }
-
- out_byte_count_ = 0;
-}
-
-void Logcat::ProcessBuffer(struct log_msg* buf) {
- int bytesWritten = 0;
- int err;
- AndroidLogEntry entry;
- char binaryMsgBuf[1024];
-
- bool is_binary =
- buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
-
- if (is_binary) {
- if (!event_tag_map_ && !has_opened_event_tag_map_) {
- event_tag_map_.reset(android_openEventTagMap(nullptr));
- has_opened_event_tag_map_ = true;
- }
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
- binaryMsgBuf, sizeof(binaryMsgBuf));
- // printf(">>> pri=%d len=%d msg='%s'\n",
- // entry.priority, entry.messageLen, entry.message);
- } else {
- err = android_log_processLogBuffer(&buf->entry, &entry);
- }
- if (err < 0 && !debug_) return;
-
- if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = !regex_ ||
- std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
-
- print_count_ += match;
- if (match || print_it_anyways_) {
- bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
-
- if (bytesWritten < 0) {
- error(EXIT_FAILURE, 0, "Output error.");
- }
- }
- }
-
- out_byte_count_ += bytesWritten;
-
- if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
- RotateLogs();
- }
-}
-
-void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
- if (log_id == last_printed_id_ || print_binary_) {
- return;
- }
- if (!printed_start_[log_id] || print_dividers) {
- if (dprintf(output_fd_.get(), "--------- %s %s\n",
- printed_start_[log_id] ? "switch to" : "beginning of",
- android_log_id_to_name(log_id)) < 0) {
- error(EXIT_FAILURE, errno, "Output error");
- }
- }
- last_printed_id_ = log_id;
- printed_start_[log_id] = true;
-}
-
-void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
- if (!output_file_name_) return;
-
- if (blocking) {
- // Lower priority and set to batch scheduling if we are saving
- // the logs into files and taking continuous content.
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- fprintf(stderr, "failed to set background scheduling policy\n");
- }
-
- struct sched_param param = {};
- if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
- fprintf(stderr, "failed to set to batch scheduler\n");
- }
-
- if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
- fprintf(stderr, "failed set to priority\n");
- }
- }
-
- output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
-
- if (!output_fd_.ok()) {
- error(EXIT_FAILURE, errno, "Couldn't open output file");
- }
-
- struct stat statbuf;
- if (fstat(output_fd_.get(), &statbuf) == -1) {
- error(EXIT_FAILURE, errno, "Couldn't get output file stat");
- }
-
- if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- error(EXIT_FAILURE, 0, "Invalid output file stat.");
- }
-
- out_byte_count_ = statbuf.st_size;
-}
-
-// clang-format off
-static void show_help() {
- const char* cmd = getprogname();
-
- fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
-
- fprintf(stderr, R"init(
-General options:
- -b, --buffer=<buffer> Request alternate ring buffer(s):
- main system radio events crash default all
- Additionally, 'kernel' for userdebug and eng builds, and
- 'security' for Device Owner installations.
- Multiple -b parameters or comma separated list of buffers are
- allowed. Buffers are interleaved.
- Default -b main,system,crash,kernel.
- -L, --last Dump logs from prior to last reboot from pstore.
- -c, --clear Clear (flush) the entire log and exit.
- if -f is specified, clear the specified file and its related rotated
- log files instead.
- if -L is specified, clear pstore log instead.
- -d Dump the log and then exit (don't block).
- --pid=<pid> Only print logs from the given pid.
- --wrap Sleep for 2 hours or when buffer about to wrap whichever
- comes first. Improves efficiency of polling by providing
- an about-to-wrap wakeup.
-
-Formatting:
- -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
- brief help long process raw tag thread threadtime time
- Modifying adverbs can be added:
- color descriptive epoch monotonic printable uid usec UTC year zone
- Multiple -v parameters or comma separated list of format and format
- modifiers are allowed.
- -D, --dividers Print dividers between each log buffer.
- -B, --binary Output the log in binary.
-
-Outfile files:
- -f, --file=<file> Log to file instead of stdout.
- -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
- -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
- --id=<id> If the signature <id> for logging to file changes, then clear the
- associated files and continue.
-
-Logd control:
- These options send a control message to the logd daemon on device, print its return message if
- applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
- -g, --buffer-size Get the size of the ring buffers within logd.
- -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
- This can individually control each buffer's size with -b.
- -S, --statistics Output statistics.
- --pid can be used to provide pid specific stats.
- -p, --prune Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
- '~' prefix indicates that elements matching the rule should be pruned
- with higher priority otherwise they're pruned with lower priority. All
- other pruning activity is oldest first. Special case ~! represents an
- automatic pruning for the noisiest UID as determined by the current
- statistics. Special case ~1000/! represents pruning of the worst PID
- within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
- -P, --prune='<list> ...' Set prune rules, using same format as listed above. Must be quoted.
-
-Filtering:
- -s Set default filter to silent. Equivalent to filterspec '*:S'
- -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
- an ECMAScript regular expression.
- -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
- --regex, but will work on its own.
- --print This option is only applicable when --regex is set and only useful if
- --max-count is also provided.
- With --print, logcat will print all messages even if they do not
- match the regex. Logcat will quit after printing the max-count number
- of lines that match the regex.
- -t <count> Print only the most recent <count> lines (implies -d).
- -t '<time>' Print the lines since specified time (implies -d).
- -T <count> Print only the most recent <count> lines (does not imply -d).
- -T '<time>' Print the lines since specified time (not imply -d).
- count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
- 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
- --uid=<uids> Only display log messages from UIDs present in the comma separate list
- <uids>. No name look-up is performed, so UIDs must be provided as
- numeric values. This option is only useful for the 'root', 'log', and
- 'system' users since only those users can view logs from other users.
-)init");
-
- fprintf(stderr, "\nfilterspecs are a series of \n"
- " <tag>[:priority]\n\n"
- "where <tag> is a log component tag (or * for all) and priority is:\n"
- " V Verbose (default for <tag>)\n"
- " D Debug (default for '*')\n"
- " I Info\n"
- " W Warn\n"
- " E Error\n"
- " F Fatal\n"
- " S Silent (suppress all output)\n"
- "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
- "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
- "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
- "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
- "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
- "or defaults to \"threadtime\"\n\n");
-}
-
-static void show_format_help() {
- fprintf(stderr,
- "-v <format>, --format=<format> options:\n"
- " Sets log print format verb and adverbs, where <format> is:\n"
- " brief long process raw tag thread threadtime time\n"
- " and individually flagged modifying adverbs can be added:\n"
- " color descriptive epoch monotonic printable uid usec UTC year zone\n"
- "\nSingle format verbs:\n"
- " brief — Display priority/tag and PID of the process issuing the message.\n"
- " long — Display all metadata fields, separate messages with blank lines.\n"
- " process — Display PID only.\n"
- " raw — Display the raw log message, with no other metadata fields.\n"
- " tag — Display the priority/tag only.\n"
- " thread — Display priority, PID and TID of process issuing the message.\n"
- " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
- " and TID of the thread issuing the message. (the default format).\n"
- " time — Display the date, invocation time, priority/tag, and PID of the\n"
- " process issuing the message.\n"
- "\nAdverb modifiers can be used in combination:\n"
- " color — Display in highlighted color to match priority. i.e. \x1B[39mVERBOSE\n"
- " \x1B[34mDEBUG \x1B[32mINFO \x1B[33mWARNING \x1B[31mERROR FATAL\x1B[0m\n"
- " descriptive — events logs only, descriptions from event-log-tags database.\n"
- " epoch — Display time as seconds since Jan 1 1970.\n"
- " monotonic — Display time as cpu seconds since last boot.\n"
- " printable — Ensure that any binary logging content is escaped.\n"
- " uid — If permitted, display the UID or Android ID of logged process.\n"
- " usec — Display time down the microsecond precision.\n"
- " UTC — Display time as UTC.\n"
- " year — Add the year to the displayed time.\n"
- " zone — Add the local timezone to the displayed time.\n"
- " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
- );
-}
-// clang-format on
-
-int Logcat::SetLogFormat(const char* format_string) {
- AndroidLogPrintFormat format = android_log_formatFromString(format_string);
-
- // invalid string?
- if (format == FORMAT_OFF) return -1;
-
- return android_log_setPrintFormat(logformat_.get(), format);
-}
-
-static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
- static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
- size_t i;
- for (i = 0;
- (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
- value /= 1024, ++i)
- ;
- return std::make_pair(value, multipliers[i]);
-}
-
-static char* parseTime(log_time& t, const char* cp) {
- char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
- if (ep) return ep;
- ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
- if (ep) return ep;
- return t.strptime(cp, "%s.%q");
-}
-
-// Find last logged line in <outputFileName>, or <outputFileName>.1
-static log_time lastLogTime(const char* outputFileName) {
- log_time retval(log_time::EPOCH);
- if (!outputFileName) return retval;
-
- std::string directory;
- const char* file = strrchr(outputFileName, '/');
- if (!file) {
- directory = ".";
- file = outputFileName;
- } else {
- directory = std::string(outputFileName, file - outputFileName);
- ++file;
- }
-
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
- closedir);
- if (!dir.get()) return retval;
-
- log_time now(CLOCK_REALTIME);
-
- size_t len = strlen(file);
- log_time modulo(0, NS_PER_SEC);
- struct dirent* dp;
-
- while (!!(dp = readdir(dir.get()))) {
- if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
- (dp->d_name[len] && ((dp->d_name[len] != '.') ||
- (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
- continue;
- }
-
- std::string file_name = directory;
- file_name += "/";
- file_name += dp->d_name;
- std::string file;
- if (!android::base::ReadFileToString(file_name, &file)) continue;
-
- bool found = false;
- for (const auto& line : android::base::Split(file, "\n")) {
- log_time t(log_time::EPOCH);
- char* ep = parseTime(t, line.c_str());
- if (!ep || (*ep != ' ')) continue;
- // determine the time precision of the logs (eg: msec or usec)
- for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
- if (t.tv_nsec % (mod * 10)) {
- modulo.tv_nsec = mod;
- break;
- }
- }
- // We filter any times later than current as we may not have the
- // year stored with each log entry. Also, since it is possible for
- // entries to be recorded out of order (very rare) we select the
- // maximum we find just in case.
- if ((t < now) && (t > retval)) {
- retval = t;
- found = true;
- }
- }
- // We count on the basename file to be the definitive end, so stop here.
- if (!dp->d_name[len] && found) break;
- }
- if (retval == log_time::EPOCH) return retval;
- // tail_time prints matching or higher, round up by the modulo to prevent
- // a replay of the last entry we have just checked.
- retval += modulo;
- return retval;
-}
-
-void ReportErrorName(const std::string& name, bool allow_security,
- std::vector<std::string>* errors) {
- if (allow_security || name != "security") {
- errors->emplace_back(name);
- }
-}
-
-int Logcat::Run(int argc, char** argv) {
- bool hasSetLogFormat = false;
- bool clearLog = false;
- bool security_buffer_selected =
- false; // Do not report errors on the security buffer unless it is explicitly named.
- bool getLogSize = false;
- bool getPruneList = false;
- bool printStatistics = false;
- bool printDividers = false;
- unsigned long setLogSize = 0;
- const char* setPruneList = nullptr;
- const char* setId = nullptr;
- int mode = 0;
- std::string forceFilters;
- size_t tail_lines = 0;
- log_time tail_time(log_time::EPOCH);
- size_t pid = 0;
- bool got_t = false;
- unsigned id_mask = 0;
- std::set<uid_t> uids;
-
- if (argc == 2 && !strcmp(argv[1], "--help")) {
- show_help();
- return EXIT_SUCCESS;
- }
-
- // meant to catch comma-delimited values, but cast a wider
- // net for stability dealing with possible mistaken inputs.
- static const char delimiters[] = ",:; \t\n\r\f";
-
- optind = 0;
- while (true) {
- int option_index = 0;
- // list of long-argument only strings for later comparison
- static const char pid_str[] = "pid";
- static const char debug_str[] = "debug";
- static const char id_str[] = "id";
- static const char wrap_str[] = "wrap";
- static const char print_str[] = "print";
- static const char uid_str[] = "uid";
- // clang-format off
- static const struct option long_options[] = {
- { "binary", no_argument, nullptr, 'B' },
- { "buffer", required_argument, nullptr, 'b' },
- { "buffer-size", optional_argument, nullptr, 'g' },
- { "clear", no_argument, nullptr, 'c' },
- { debug_str, no_argument, nullptr, 0 },
- { "dividers", no_argument, nullptr, 'D' },
- { "file", required_argument, nullptr, 'f' },
- { "format", required_argument, nullptr, 'v' },
- // hidden and undocumented reserved alias for --regex
- { "grep", required_argument, nullptr, 'e' },
- // hidden and undocumented reserved alias for --max-count
- { "head", required_argument, nullptr, 'm' },
- { "help", no_argument, nullptr, 'h' },
- { id_str, required_argument, nullptr, 0 },
- { "last", no_argument, nullptr, 'L' },
- { "max-count", required_argument, nullptr, 'm' },
- { pid_str, required_argument, nullptr, 0 },
- { print_str, no_argument, nullptr, 0 },
- { "prune", optional_argument, nullptr, 'p' },
- { "regex", required_argument, nullptr, 'e' },
- { "rotate-count", required_argument, nullptr, 'n' },
- { "rotate-kbytes", required_argument, nullptr, 'r' },
- { "statistics", no_argument, nullptr, 'S' },
- // hidden and undocumented reserved alias for -t
- { "tail", required_argument, nullptr, 't' },
- { uid_str, required_argument, nullptr, 0 },
- // support, but ignore and do not document, the optional argument
- { wrap_str, optional_argument, nullptr, 0 },
- { nullptr, 0, nullptr, 0 }
- };
- // clang-format on
-
- int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
- &option_index);
- if (c == -1) break;
-
- switch (c) {
- case 0:
- // only long options
- if (long_options[option_index].name == pid_str) {
- if (pid != 0) {
- error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
- }
-
- if (!ParseUint(optarg, &pid) || pid < 1) {
- error(EXIT_FAILURE, 0, "%s %s out of range.",
- long_options[option_index].name, optarg);
- }
- break;
- }
- if (long_options[option_index].name == wrap_str) {
- mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
- // ToDo: implement API that supports setting a wrap timeout
- size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
- if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
- error(EXIT_FAILURE, 0, "%s %s out of range.",
- long_options[option_index].name, optarg);
- }
- if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
- fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
- long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
- timeout);
- }
- break;
- }
- if (long_options[option_index].name == print_str) {
- print_it_anyways_ = true;
- break;
- }
- if (long_options[option_index].name == debug_str) {
- debug_ = true;
- break;
- }
- if (long_options[option_index].name == id_str) {
- setId = (optarg && optarg[0]) ? optarg : nullptr;
- }
- if (long_options[option_index].name == uid_str) {
- auto uid_strings = Split(optarg, delimiters);
- for (const auto& uid_string : uid_strings) {
- uid_t uid;
- if (!ParseUint(uid_string, &uid)) {
- error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
- }
- uids.emplace(uid);
- }
- break;
- }
- break;
-
- case 's':
- // default to all silent
- android_log_addFilterRule(logformat_.get(), "*:s");
- break;
-
- case 'c':
- clearLog = true;
- break;
-
- case 'L':
- mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
- break;
-
- case 'd':
- mode |= ANDROID_LOG_NONBLOCK;
- break;
-
- case 't':
- got_t = true;
- mode |= ANDROID_LOG_NONBLOCK;
- FALLTHROUGH_INTENDED;
- case 'T':
- if (strspn(optarg, "0123456789") != strlen(optarg)) {
- char* cp = parseTime(tail_time, optarg);
- if (!cp) {
- error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
- }
- if (*cp) {
- char ch = *cp;
- *cp = '\0';
- fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
- cp + 1);
- *cp = ch;
- }
- } else {
- if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
- fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
- tail_lines = 1;
- }
- }
- break;
-
- case 'D':
- printDividers = true;
- break;
-
- case 'e':
- regex_.reset(new std::regex(optarg));
- break;
-
- case 'm': {
- if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
- error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
- optarg);
- }
- } break;
-
- case 'g':
- if (!optarg) {
- getLogSize = true;
- break;
- }
- FALLTHROUGH_INTENDED;
-
- case 'G': {
- if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
- error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
- }
- } break;
-
- case 'p':
- if (!optarg) {
- getPruneList = true;
- break;
- }
- FALLTHROUGH_INTENDED;
-
- case 'P':
- setPruneList = optarg;
- break;
-
- case 'b':
- for (const auto& buffer : Split(optarg, delimiters)) {
- if (buffer == "default") {
- id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
- } else if (buffer == "all") {
- id_mask = -1;
- } else {
- log_id_t log_id = android_name_to_log_id(buffer.c_str());
- if (log_id >= LOG_ID_MAX) {
- error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
- buffer.c_str());
- }
- if (log_id == LOG_ID_SECURITY) {
- security_buffer_selected = true;
- }
- id_mask |= (1 << log_id);
- }
- }
- break;
-
- case 'B':
- print_binary_ = 1;
- break;
-
- case 'f':
- if ((tail_time == log_time::EPOCH) && !tail_lines) {
- tail_time = lastLogTime(optarg);
- }
- // redirect output to a file
- output_file_name_ = optarg;
- break;
-
- case 'r':
- if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
- }
- break;
-
- case 'n':
- if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
- }
- break;
-
- case 'v':
- if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
- show_format_help();
- return EXIT_SUCCESS;
- }
- for (const auto& arg : Split(optarg, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
- }
- if (err) hasSetLogFormat = true;
- }
- break;
-
- case 'Q':
-#define LOGCAT_FILTER "androidboot.logcat="
-#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
-#define CONSOLE_OPTION "androidboot.console="
-#define QEMU_PROPERTY "ro.kernel.qemu"
-#define QEMU_CMDLINE "qemu.cmdline"
- // This is a *hidden* option used to start a version of logcat
- // in an emulated device only. It basically looks for
- // androidboot.logcat= on the kernel command line. If
- // something is found, it extracts a log filter and uses it to
- // run the program. The logcat output will go to consolepipe if
- // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
- // it goes to androidboot.console (e.g. tty)
- {
- // if not in emulator, exit quietly
- if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
- return EXIT_SUCCESS;
- }
-
- std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
- if (cmdline.empty()) {
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
- }
-
- const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
- // if nothing found or invalid filters, exit quietly
- if (!logcatFilter) {
- return EXIT_SUCCESS;
- }
-
- const char* p = logcatFilter + strlen(LOGCAT_FILTER);
- const char* q = strpbrk(p, " \t\n\r");
- if (!q) q = p + strlen(p);
- forceFilters = std::string(p, q);
-
- // redirect our output to the emulator console pipe or console
- const char* consolePipe =
- strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
- const char* console =
- strstr(cmdline.c_str(), CONSOLE_OPTION);
-
- if (consolePipe) {
- p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
- } else if (console) {
- p = console + strlen(CONSOLE_OPTION);
- } else {
- return EXIT_FAILURE;
- }
-
- q = strpbrk(p, " \t\n\r");
- int len = q ? q - p : strlen(p);
- std::string devname = "/dev/" + std::string(p, len);
- std::string pipePurpose("pipe:logcat");
- if (consolePipe) {
- // example: "qemu_pipe,pipe:logcat"
- // upon opening of /dev/qemu_pipe, the "pipe:logcat"
- // string with trailing '\0' should be written to the fd
- size_t pos = devname.find(',');
- if (pos != std::string::npos) {
- pipePurpose = devname.substr(pos + 1);
- devname = devname.substr(0, pos);
- }
- }
-
- fprintf(stderr, "logcat using %s\n", devname.c_str());
-
- int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
- if (fd < 0) {
- break;
- }
-
- if (consolePipe) {
- // need the trailing '\0'
- if (!WriteFully(fd, pipePurpose.c_str(), pipePurpose.size() + 1)) {
- close(fd);
- return EXIT_FAILURE;
- }
- }
- // close output and error channels, replace with console
- dup2(fd, output_fd_.get());
- dup2(fd, STDERR_FILENO);
- close(fd);
- }
- break;
-
- case 'S':
- printStatistics = true;
- break;
-
- case ':':
- error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
- break;
-
- case 'h':
- show_help();
- show_format_help();
- return EXIT_SUCCESS;
-
- case '?':
- error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind - 1]);
- break;
-
- default:
- error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
- }
- }
-
- if (max_count_ && got_t) {
- error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
- }
- if (print_it_anyways_ && (!regex_ || !max_count_)) {
- // One day it would be nice if --print -v color and --regex <expr>
- // could play with each other and show regex highlighted content.
- fprintf(stderr,
- "WARNING: "
- "--print ignored, to be used in combination with\n"
- " "
- "--regex <expr> and --max-count <N>\n");
- print_it_anyways_ = false;
- }
-
- // If no buffers are specified, default to using these buffers.
- if (id_mask == 0) {
- id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
- (1 << LOG_ID_KERNEL);
- }
-
- if (log_rotate_size_kb_ != 0 && !output_file_name_) {
- error(EXIT_FAILURE, 0, "-r requires -f as well.");
- }
-
- if (setId != 0) {
- if (!output_file_name_) {
- error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
- }
-
- std::string file_name = StringPrintf("%s.id", output_file_name_);
- std::string file;
- bool file_ok = android::base::ReadFileToString(file_name, &file);
- android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
- getuid(), getgid());
- if (!file_ok || !file.compare(setId)) setId = nullptr;
- }
-
- if (!hasSetLogFormat) {
- const char* logFormat = getenv("ANDROID_PRINTF_LOG");
-
- if (!!logFormat) {
- for (const auto& arg : Split(logFormat, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- // environment should not cause crash of logcat
- if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
- }
- if (err > 0) hasSetLogFormat = true;
- }
- }
- if (!hasSetLogFormat) {
- SetLogFormat("threadtime");
- }
- }
-
- if (forceFilters.size()) {
- int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
- }
- } else if (argc == optind) {
- // Add from environment variable
- const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
-
- if (!!env_tags_orig) {
- int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
-
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
- }
- }
- } else {
- // Add from commandline
- for (int i = optind ; i < argc ; i++) {
- int err = android_log_addFilterString(logformat_.get(), argv[i]);
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
- }
- }
- }
-
- if (mode & ANDROID_LOG_PSTORE) {
- if (output_file_name_) {
- error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
- }
- if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
- error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
- }
- if (clearLog) {
- unlink("/sys/fs/pstore/pmsg-ramoops-0");
- return EXIT_SUCCESS;
- }
- }
-
- if (output_file_name_) {
- if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
- error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
- }
-
- if (clearLog || setId) {
- int max_rotation_count_digits =
- max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
-
- for (int i = max_rotated_logs_; i >= 0; --i) {
- std::string file;
-
- if (!i) {
- file = output_file_name_;
- } else {
- file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
- }
-
- int err = unlink(file.c_str());
-
- if (err < 0 && errno != ENOENT) {
- fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
- strerror(errno));
- }
- }
- }
-
- if (clearLog) {
- return EXIT_SUCCESS;
- }
- }
-
- std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
- nullptr, &android_logger_list_free};
- if (tail_time != log_time::EPOCH) {
- logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
- } else {
- logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
- }
- // We have three orthogonal actions below to clear, set log size and
- // get log size. All sharing the same iteration loop.
- std::vector<std::string> open_device_failures;
- std::vector<std::string> clear_failures;
- std::vector<std::string> set_size_failures;
- std::vector<std::string> get_size_failures;
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- if (!(id_mask & (1 << i))) continue;
- const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
-
- auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
- if (logger == nullptr) {
- ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
- continue;
- }
-
- if (clearLog) {
- if (android_logger_clear(logger)) {
- ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
- }
- }
-
- if (setLogSize) {
- if (android_logger_set_log_size(logger, setLogSize)) {
- ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
- }
- }
-
- if (getLogSize) {
- long size = android_logger_get_log_size(logger);
- long readable = android_logger_get_log_readable_size(logger);
- long consumed = android_logger_get_log_consumed_size(logger);
-
- if (size < 0 || readable < 0) {
- ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
- } else {
- auto size_format = format_of_size(size);
- auto readable_format = format_of_size(readable);
- auto consumed_format = format_of_size(consumed);
- std::string str = android::base::StringPrintf(
- "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
- " max entry is %d B, max payload is %d B\n",
- buffer_name, size_format.first, size_format.second, consumed_format.first,
- consumed_format.second, readable_format.first, readable_format.second,
- (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
- if (!WriteFully(output_fd_, str.data(), str.length())) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- }
- }
- }
-
- // report any errors in the above loop and exit
- if (!open_device_failures.empty()) {
- error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
- open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
- }
- if (!clear_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
- clear_failures.size() > 1 ? "s" : "");
- }
- if (!set_size_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
- Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
- }
- if (!get_size_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
- Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
- }
-
- if (setPruneList) {
- size_t len = strlen(setPruneList);
- if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
- error(EXIT_FAILURE, 0, "Failed to set the prune list.");
- }
- return EXIT_SUCCESS;
- }
-
- if (printStatistics || getPruneList) {
- std::string buf(8192, '\0');
- size_t ret_length = 0;
- int retry = 32;
-
- for (; retry >= 0; --retry) {
- if (getPruneList) {
- android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
- } else {
- android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
- }
-
- ret_length = atol(buf.c_str());
- if (ret_length < 3) {
- error(EXIT_FAILURE, 0, "Failed to read data.");
- }
-
- if (ret_length < buf.size()) {
- break;
- }
-
- buf.resize(ret_length + 1);
- }
-
- if (retry < 0) {
- error(EXIT_FAILURE, 0, "Failed to read data.");
- }
-
- buf.resize(ret_length);
- if (buf.back() == '\f') {
- buf.pop_back();
- }
-
- // Remove the byte count prefix
- const char* cp = buf.c_str();
- while (isdigit(*cp)) ++cp;
- if (*cp == '\n') ++cp;
-
- size_t len = strlen(cp);
- if (!WriteFully(output_fd_, cp, len)) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- return EXIT_SUCCESS;
- }
-
- if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
-
- SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
-
- while (!max_count_ || print_count_ < max_count_) {
- struct log_msg log_msg;
- int ret = android_logger_list_read(logger_list.get(), &log_msg);
- if (!ret) {
- error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
-
-This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
-messages as quickly as they were being produced.
-
-If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
- }
-
- if (ret < 0) {
- if (ret == -EAGAIN) break;
-
- if (ret == -EIO) {
- error(EXIT_FAILURE, 0, "Unexpected EOF!");
- }
- if (ret == -EINVAL) {
- error(EXIT_FAILURE, 0, "Unexpected length.");
- }
- error(EXIT_FAILURE, errno, "Logcat read failure");
- }
-
- if (log_msg.id() > LOG_ID_MAX) {
- error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
- LOG_ID_MAX);
- }
-
- if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
- continue;
- }
-
- PrintDividers(log_msg.id(), printDividers);
-
- if (print_binary_) {
- if (!WriteFully(output_fd_, &log_msg, log_msg.len())) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- } else {
- ProcessBuffer(&log_msg);
- }
- }
- return EXIT_SUCCESS;
-}
-
-int main(int argc, char** argv) {
- Logcat logcat;
- return logcat.Run(argc, argv);
-}
diff --git a/logcat/logcatd b/logcat/logcatd
deleted file mode 100755
index 5a1415d..0000000
--- a/logcat/logcatd
+++ /dev/null
@@ -1,29 +0,0 @@
-#! /system/bin/sh
-
-# This is primarily meant to be used by logpersist. This script is run as an init service, which
-# first reads the 'last' logcat to persistent storage with `-L` then run logcat again without
-# `-L` to read the current logcat buffers to persistent storage.
-
-# init sets the umask to 077 for forked processes. logpersist needs to create files that are group
-# readable. So relax the umask to only disallow group wx and world rwx.
-umask 037
-
-has_last="false"
-for arg in "$@"; do
- if [ "$arg" == "-L" -o "$arg" == "--last" ]; then
- has_last="true"
- fi
-done
-
-if [ "$has_last" == "true" ]; then
- logcat "$@"
-fi
-
-args_without_last=()
-for arg in "$@"; do
- if [ "$arg" != "-L" -a "$arg" != "--last" ]; then
- ARGS+=("$arg")
- fi
-done
-
-exec logcat "${ARGS[@]}"
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
deleted file mode 100644
index 64d5500..0000000
--- a/logcat/logcatd.rc
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# init scriptures for logcatd persistent logging.
-#
-# Make sure any property changes are only performed with /data mounted, after
-# post-fs-data state because otherwise behavior is undefined. The exceptions
-# are device adjustments for logcatd service properties (persist.* overrides
-# notwithstanding) for logd.logpersistd.size logd.logpersistd.rotate_kbytes and
-# logd.logpersistd.buffer.
-
-# persist to non-persistent trampolines to permit device properties can be
-# overridden when /data mounts, or during runtime.
-on property:persist.logd.logpersistd.count=*
- # expect /init to report failure if property empty (default)
- setprop persist.logd.logpersistd.size ${persist.logd.logpersistd.count}
-
-on property:persist.logd.logpersistd.size=*
- setprop logd.logpersistd.size ${persist.logd.logpersistd.size}
-
-on property:persist.logd.logpersistd.rotate_kbytes=*
- setprop logd.logpersistd.rotate_kbytes ${persist.logd.logpersistd.rotate_kbytes}
-
-on property:persist.logd.logpersistd.buffer=*
- setprop logd.logpersistd.buffer ${persist.logd.logpersistd.buffer}
-
-on property:persist.logd.logpersistd=logcatd
- setprop logd.logpersistd logcatd
-
-# enable, prep and start logcatd service
-on load_persist_props_action
- setprop logd.logpersistd.enable true
-
-on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd
- # log group should be able to read persisted logs
- mkdir /data/misc/logd 0750 logd log
- start logcatd
-
-# stop logcatd service and clear data
-on property:logd.logpersistd.enable=true && property:logd.logpersistd=clear
- setprop persist.logd.logpersistd ""
- stop logcatd
- # logd for clear of only our files in /data/misc/logd
- exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${logd.logpersistd.size:-256}
- setprop logd.logpersistd ""
-
-# stop logcatd service
-on property:logd.logpersistd=stop
- setprop persist.logd.logpersistd ""
- stop logcatd
- setprop logd.logpersistd ""
-
-on property:logd.logpersistd.enable=false
- stop logcatd
-
-# logcatd service
-service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r ${logd.logpersistd.rotate_kbytes:-2048} -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
- class late_start
- disabled
- # logd for write to /data/misc/logd, log group for read from log daemon
- user logd
- group log
- writepid /dev/cpuset/system-background/tasks
- oom_score_adjust -600
diff --git a/logcat/logpersist b/logcat/logpersist
deleted file mode 100755
index 05b46f0..0000000
--- a/logcat/logpersist
+++ /dev/null
@@ -1,178 +0,0 @@
-#! /system/bin/sh
-# logpersist cat, start and stop handlers
-progname="${0##*/}"
-case `getprop ro.debuggable` in
-1) ;;
-*) echo "${progname} - Permission denied"
- exit 1
- ;;
-esac
-
-property=persist.logd.logpersistd
-
-case `getprop ${property#persist.}.enable` in
-true) ;;
-*) echo "${progname} - Disabled"
- exit 1
- ;;
-esac
-
-log_uid=logd
-log_tag_property=persist.log.tag
-data=/data/misc/logd/logcat
-service=logcatd
-size_default=256
-buffer_default=all
-args="${@}"
-
-size=${size_default}
-buffer=${buffer_default}
-clear=false
-while [ ${#} -gt 0 ]; do
- case ${1} in
- -c|--clear) clear=true ;;
- --size=*) size="${1#--size=}" ;;
- --rotate-count=*) size="${1#--rotate-count=}" ;;
- -n|--size|--rotate-count) size="${2}" ; shift ;;
- --buffer=*) buffer="${1#--buffer=}" ;;
- -b|--buffer) buffer="${2}" ; shift ;;
- -h|--help|*)
- LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
- echo "${progname%.*}.cat - dump current ${service} logs"
- echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
- echo "${LEAD_SPACE_} - start ${service} service"
- echo "${progname%.*}.stop [--clear] - stop ${service} service"
- case ${1} in
- -h|--help) exit 0 ;;
- *) echo ERROR: bad argument ${@} >&2 ; exit 1 ;;
- esac
- ;;
- esac
- shift
-done
-
-if [ -z "${size}" -o "${size_default}" = "${size}" ]; then
- unset size
-fi
-if [ -n "${size}" ] &&
- ! ( [ 0 -lt "${size}" ] && [ 2048 -ge "${size}" ] ) >/dev/null 2>&1; then
- echo ERROR: Invalid --size ${size} >&2
- exit 1
-fi
-if [ -z "${buffer}" -o "${buffer_default}" = "${buffer}" ]; then
- unset buffer
-fi
-if [ -n "${buffer}" ] && ! logcat -b ${buffer} -g >/dev/null 2>&1; then
- echo ERROR: Invalid --buffer ${buffer} >&2
- exit 1
-fi
-
-log_tag="`getprop ${log_tag_property}`"
-logd_logpersistd="`getprop ${property}`"
-
-case ${progname} in
-*.cat)
- if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
- echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
- fi
- su ${log_uid} ls "${data%/*}" |
- tr -d '\r' |
- sort -ru |
- sed "s#^#${data%/*}/#" |
- grep "${data}[.]*[0-9]*\$" |
- su ${log_uid} xargs cat
- ;;
-*.start)
- current_buffer="`getprop ${property#persist.}.buffer`"
- current_size="`getprop ${property#persist.}.size`"
- if [ "${service}" = "`getprop ${property#persist.}`" ]; then
- if [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
- echo "ERROR: Changing existing collection parameters from" >&2
- if [ "${buffer}" != "${current_buffer}" ]; then
- a=${current_buffer}
- b=${buffer}
- if [ -z "${a}" ]; then a="${default_buffer}"; fi
- if [ -z "${b}" ]; then b="${default_buffer}"; fi
- echo " --buffer ${a} to ${b}" >&2
- fi
- if [ "${size}" != "${current_size}" ]; then
- a=${current_size}
- b=${size}
- if [ -z "${a}" ]; then a="${default_size}"; fi
- if [ -z "${b}" ]; then b="${default_size}"; fi
- echo " --size ${a} to ${b}" >&2
- fi
- echo " Are you sure you want to do this?" >&2
- echo " Suggest add --clear to erase data and restart with new settings." >&2
- echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
- exit 1
- fi
- elif [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- fi
- if [ -n "${buffer}${current_buffer}" ]; then
- setprop ${property}.buffer "${buffer}"
- if [ -z "${buffer}" ]; then
- # deal with trampoline for empty properties
- setprop ${property#persist.}.buffer ""
- fi
- fi
- if [ -n "${size}${current_size}" ]; then
- setprop ${property}.size "${size}"
- if [ -z "${size}" ]; then
- # deal with trampoline for empty properties
- setprop ${property#persist.}.size ""
- fi
- fi
- while [ "clear" = "`getprop ${property#persist.}`" ]; do
- continue
- done
- # Tell Settings that we are back on again if we turned logging off
- tag="${log_tag#Settings}"
- if [ X"${log_tag}" != X"${tag}" ]; then
- echo "WARNING: enabling logd service" >&2
- setprop ${log_tag_property} "${tag#,}"
- fi
- # ${service}.rc does the heavy lifting with the following trigger
- setprop ${property} ${service}
- # 20ms done, to permit process feedback check
- sleep 1
- getprop ${property#persist.}
- # also generate an error return code if not found running
- pgrep -u ${log_uid} ${service%d}
- ;;
-*.stop)
- if [ -n "${size}${buffer}" ]; then
- echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
- fi
- if [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- else
- setprop ${property#persist.} "stop"
- fi
- if [ -n "`getprop ${property#persist.}.buffer`" ]; then
- setprop ${property}.buffer ""
- # deal with trampoline for empty properties
- setprop ${property#persist.}.buffer ""
- fi
- if [ -n "`getprop ${property#persist.}.size`" ]; then
- setprop ${property}.size ""
- # deal with trampoline for empty properties
- setprop ${property#persist.}.size ""
- fi
- while [ "clear" = "`getprop ${property#persist.}`" ]; do
- continue
- done
- ;;
-*)
- echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
- exit 1
-esac
-
-if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
- [ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
- echo "WARNING: killing Settings application to pull in new values" >&2
- am force-stop com.android.settings
-fi
diff --git a/logcat/tests/Android.bp b/logcat/tests/Android.bp
deleted file mode 100644
index ab84150..0000000
--- a/logcat/tests/Android.bp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (C) 2013-2014 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.
-//
-
-cc_defaults {
- name: "logcat-tests-defaults",
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
-}
-
-// -----------------------------------------------------------------------------
-// Benchmarks
-// ----------------------------------------------------------------------------
-
-// Build benchmarks for the device. Run with:
-// adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
-cc_benchmark {
- name: "logcat-benchmarks",
- defaults: ["logcat-tests-defaults"],
- srcs: ["logcat_benchmark.cpp"],
- shared_libs: ["libbase"],
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-// Build tests for the device (with .so). Run with:
-// adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
-cc_test {
- name: "logcat-unit-tests",
- defaults: ["logcat-tests-defaults"],
- shared_libs: ["libbase"],
- static_libs: ["liblog"],
- srcs: [
- "logcat_test.cpp",
- "logcatd_test.cpp",
- ],
-}
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
deleted file mode 100644
index 8d88628..0000000
--- a/logcat/tests/logcat_benchmark.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <benchmark/benchmark.h>
-
-static const char begin[] = "--------- beginning of ";
-
-static void BM_logcat_sorted_order(benchmark::State& state) {
- FILE* fp;
-
- if (!state.KeepRunning()) return;
-
- fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r");
- if (!fp) return;
-
- class timestamp {
- private:
- int month;
- int day;
- int hour;
- int minute;
- int second;
- int millisecond;
- bool ok;
-
- public:
- void init(const char* buffer) {
- ok = false;
- if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
- &minute, &second, &millisecond) == 6;
- }
- }
-
- explicit timestamp(const char* buffer) {
- init(buffer);
- }
-
- bool operator<(timestamp& T) {
- return !ok || !T.ok || (month < T.month) ||
- ((month == T.month) &&
- ((day < T.day) ||
- ((day == T.day) &&
- ((hour < T.hour) ||
- ((hour == T.hour) &&
- ((minute < T.minute) ||
- ((minute == T.minute) &&
- ((second < T.second) ||
- ((second == T.second) &&
- (millisecond < T.millisecond))))))))));
- }
-
- bool valid(void) {
- return ok;
- }
- } last(NULL);
-
- char* last_buffer = NULL;
- char buffer[5120];
-
- int count = 0;
- int next_lt_last = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
- if (!last.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- timestamp next(buffer);
- if (next < last) {
- if (last_buffer) {
- fprintf(stderr, "<%s", last_buffer);
- }
- fprintf(stderr, ">%s", buffer);
- ++next_lt_last;
- }
- if (next.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- ++count;
- }
- free(last_buffer);
-
- pclose(fp);
-
- static const int max_ok = 2;
-
- // Allow few fails, happens with readers active
- fprintf(stderr, "%s: %d/%d out of order entries\n",
- (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
- : "INFO",
- next_lt_last, count);
-
- if (next_lt_last > max_ok) {
- fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
- next_lt_last);
- }
-
- // sample statistically too small
- if (count < 100) {
- fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
- }
-
- state.KeepRunning();
-}
-BENCHMARK(BM_logcat_sorted_order);
-
-BENCHMARK_MAIN();
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
deleted file mode 100644
index 735fd94..0000000
--- a/logcat/tests/logcat_test.cpp
+++ /dev/null
@@ -1,1772 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <ctype.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <memory>
-#include <regex>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-#include <log/event_tag_map.h>
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#ifndef logcat_executable
-#define USING_LOGCAT_EXECUTABLE_DEFAULT
-#define logcat_executable "logcat"
-#endif
-
-#define BIG_BUFFER (5 * 1024)
-
-// rest(), let the logs settle.
-//
-// logd is in a background cgroup and under extreme load can take up to
-// 3 seconds to land a log entry. Under moderate load we can do with 200ms.
-static void rest() {
- static const useconds_t restPeriod = 200000;
-
- usleep(restPeriod);
-}
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are only using this in the emergency of
-// a signal to stuff a terminating code into the logs, we will spin rather
-// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-static const char begin[] = "--------- beginning of ";
-
-TEST(logcat, buckets) {
- FILE* fp;
-
-#undef LOG_TAG
-#define LOG_TAG "inject.buckets"
- // inject messages into radio, system, main and events buffers to
- // ensure that we see all the begin[] bucket messages.
- RLOGE(logcat_executable);
- SLOGE(logcat_executable);
- ALOGE(logcat_executable);
- __android_log_bswrite(0, logcat_executable ".inject.buckets");
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(logcat_executable
- " -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int ids = 0;
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- while (char* cp = strrchr(buffer, '\n')) {
- *cp = '\0';
- }
- log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1);
- ids |= 1 << id;
- ++count;
- }
- }
-
- pclose(fp);
-
- EXPECT_EQ(ids, 15);
-
- EXPECT_EQ(count, 4);
-}
-
-TEST(logcat, event_tag_filter) {
- FILE* fp;
-
-#undef LOG_TAG
-#define LOG_TAG "inject.filter"
- // inject messages into radio, system and main buffers
- // with our unique log tag to test logcat filter.
- RLOGE(logcat_executable);
- SLOGE(logcat_executable);
- ALOGE(logcat_executable);
- rest();
-
- std::string command = android::base::StringPrintf(
- logcat_executable
- " -b radio -b system -b main --pid=%d -d -s inject.filter 2>/dev/null",
- getpid());
- ASSERT_TRUE(NULL != (fp = popen(command.c_str(), "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (strncmp(begin, buffer, sizeof(begin) - 1)) ++count;
- }
-
- pclose(fp);
-
- // logcat, liblogcat and logcatd test instances result in the progression
- // of 3, 6 and 9 for our counts as each round is performed.
- EXPECT_GE(count, 3);
- EXPECT_LE(count, 9);
- EXPECT_EQ(count % 3, 0);
-}
-
-// If there is not enough background noise in the logs, then spam the logs to
-// permit tail checking so that the tests can progress.
-static size_t inject(ssize_t count) {
- if (count <= 0) return 0;
-
- static const size_t retry = 4;
- size_t errors = retry;
- size_t num = 0;
- for (;;) {
- log_time ts(CLOCK_MONOTONIC);
- if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) {
- if (++num >= (size_t)count) {
- // let data settle end-to-end
- sleep(3);
- return num;
- }
- errors = retry;
- usleep(100); // ~32 per timer tick, we are a spammer regardless
- } else if (--errors <= 0) {
- return num;
- }
- }
- // NOTREACH
- return num;
-}
-
-TEST(logcat, year) {
- int count;
- int tries = 3; // in case run too soon after system start or buffer clear
-
- do {
- FILE* fp;
-
- char needle[32];
- time_t now;
- time(&now);
- struct tm* ptm;
-#if !defined(_WIN32)
- struct tm tmBuf;
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&&now);
-#endif
- strftime(needle, sizeof(needle), "[ %Y-", ptm);
-
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable " -v long -v year -b all -t 3 2>/dev/null", "r")));
-
- char buffer[BIG_BUFFER];
-
- count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, needle, strlen(needle))) {
- ++count;
- }
- }
- pclose(fp);
-
- } while ((count < 3) && --tries && inject(3 - count));
-
- ASSERT_EQ(3, count);
-}
-
-// Return a pointer to each null terminated -v long time field.
-static char* fgetLongTime(char* buffer, size_t buflen, FILE* fp) {
- while (fgets(buffer, buflen, fp)) {
- char* cp = buffer;
- if (*cp != '[') {
- continue;
- }
- while (*++cp == ' ') {
- ;
- }
- char* ep = cp;
- while (isdigit(*ep)) {
- ++ep;
- }
- if ((*ep != '-') && (*ep != '.')) {
- continue;
- }
- // Find PID field. Look for ': ' or ':[0-9][0-9][0-9]'
- while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) {
- if (isdigit(ep[0]) && isdigit(ep[1]) && isdigit(ep[2])) break;
- }
- if (!ep) {
- continue;
- }
- static const size_t pid_field_width = 7;
- ep -= pid_field_width;
- *ep = '\0';
- return cp;
- }
- return NULL;
-}
-
-TEST(logcat, tz) {
- int tries = 4; // in case run too soon after system start or buffer clear
- int count;
-
- do {
- FILE* fp;
-
- ASSERT_TRUE(NULL != (fp = popen(logcat_executable
- " -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
- ++count;
- } else {
- fprintf(stderr, "ts=\"%s\"\n", buffer + 2);
- }
- }
-
- pclose(fp);
-
- } while ((count < 3) && --tries && inject(3 - count));
-
- ASSERT_EQ(3, count);
-}
-
-TEST(logcat, ntz) {
- FILE* fp;
-
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable
- " -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
- ++count;
- }
- }
-
- pclose(fp);
-
- ASSERT_EQ(0, count);
-}
-
-static void do_tail(int num) {
- int tries = 4; // in case run too soon after system start or buffer clear
- int count;
-
- if (num > 10) ++tries;
- if (num > 100) ++tries;
- do {
- char buffer[BIG_BUFFER];
-
- snprintf(buffer, sizeof(buffer),
- "ANDROID_PRINTF_LOG=long logcat -b all -t %d 2>/dev/null", num);
-
- FILE* fp;
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- ++count;
- }
-
- pclose(fp);
-
- } while ((count < num) && --tries && inject(num - count));
-
- ASSERT_EQ(num, count);
-}
-
-TEST(logcat, tail_3) {
- do_tail(3);
-}
-
-TEST(logcat, tail_10) {
- do_tail(10);
-}
-
-TEST(logcat, tail_100) {
- do_tail(100);
-}
-
-TEST(logcat, tail_1000) {
- do_tail(1000);
-}
-
-static void do_tail_time(const char* cmd) {
- FILE* fp;
- int count;
- char buffer[BIG_BUFFER];
- char* last_timestamp = NULL;
- // Hard to predict 100% if first (overlap) or second line will match.
- // -v nsec will in a substantial majority be the second line.
- char* first_timestamp = NULL;
- char* second_timestamp = NULL;
- char* input;
-
- int tries = 4; // in case run too soon after system start or buffer clear
-
- do {
- snprintf(buffer, sizeof(buffer), "%s -t 10 2>&1", cmd);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
- count = 0;
-
- while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
- ++count;
- if (!first_timestamp) {
- first_timestamp = strdup(input);
- } else if (!second_timestamp) {
- second_timestamp = strdup(input);
- }
- free(last_timestamp);
- last_timestamp = strdup(input);
- }
- pclose(fp);
-
- } while ((count < 10) && --tries && inject(10 - count));
-
- EXPECT_EQ(count, 10); // We want _some_ history, too small, falses below
- EXPECT_TRUE(last_timestamp != NULL);
- EXPECT_TRUE(first_timestamp != NULL);
- EXPECT_TRUE(second_timestamp != NULL);
-
- snprintf(buffer, sizeof(buffer), "%s -t '%s' 2>&1", cmd, first_timestamp);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- int second_count = 0;
- int last_timestamp_count = -1;
-
- --count; // One less unless we match the first_timestamp
- bool found = false;
- while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
- ++second_count;
- // We want to highlight if we skip to the next entry.
- // WAI, if the time in logd is *exactly*
- // XX-XX XX:XX:XX.XXXXXX000 (usec) or XX-XX XX:XX:XX.XXX000000
- // this can happen, but it should not happen with nsec.
- // We can make this WAI behavior happen 1000 times less
- // frequently if the caller does not use the -v usec flag,
- // but always the second (always skip) if they use the
- // (undocumented) -v nsec flag.
- if (first_timestamp) {
- found = !strcmp(input, first_timestamp);
- if (found) {
- ++count;
- GTEST_LOG_(INFO)
- << "input = first(" << first_timestamp << ")\n";
- }
- free(first_timestamp);
- first_timestamp = NULL;
- }
- if (second_timestamp) {
- found = found || !strcmp(input, second_timestamp);
- if (!found) {
- GTEST_LOG_(INFO) << "input(" << input << ") != second("
- << second_timestamp << ")\n";
- }
- free(second_timestamp);
- second_timestamp = NULL;
- }
- if (!strcmp(input, last_timestamp)) {
- last_timestamp_count = second_count;
- }
- }
- pclose(fp);
-
- EXPECT_TRUE(found);
- if (!found) {
- if (first_timestamp) {
- GTEST_LOG_(INFO) << "first = " << first_timestamp << "\n";
- }
- if (second_timestamp) {
- GTEST_LOG_(INFO) << "second = " << second_timestamp << "\n";
- }
- if (last_timestamp) {
- GTEST_LOG_(INFO) << "last = " << last_timestamp << "\n";
- }
- }
- free(last_timestamp);
- last_timestamp = NULL;
- free(first_timestamp);
- free(second_timestamp);
-
- EXPECT_TRUE(first_timestamp == NULL);
- EXPECT_TRUE(second_timestamp == NULL);
- EXPECT_LE(count, second_count);
- EXPECT_LE(count, last_timestamp_count);
-}
-
-TEST(logcat, tail_time) {
- do_tail_time(logcat_executable " -v long -v nsec -b all");
-}
-
-TEST(logcat, tail_time_epoch) {
- do_tail_time(logcat_executable " -v long -v nsec -v epoch -b all");
-}
-
-TEST(logcat, End_to_End) {
- pid_t pid = getpid();
-
- log_time ts(CLOCK_MONOTONIC);
-
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- FILE* fp;
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable " -v brief -b events -t 100 2>/dev/null", "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- int p;
- unsigned long long t;
-
- if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) ||
- (p != pid)) {
- continue;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&t);
- if (ts == *tx) {
- ++count;
- }
- }
-
- pclose(fp);
-
- ASSERT_EQ(1, count);
-}
-
-TEST(logcat, End_to_End_multitude) {
- pid_t pid = getpid();
-
- log_time ts(CLOCK_MONOTONIC);
-
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- FILE* fp[256]; // does this count as a multitude!
- memset(fp, 0, sizeof(fp));
- size_t num = 0;
- do {
- EXPECT_TRUE(NULL != (fp[num] = popen(logcat_executable " -v brief -b events -t 100", "r")));
- if (!fp[num]) {
- fprintf(stderr,
- "WARNING: limiting to %zu simultaneous logcat operations\n",
- num);
- break;
- }
- } while (++num < sizeof(fp) / sizeof(fp[0]));
-
- char buffer[BIG_BUFFER];
-
- size_t count = 0;
-
- for (size_t idx = 0; idx < sizeof(fp) / sizeof(fp[0]); ++idx) {
- if (!fp[idx]) break;
- while (fgets(buffer, sizeof(buffer), fp[idx])) {
- int p;
- unsigned long long t;
-
- if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) ||
- (p != pid)) {
- continue;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&t);
- if (ts == *tx) {
- ++count;
- }
- }
-
- pclose(fp[idx]);
- }
-
- ASSERT_EQ(num, count);
-}
-
-static int get_groups(const char* cmd) {
- FILE* fp;
-
- EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
-
- if (fp == NULL) {
- return 0;
- }
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- int size, consumed, readable, max, payload;
- char size_mult[4], consumed_mult[4], readable_mult[4];
- long full_size, full_consumed;
-
- size = consumed = max = payload = 0;
- // NB: crash log can be very small, not hit a Kb of consumed space
- // doubly lucky we are not including it.
- EXPECT_EQ(8, sscanf(buffer,
- "%*s ring buffer is %d %3s (%d %3s consumed, %d %3s readable),"
- " max entry is %d B, max payload is %d B",
- &size, size_mult, &consumed, consumed_mult, &readable, readable_mult,
- &max, &payload))
- << "Parse error on: " << buffer;
- full_size = size;
- switch (size_mult[0]) {
- case 'G':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- default:
- ADD_FAILURE() << "Parse error on multiplier: " << size_mult;
- }
- full_consumed = consumed;
- switch (consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- default:
- ADD_FAILURE() << "Parse error on multiplier: " << consumed_mult;
- }
- EXPECT_GT((full_size * 9) / 4, full_consumed);
- EXPECT_GT(full_size, max);
- EXPECT_GT(max, payload);
-
- if ((((full_size * 9) / 4) >= full_consumed) && (full_size > max) &&
- (max > payload)) {
- ++count;
- }
- }
-
- pclose(fp);
-
- return count;
-}
-
-TEST(logcat, get_size) {
- ASSERT_EQ(4, get_groups(logcat_executable
- " -v brief -b radio -b events -b system -b "
- "main -g 2>/dev/null"));
-}
-
-// duplicate test for get_size, but use comma-separated list of buffers
-TEST(logcat, multiple_buffer) {
- ASSERT_EQ(
- 4, get_groups(logcat_executable
- " -v brief -b radio,events,system,main -g 2>/dev/null"));
-}
-
-TEST(logcat, bad_buffer) {
- ASSERT_EQ(0,
- get_groups(
- logcat_executable
- " -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
-}
-
-#ifndef logcat
-static void caught_blocking(int signum) {
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking) {
- FILE* fp;
- unsigned long long v = 0xDEADBEEFA55F0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- v &= 0xFFFFFFFFFFFAFFFFULL;
-
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- ++signals;
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 2);
-
- EXPECT_EQ(signals, 1);
-}
-
-static void caught_blocking_tail(int signum) {
- unsigned long long v = 0xA55ADEADBEEF0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking_tail) {
- FILE* fp;
- unsigned long long v = 0xA55FDEADBEEF0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- v &= 0xFFFAFFFFFFFFFFFFULL;
-
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events -T 5 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking_tail);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- if (count >= 5) {
- ++signals;
- }
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking_tail(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 2);
-
- EXPECT_EQ(signals, 1);
-}
-#endif
-
-// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
-static testing::AssertionResult IsFalse(int ret, const char* command) {
- return ret ? (testing::AssertionSuccess()
- << "ret=" << ret << " command=\"" << command << "\"")
- : testing::AssertionFailure();
-}
-
-TEST(logcat, logrotate) {
- static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
- char buf[sizeof(form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
-
- static const char comm[] = logcat_executable
- " -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 7 -r 1";
- char command[sizeof(buf) + sizeof(comm)];
- snprintf(command, sizeof(command), comm, buf);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (!ret) {
- snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
-
- FILE* fp;
- EXPECT_TRUE(NULL != (fp = popen(command, "r")));
- if (fp) {
- char buffer[BIG_BUFFER];
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- static const char total[] = "total ";
- int num;
- char c;
-
- if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
- (num <= 40)) {
- ++count;
- } else if (strncmp(buffer, total, sizeof(total) - 1)) {
- fprintf(stderr, "WARNING: Parse error: %s", buffer);
- }
- }
- pclose(fp);
- if ((count != 7) && (count != 8)) {
- fprintf(stderr, "count=%d\n", count);
- }
- EXPECT_TRUE(count == 7 || count == 8);
- }
- }
- snprintf(command, sizeof(command), "rm -rf %s", buf);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_suffix) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char logcat_cmd[] = logcat_executable
- " -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 10 -r 1";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (!ret) {
- snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
-
- FILE* fp;
- EXPECT_TRUE(NULL != (fp = popen(command, "r")));
- char buffer[BIG_BUFFER];
- int log_file_count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- static const char rotated_log_filename_prefix[] = "log.txt.";
- static const size_t rotated_log_filename_prefix_len =
- strlen(rotated_log_filename_prefix);
- static const char log_filename[] = "log.txt";
-
- if (!strncmp(buffer, rotated_log_filename_prefix,
- rotated_log_filename_prefix_len)) {
- // Rotated file should have form log.txt.##
- char* rotated_log_filename_suffix =
- buffer + rotated_log_filename_prefix_len;
- char* endptr;
- const long int suffix_value =
- strtol(rotated_log_filename_suffix, &endptr, 10);
- EXPECT_EQ(rotated_log_filename_suffix + 2, endptr);
- EXPECT_LE(suffix_value, 10);
- EXPECT_GT(suffix_value, 0);
- ++log_file_count;
- continue;
- }
-
- if (!strncmp(buffer, log_filename, strlen(log_filename))) {
- ++log_file_count;
- continue;
- }
-
- fprintf(stderr, "ERROR: Unexpected file: %s", buffer);
- ADD_FAILURE();
- }
- pclose(fp);
- EXPECT_EQ(log_file_count, 11);
- }
- snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_continue) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char log_filename[] = "log.txt";
- static const char logcat_cmd[] =
- logcat_executable " -b all -v nsec -d -f %s/%s -n 256 -r 1024";
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)];
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- FILE* fp;
- snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename);
- EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
- if (!fp) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- char* line = NULL;
- char* last_line =
- NULL; // this line is allowed to stutter, one-line overlap
- char* second_last_line = NULL; // should never stutter
- char* first_line = NULL; // help diagnose failure?
- size_t len = 0;
- while (getline(&line, &len, fp) != -1) {
- if (!first_line) {
- first_line = line;
- line = NULL;
- continue;
- }
- free(second_last_line);
- second_last_line = last_line;
- last_line = line;
- line = NULL;
- }
- fclose(fp);
- free(line);
- if (second_last_line == NULL) {
- fprintf(stderr, "No second to last line, using last, test may fail\n");
- second_last_line = last_line;
- last_line = NULL;
- }
- free(last_line);
- EXPECT_TRUE(NULL != second_last_line);
- if (!second_last_line) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(first_line);
- return;
- }
- // re-run the command, it should only add a few lines more content if it
- // continues where it left off.
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(second_last_line);
- free(first_line);
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(second_last_line);
- free(first_line);
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name);
- EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
- if (!fp) {
- fprintf(stderr, "%s ?\n", command);
- continue;
- }
- line = NULL;
- size_t number = 0;
- while (getline(&line, &len, fp) != -1) {
- ++number;
- if (!strcmp(line, second_last_line)) {
- EXPECT_TRUE(++count <= 1);
- fprintf(stderr, "%s(%zu):\n", entry->d_name, number);
- }
- }
- fclose(fp);
- free(line);
- unlink(command);
- }
- if (count > 1) {
- char* brk = strpbrk(second_last_line, "\r\n");
- if (!brk) brk = second_last_line + strlen(second_last_line);
- fprintf(stderr, "\"%.*s\" occurred %u times\n",
- (int)(brk - second_last_line), second_last_line, count);
- if (first_line) {
- brk = strpbrk(first_line, "\r\n");
- if (!brk) brk = first_line + strlen(first_line);
- fprintf(stderr, "\"%.*s\" was first line, fault?\n",
- (int)(brk - first_line), first_line);
- }
- }
- free(second_last_line);
- free(first_line);
-
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_clear) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char log_filename[] = "log.txt";
- static const unsigned num_val = 32;
- static const char logcat_cmd[] =
- logcat_executable " -b all -d -f %s/%s -n %d -r 1";
- static const char clear_cmd[] = " -c";
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) +
- sizeof(log_filename) + sizeof(clear_cmd) + 32];
-
- // Run command with all data
- {
- snprintf(command, sizeof(command) - sizeof(clear_cmd), logcat_cmd,
- tmp_out_dir, log_filename, num_val);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- ++count;
- }
- EXPECT_EQ(count, num_val + 1);
- }
-
- {
- // Now with -c option tacked onto the end
- strcat(command, clear_cmd);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name);
- ++count;
- }
- EXPECT_EQ(count, 0U);
- }
-
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-static int logrotate_count_id(const char* logcat_cmd, const char* tmp_out_dir) {
- static const char log_filename[] = "log.txt";
- char command[strlen(tmp_out_dir) + strlen(logcat_cmd) +
- strlen(log_filename) + 32];
-
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-
- int ret = system(command);
- if (ret) {
- fprintf(stderr, "system(\"%s\")=%d", command, ret);
- return -1;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- if (!dir) {
- fprintf(stderr, "opendir(\"%s\") failed", tmp_out_dir);
- return -1;
- }
- struct dirent* entry;
- int count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- ++count;
- }
- return count;
-}
-
-TEST(logcat, logrotate_id) {
- static const char logcat_cmd[] =
- logcat_executable " -b all -d -f %s/%s -n 32 -r 1 --id=test";
- static const char logcat_short_cmd[] =
- logcat_executable " -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- static const char log_filename[] = "log.txt";
- char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- EXPECT_EQ(logrotate_count_id(logcat_cmd, tmp_out_dir), 34);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
-
- char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5];
- snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename);
- if (getuid() != 0) {
- chmod(id_file, 0);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
- }
- unlink(id_file);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
-
- FILE* fp = fopen(id_file, "w");
- if (fp) {
- fprintf(fp, "not_a_test");
- fclose(fp);
- }
- if (getuid() != 0) {
- chmod(id_file,
- 0); // API to preserve content even with signature change
- ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
- chmod(id_file, 0600);
- }
-
- int new_signature;
- EXPECT_GE(
- (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)), 2);
- EXPECT_LT(new_signature, 34);
-
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_nodir) {
- // expect logcat to error out on writing content and not exit(0) for nodir
- static const char command[] = logcat_executable
- " -b all -d"
- " -f /das/nein/gerfingerpoken/logcat/log.txt"
- " -n 256 -r 1024";
- EXPECT_FALSE(IsFalse(0 == system(command), command));
-}
-
-#ifndef logcat
-static void caught_blocking_clear(int signum) {
- unsigned long long v = 0xDEADBEEFA55C0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking_clear) {
- FILE* fp;
- unsigned long long v = 0xDEADBEEFA55C0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- // This test is racey; an event occurs between clear and dump.
- // We accept that we will get a false positive, but never a false negative.
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -b events -c 2>&1 ;"
- " logcat -b events -g 2>&1 ;"
- " logcat -v brief -b events 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
- int minus_g = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking_clear);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "clearLog: ", strlen("clearLog: "))) {
- fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
- count = signals = 1;
- break;
- }
- if (!strncmp(buffer, "failed to clear", strlen("failed to clear"))) {
- fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
- count = signals = 1;
- break;
- }
-
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- int size, consumed, readable, max, payload;
- char size_mult[4], consumed_mult[4], readable_mult[4];
- size = consumed = max = payload = 0;
- if (8 == sscanf(buffer,
- "events: ring buffer is %d %3s (%d %3s consumed, %d %3s readable),"
- " max entry is %d B, max payload is %d B",
- &size, size_mult, &consumed, consumed_mult, &readable, readable_mult, &max,
- &payload)) {
- long full_size = size, full_consumed = consumed;
-
- switch (size_mult[0]) {
- case 'G':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- }
- switch (consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- }
- EXPECT_GT(full_size, full_consumed);
- EXPECT_GT(full_size, max);
- EXPECT_GT(max, payload);
- EXPECT_GT(max, full_consumed);
-
- ++minus_g;
- continue;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- if (count > 1) {
- fprintf(stderr, "WARNING: Possible false positive\n");
- }
- ++signals;
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking_clear(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 1);
- EXPECT_EQ(minus_g, 1);
-
- EXPECT_EQ(signals, 1);
-}
-#endif
-
-static bool get_prune_rules(char** list) {
- FILE* fp = popen(logcat_executable " -p 2>/dev/null", "r");
- if (fp == NULL) {
- fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
- return false;
- }
-
- char buffer[BIG_BUFFER];
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- char* hold = *list;
- char* buf = buffer;
- while (isspace(*buf)) {
- ++buf;
- }
- char* end = buf + strlen(buf);
- while (isspace(*--end) && (end >= buf)) {
- *end = '\0';
- }
- if (end < buf) {
- continue;
- }
- if (hold) {
- asprintf(list, "%s %s", hold, buf);
- free(hold);
- } else {
- asprintf(list, "%s", buf);
- }
- }
- pclose(fp);
- return *list != NULL;
-}
-
-static bool set_prune_rules(const char* list) {
- char buffer[BIG_BUFFER];
- snprintf(buffer, sizeof(buffer), logcat_executable " -P '%s' 2>&1",
- list ? list : "");
- FILE* fp = popen(buffer, "r");
- if (fp == NULL) {
- fprintf(stderr, "ERROR: %s\n", buffer);
- return false;
- }
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- char* buf = buffer;
- while (isspace(*buf)) {
- ++buf;
- }
- char* end = buf + strlen(buf);
- while ((end > buf) && isspace(*--end)) {
- *end = '\0';
- }
- if (end <= buf) {
- continue;
- }
- fprintf(stderr, "%s\n", buf);
- pclose(fp);
- return false;
- }
- return pclose(fp) == 0;
-}
-
-TEST(logcat, prune_rules_adjust) {
- char* list = NULL;
- char* adjust = NULL;
-
- get_prune_rules(&list);
-
- static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
- ASSERT_EQ(true, set_prune_rules(adjustment));
- ASSERT_EQ(true, get_prune_rules(&adjust));
- EXPECT_STREQ(adjustment, adjust);
- free(adjust);
- adjust = NULL;
-
- static const char adjustment2[] = "300/20 300/21 2000 ~1000";
- ASSERT_EQ(true, set_prune_rules(adjustment2));
- ASSERT_EQ(true, get_prune_rules(&adjust));
- EXPECT_STREQ(adjustment2, adjust);
- free(adjust);
- adjust = NULL;
-
- ASSERT_EQ(true, set_prune_rules(list));
- get_prune_rules(&adjust);
- EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
- free(adjust);
- adjust = NULL;
-
- free(list);
- list = NULL;
-}
-
-TEST(logcat, regex) {
- FILE* fp;
- int count = 0;
-
- char buffer[BIG_BUFFER];
-#define logcat_regex_prefix logcat_executable "_test"
-
- snprintf(buffer, sizeof(buffer),
- logcat_executable " --pid %d -d -e " logcat_regex_prefix "_a+b",
- getpid());
-
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_ab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_b"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_aaaab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_aaaa"));
- // Let the logs settle
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
-
- EXPECT_TRUE(strstr(buffer, logcat_regex_prefix "_") != NULL);
-
- count++;
- }
-
- pclose(fp);
-
- ASSERT_EQ(2, count);
-}
-
-TEST(logcat, maxcount) {
- FILE* fp;
- int count = 0;
-
- char buffer[BIG_BUFFER];
-
- snprintf(buffer, sizeof(buffer),
- logcat_executable " --pid %d -d --max-count 3", getpid());
-
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
-
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
-
- count++;
- }
-
- pclose(fp);
-
- ASSERT_EQ(3, count);
-}
-
-static bool End_to_End(const char* tag, const char* fmt, ...)
-#if defined(__GNUC__)
- __attribute__((__format__(printf, 2, 3)))
-#endif
- ;
-
-static bool End_to_End(const char* tag, const char* fmt, ...) {
- FILE* fp = popen(logcat_executable " -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
- if (!fp) {
- fprintf(stderr, "End_to_End: popen failed");
- return false;
- }
-
- char buffer[BIG_BUFFER];
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- va_end(ap);
-
- char* str = NULL;
- asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
- std::string expect(str);
- free(str);
-
- int count = 0;
- pid_t pid = getpid();
- std::string lastMatch;
- int maxMatch = 1;
- while (fgets(buffer, sizeof(buffer), fp)) {
- char space;
- char newline;
- int p;
- int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
- if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
- ++count;
- } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
- lastMatch = buffer;
- maxMatch = ret;
- }
- }
-
- pclose(fp);
-
- if ((count == 0) && (lastMatch.length() > 0)) {
- // Help us pinpoint where things went wrong ...
- fprintf(stderr, "Closest match for\n %s\n is\n %s",
- expect.c_str(), lastMatch.c_str());
- } else if (count > 3) {
- fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str());
- }
-
- // Three different known tests, we can see pollution from the others
- return count && (count <= 3);
-}
-
-TEST(logcat, descriptive) {
- struct tag {
- uint32_t tagNo;
- const char* tagStr;
- };
- int ret;
-
- {
- static const struct tag hhgtg = { 42, "answer" };
- android_log_event_list ctx(hhgtg.tagNo);
- static const char theAnswer[] = "what is five by seven";
- ctx << theAnswer;
- // crafted to rest at least once after, and rest between retries.
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
- }
-
- {
- static const struct tag sync = { 2720, "sync" };
- static const char id[] = logcat_executable ".descriptive-sync";
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr,
- "[id=%s,event=42,source=-1,account=0]", id));
- }
-
- // Partial match to description
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
- }
-
- // Negative Test of End_to_End, ensure it is working
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- fprintf(stderr, "Expect a \"Closest match\" message\n");
- EXPECT_FALSE(End_to_End(
- sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
- }
- }
-
- {
- static const struct tag sync = { 2747, "contacts_aggregation" };
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint64_t)30 << (int32_t)2;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint64_t)31570 << (int32_t)911;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
- }
- }
-
- {
- static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)512;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)3072;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)2097152;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)2097153;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)1073741824;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
- }
- }
-
- {
- static const struct tag sync = { 27501, "notification_panel_hidden" };
- android_log_event_list ctx(sync.tagNo);
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, ""));
- }
-}
-
-static size_t commandOutputSize(const char* command) {
- FILE* fp = popen(command, "r");
- if (!fp) return 0;
-
- std::string ret;
- if (!android::base::ReadFdToString(fileno(fp), &ret)) return 0;
- if (pclose(fp) != 0) return 0;
-
- return ret.size();
-}
-
-TEST(logcat, help) {
- size_t logcatHelpTextSize = commandOutputSize(logcat_executable " -h 2>&1");
- EXPECT_GT(logcatHelpTextSize, 4096UL);
- size_t logcatLastHelpTextSize =
- commandOutputSize(logcat_executable " -L -h 2>&1");
-#ifdef USING_LOGCAT_EXECUTABLE_DEFAULT // logcat and liblogcat
- EXPECT_EQ(logcatHelpTextSize, logcatLastHelpTextSize);
-#else
- // logcatd -L -h prints the help twice, as designed.
- EXPECT_EQ(logcatHelpTextSize * 2, logcatLastHelpTextSize);
-#endif
-}
-
-TEST(logcat, invalid_buffer) {
- FILE* fp = popen("logcat -b foo 2>&1", "r");
- ASSERT_NE(nullptr, fp);
- std::string output;
- ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &output));
- pclose(fp);
-
- EXPECT_NE(std::string::npos, output.find("Unknown buffer 'foo'"));
-}
-
-static void SniffUid(const std::string& line, uid_t& uid) {
- auto uid_regex = std::regex{"\\S+\\s+\\S+\\s+(\\S+).*"};
-
- auto trimmed_line = android::base::Trim(line);
-
- std::smatch match_results;
- ASSERT_TRUE(std::regex_match(trimmed_line, match_results, uid_regex))
- << "Unable to find UID in line '" << trimmed_line << "'";
- auto uid_string = match_results[1];
- if (!android::base::ParseUint(uid_string, &uid)) {
- auto pwd = getpwnam(uid_string.str().c_str());
- ASSERT_NE(nullptr, pwd) << "uid '" << uid_string << "' in line '" << trimmed_line << "'";
- uid = pwd->pw_uid;
- }
-}
-
-static void UidsInLog(std::optional<std::vector<uid_t>> filter_uid, std::map<uid_t, size_t>& uids) {
- std::string command;
- if (filter_uid) {
- std::vector<std::string> uid_strings;
- for (const auto& uid : *filter_uid) {
- uid_strings.emplace_back(std::to_string(uid));
- }
- command = android::base::StringPrintf(logcat_executable
- " -v uid -b all -d 2>/dev/null --uid=%s",
- android::base::Join(uid_strings, ",").c_str());
- } else {
- command = logcat_executable " -v uid -b all -d 2>/dev/null";
- }
- auto fp = std::unique_ptr<FILE, decltype(&pclose)>(popen(command.c_str(), "r"), pclose);
- ASSERT_NE(nullptr, fp);
-
- char buffer[BIG_BUFFER];
- while (fgets(buffer, sizeof(buffer), fp.get())) {
- // Ignore dividers, e.g. '--------- beginning of radio'
- if (android::base::StartsWith(buffer, "---------")) {
- continue;
- }
- uid_t uid;
- SniffUid(buffer, uid);
- uids[uid]++;
- }
-}
-
-static std::vector<uid_t> TopTwoInMap(const std::map<uid_t, size_t>& uids) {
- std::pair<uid_t, size_t> top = {0, 0};
- std::pair<uid_t, size_t> second = {0, 0};
- for (const auto& [uid, count] : uids) {
- if (count > top.second) {
- top = second;
- top = {uid, count};
- } else if (count > second.second) {
- second = {uid, count};
- }
- }
- return {top.first, second.first};
-}
-
-TEST(logcat, uid_filter) {
- std::map<uid_t, size_t> uids;
- UidsInLog({}, uids);
-
- ASSERT_GT(uids.size(), 2U);
- auto top_uids = TopTwoInMap(uids);
-
- // Test filtering with --uid=<top uid>
- std::map<uid_t, size_t> uids_only_top;
- std::vector<uid_t> top_uid = {top_uids[0]};
- UidsInLog(top_uid, uids_only_top);
-
- EXPECT_EQ(1U, uids_only_top.size());
-
- // Test filtering with --uid=<top uid>,<2nd top uid>
- std::map<uid_t, size_t> uids_only_top2;
- std::vector<uid_t> top2_uids = {top_uids[0], top_uids[1]};
- UidsInLog(top2_uids, uids_only_top2);
-
- EXPECT_EQ(2U, uids_only_top2.size());
-}
diff --git a/logcat/tests/logcatd_test.cpp b/logcat/tests/logcatd_test.cpp
deleted file mode 100644
index bb7534e..0000000
--- a/logcat/tests/logcatd_test.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define logcat logcatd
-#define logcat_executable "logcatd"
-
-#include "logcat_test.cpp"
diff --git a/logd b/logd
new file mode 120000
index 0000000..bb2232f
--- /dev/null
+++ b/logd
@@ -0,0 +1 @@
+../logging/logd
\ No newline at end of file
diff --git a/logd/.clang-format b/logd/.clang-format
deleted file mode 120000
index 1af4f51..0000000
--- a/logd/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-4
\ No newline at end of file
diff --git a/logd/Android.bp b/logd/Android.bp
deleted file mode 100644
index 829c95f..0000000
--- a/logd/Android.bp
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright (C) 2017 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.
-
-// This is what we want to do:
-// event_logtags = $(shell
-// sed -n
-// "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p"
-// $(LOCAL_PATH)/$2/event.logtags)
-// event_flag := $(call event_logtags,auditd)
-// event_flag += $(call event_logtags,logd)
-// event_flag += $(call event_logtags,tag_def)
-// so make sure we do not regret hard-coding it as follows:
-event_flag = [
- "-DAUDITD_LOG_TAG=1003",
- "-DCHATTY_LOG_TAG=1004",
- "-DTAG_DEF_LOG_TAG=1005",
- "-DLIBLOG_LOG_TAG=1006",
-]
-
-cc_defaults {
- name: "logd_defaults",
-
- shared_libs: [
- "libbase",
- "libz",
- ],
- static_libs: ["libzstd"],
- header_libs: ["libcutils_headers"],
- cflags: [
- "-Wextra",
- "-Wthread-safety",
- ] + event_flag,
-
- lto: {
- thin: true,
- },
- sanitize: {
- cfi: true,
- },
- cpp_std: "experimental",
-}
-
-cc_library_static {
- name: "liblogd",
- defaults: ["logd_defaults"],
- host_supported: true,
- srcs: [
- "ChattyLogBuffer.cpp",
- "CompressionEngine.cpp",
- "LogBufferElement.cpp",
- "LogReaderList.cpp",
- "LogReaderThread.cpp",
- "LogSize.cpp",
- "LogStatistics.cpp",
- "LogTags.cpp",
- "LogdLock.cpp",
- "PruneList.cpp",
- "SerializedFlushToState.cpp",
- "SerializedLogBuffer.cpp",
- "SerializedLogChunk.cpp",
- "SimpleLogBuffer.cpp",
- ],
- static_libs: ["liblog"],
- logtags: ["event.logtags"],
-
- export_include_dirs: ["."],
-}
-
-cc_binary {
- name: "logd",
- defaults: ["logd_defaults"],
- init_rc: ["logd.rc"],
-
- srcs: [
- "main.cpp",
- "LogPermissions.cpp",
- "CommandListener.cpp",
- "LogListener.cpp",
- "LogReader.cpp",
- "LogAudit.cpp",
- "LogKlog.cpp",
- "libaudit.cpp",
- ],
-
- static_libs: [
- "liblog",
- "liblogd",
- ],
-
- shared_libs: [
- "libsysutils",
- "libcutils",
- "libpackagelistparser",
- "libprocessgroup",
- "libcap",
- ],
-}
-
-cc_binary {
- name: "auditctl",
-
- srcs: [
- "auditctl.cpp",
- "libaudit.cpp",
- ],
-
- shared_libs: ["libbase"],
-
- cflags: [
- "-Wextra",
- ],
-}
-
-prebuilt_etc {
- name: "logtagd.rc",
- src: "logtagd.rc",
- sub_dir: "init",
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-cc_defaults {
- name: "logd-unit-test-defaults",
-
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wthread-safety",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ] + event_flag,
-
- srcs: [
- "ChattyLogBufferTest.cpp",
- "logd_test.cpp",
- "LogBufferTest.cpp",
- "SerializedLogChunkTest.cpp",
- "SerializedFlushToStateTest.cpp",
- ],
- sanitize: {
- cfi: true,
- },
- static_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "liblogd",
- "libselinux",
- "libz",
- "libzstd",
- ],
-}
-
-// Build tests for the logger. Run with:
-// adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
-cc_test {
- name: "logd-unit-tests",
- host_supported: true,
- defaults: ["logd-unit-test-defaults"],
-}
-
-cc_test {
- name: "CtsLogdTestCases",
- defaults: ["logd-unit-test-defaults"],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
- test_suites: [
- "cts",
- "device-tests",
- ],
-}
-
-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/AndroidTest.xml b/logd/AndroidTest.xml
deleted file mode 100644
index a25dc44..0000000
--- a/logd/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<configuration description="Config for CTS Logging Daemon test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="systems" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsLogdTestCases" />
- <option name="runtime-hint" value="65s" />
- </test>
-</configuration>
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
deleted file mode 100644
index 19dad17..0000000
--- a/logd/ChattyLogBuffer.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-// for manual checking of stale entries during ChattyLogBuffer::erase()
-//#define DEBUG_CHECK_FOR_STALE_ENTRIES
-
-#include "ChattyLogBuffer.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/user.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <limits>
-#include <unordered_map>
-#include <utility>
-
-#include <private/android_logger.h>
-
-#include "LogUtils.h"
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
- LogStatistics* stats)
- : SimpleLogBuffer(reader_list, tags, stats), prune_(prune) {}
-
-ChattyLogBuffer::~ChattyLogBuffer() {}
-
-enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
-
-static enum match_type Identical(const LogBufferElement& elem, const LogBufferElement& last) {
- ssize_t lenl = elem.msg_len();
- if (lenl <= 0) return DIFFERENT; // value if this represents a chatty elem
- ssize_t lenr = last.msg_len();
- if (lenr <= 0) return DIFFERENT; // value if this represents a chatty elem
- if (elem.uid() != last.uid()) return DIFFERENT;
- if (elem.pid() != last.pid()) return DIFFERENT;
- if (elem.tid() != last.tid()) return DIFFERENT;
-
- // last is more than a minute old, stop squashing identical messages
- if (elem.realtime().nsec() > (last.realtime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT;
-
- // Identical message
- const char* msgl = elem.msg();
- const char* msgr = last.msg();
- if (lenl == lenr) {
- if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
- // liblog tagged messages (content gets summed)
- if (elem.log_id() == LOG_ID_EVENTS && lenl == sizeof(android_log_event_int_t) &&
- !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
- elem.GetTag() == LIBLOG_LOG_TAG) {
- return SAME_LIBLOG;
- }
- }
-
- // audit message (except sequence number) identical?
- if (IsBinary(last.log_id()) &&
- lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
- lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t))) {
- if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) {
- return DIFFERENT;
- }
- msgl += sizeof(android_log_event_string_t);
- lenl -= sizeof(android_log_event_string_t);
- msgr += sizeof(android_log_event_string_t);
- lenr -= sizeof(android_log_event_string_t);
- }
- static const char avc[] = "): avc: ";
- const char* avcl = android::strnstr(msgl, lenl, avc);
- if (!avcl) return DIFFERENT;
- lenl -= avcl - msgl;
- const char* avcr = android::strnstr(msgr, lenr, avc);
- if (!avcr) return DIFFERENT;
- lenr -= avcr - msgr;
- if (lenl != lenr) return DIFFERENT;
- if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) {
- return DIFFERENT;
- }
- return SAME;
-}
-
-void ChattyLogBuffer::LogInternal(LogBufferElement&& elem) {
- // b/137093665: don't coalesce security messages.
- if (elem.log_id() == LOG_ID_SECURITY) {
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
- int log_id = elem.log_id();
-
- // Initialize last_logged_elements_ to a copy of elem if logging the first element for a log_id.
- if (!last_logged_elements_[log_id]) {
- last_logged_elements_[log_id].emplace(elem);
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
-
- LogBufferElement& current_last = *last_logged_elements_[log_id];
- enum match_type match = Identical(elem, current_last);
-
- if (match == DIFFERENT) {
- if (duplicate_elements_[log_id]) {
- // If we previously had 3+ identical messages, log the chatty message.
- if (duplicate_elements_[log_id]->dropped_count() > 0) {
- SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
- }
- duplicate_elements_[log_id].reset();
- // Log the saved copy of the last identical message seen.
- SimpleLogBuffer::LogInternal(std::move(current_last));
- }
- last_logged_elements_[log_id].emplace(elem);
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
-
- // 2 identical message: set duplicate_elements_ appropriately.
- if (!duplicate_elements_[log_id]) {
- duplicate_elements_[log_id].emplace(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
-
- // 3+ identical LIBLOG event messages: coalesce them into last_logged_elements_.
- if (match == SAME_LIBLOG) {
- const android_log_event_int_t* current_last_event =
- reinterpret_cast<const android_log_event_int_t*>(current_last.msg());
- int64_t current_last_count = current_last_event->payload.data;
- android_log_event_int_t* elem_event =
- reinterpret_cast<android_log_event_int_t*>(const_cast<char*>(elem.msg()));
- int64_t elem_count = elem_event->payload.data;
-
- int64_t total = current_last_count + elem_count;
- if (total > std::numeric_limits<int32_t>::max()) {
- SimpleLogBuffer::LogInternal(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
- stats()->AddTotal(current_last.log_id(), current_last.msg_len());
- elem_event->payload.data = total;
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
-
- // 3+ identical messages (not LIBLOG) messages: increase the drop count.
- uint16_t dropped_count = duplicate_elements_[log_id]->dropped_count();
- if (dropped_count == std::numeric_limits<uint16_t>::max()) {
- SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
- dropped_count = 0;
- }
- // We're dropping the current_last log so add its stats to the total.
- stats()->AddTotal(current_last.log_id(), current_last.msg_len());
- // Use current_last for tracking the dropped count to always use the latest timestamp.
- current_last.SetDropped(dropped_count + 1);
- duplicate_elements_[log_id].emplace(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
-}
-
-LogBufferElementCollection::iterator ChattyLogBuffer::Erase(LogBufferElementCollection::iterator it,
- bool coalesce) {
- LogBufferElement& element = *it;
- log_id_t id = element.log_id();
-
- // Remove iterator references in the various lists that will become stale
- // after the element is erased from the main logging list.
-
- { // start of scope for found iterator
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag() : element.uid();
- LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
- if ((found != mLastWorst[id].end()) && (it == found->second)) {
- mLastWorst[id].erase(found);
- }
- }
-
- { // start of scope for pid found iterator
- // element->uid() may not be AID_SYSTEM for next-best-watermark.
- // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
- // long term code stability, find() check should be fast for those ids.
- LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element.pid());
- if (found != mLastWorstPidOfSystem[id].end() && it == found->second) {
- mLastWorstPidOfSystem[id].erase(found);
- }
- }
-
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
- LogBufferElementCollection::iterator bad = it;
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->GetTag() : element->uid();
-#endif
-
- if (coalesce) {
- stats()->Erase(element.ToLogStatisticsElement());
- } else {
- stats()->Subtract(element.ToLogStatisticsElement());
- }
-
- it = SimpleLogBuffer::Erase(it);
-
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
- log_id_for_each(i) {
- for (auto b : mLastWorst[i]) {
- if (bad == b.second) {
- LOG(ERROR) << StringPrintf("stale mLastWorst[%d] key=%d mykey=%d", i, b.first, key);
- }
- }
- for (auto b : mLastWorstPidOfSystem[i]) {
- if (bad == b.second) {
- LOG(ERROR) << StringPrintf("stale mLastWorstPidOfSystem[%d] pid=%d", i, b.first);
- }
- }
- }
-#endif
- return it;
-}
-
-// Define a temporary mechanism to report the last LogBufferElement pointer
-// for the specified uid, pid and tid. Used below to help merge-sort when
-// pruning for worst UID.
-class LogBufferElementLast {
- typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
- LogBufferElementMap map;
-
- public:
- bool coalesce(LogBufferElement* element, uint16_t dropped) {
- uint64_t key = LogBufferElementKey(element->uid(), element->pid(), element->tid());
- LogBufferElementMap::iterator it = map.find(key);
- if (it != map.end()) {
- LogBufferElement* found = it->second;
- uint16_t moreDropped = found->dropped_count();
- if ((dropped + moreDropped) > USHRT_MAX) {
- map.erase(it);
- } else {
- found->SetDropped(dropped + moreDropped);
- return true;
- }
- }
- return false;
- }
-
- void add(LogBufferElement* element) {
- uint64_t key = LogBufferElementKey(element->uid(), element->pid(), element->tid());
- map[key] = element;
- }
-
- void clear() { map.clear(); }
-
- void clear(LogBufferElement* element) {
- uint64_t current = element->realtime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
- for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
- LogBufferElement* mapElement = it->second;
- if (mapElement->dropped_count() >= EXPIRE_THRESHOLD &&
- current > mapElement->realtime().nsec()) {
- it = map.erase(it);
- } else {
- ++it;
- }
- }
- }
-
- private:
- uint64_t LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) {
- return uint64_t(uid) << 32 | uint64_t(pid) << 16 | uint64_t(tid);
- }
-};
-
-// prune "pruneRows" of type "id" from the buffer.
-//
-// This garbage collection task is used to expire log entries. It is called to
-// remove all logs (clear), all UID logs (unprivileged clear), or every
-// 256 or 10% of the total logs (whichever is less) to prune the logs.
-//
-// First there is a prep phase where we discover the reader region lock that
-// acts as a backstop to any pruning activity to stop there and go no further.
-//
-// There are three major pruning loops that follow. All expire from the oldest
-// entries. Since there are multiple log buffers, the Android logging facility
-// will appear to drop entries 'in the middle' when looking at multiple log
-// sources and buffers. This effect is slightly more prominent when we prune
-// the worst offender by logging source. Thus the logs slowly loose content
-// and value as you move back in time. This is preferred since chatty sources
-// invariably move the logs value down faster as less chatty sources would be
-// expired in the noise.
-//
-// The first pass prunes elements that match 3 possible rules:
-// 1) A high priority prune rule, for example ~100/20, which indicates elements from UID 100 and PID
-// 20 should be pruned in this first pass.
-// 2) The default chatty pruning rule, ~!. This rule sums the total size spent on log messages for
-// each UID this log buffer. If the highest sum consumes more than 12.5% of the log buffer, then
-// these elements from that UID are pruned.
-// 3) The default AID_SYSTEM pruning rule, ~1000/!. This rule is a special case to 2), if
-// AID_SYSTEM is the top consumer of the log buffer, then this rule sums the total size spent on
-// log messages for each PID in AID_SYSTEM in this log buffer and prunes elements from the PID
-// with the highest sum.
-// This pass reevaluates the sums for rules 2) and 3) for every log message pruned. It creates
-// 'chatty' entries for the elements that it prunes and merges related chatty entries together. It
-// completes when one of three conditions have been met:
-// 1) The requested element count has been pruned.
-// 2) There are no elements that match any of these rules.
-// 3) A reader is referencing the oldest element that would match these rules.
-//
-// The second pass prunes elements starting from the beginning of the log. It skips elements that
-// match any low priority prune rules. It completes when one of three conditions have been met:
-// 1) The requested element count has been pruned.
-// 2) All elements except those mwatching low priority prune rules have been pruned.
-// 3) A reader is referencing the oldest element that would match these rules.
-//
-// The final pass only happens if there are any low priority prune rules and if the first two passes
-// were unable to prune the requested number of elements. It prunes elements all starting from the
-// beginning of the log, regardless of if they match any low priority prune rules.
-//
-// If the requested number of logs was unable to be pruned, KickReader() is called to mitigate the
-// situation before the next call to Prune() and the function returns false. Otherwise, if the
-// requested number of logs or all logs present in the buffer are pruned, in the case of Clear(),
-// it returns true.
-bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
- LogReaderThread* oldest = nullptr;
- bool clearAll = pruneRows == ULONG_MAX;
-
- // Region locked?
- for (const auto& reader_thread : reader_list()->reader_threads()) {
- if (!reader_thread->IsWatching(id)) {
- continue;
- }
- if (!oldest || oldest->start() > reader_thread->start() ||
- (oldest->start() == reader_thread->start() &&
- reader_thread->deadline().time_since_epoch().count() != 0)) {
- oldest = reader_thread.get();
- }
- }
-
- LogBufferElementCollection::iterator it;
-
- if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
- // Only here if clear all request from non system source, so chatty
- // filter logistics is not required.
- it = GetOldest(id);
- while (it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id || element.uid() != caller_uid) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, pruneRows);
- return false;
- }
-
- it = Erase(it);
- if (--pruneRows == 0) {
- return true;
- }
- }
- return true;
- }
-
- // First prune pass.
- bool check_high_priority = id != LOG_ID_SECURITY && prune_->HasHighPriorityPruneRules();
- while (!clearAll && (pruneRows > 0)) {
- // recalculate the worst offender on every batched pass
- int worst = -1; // not valid for uid() or getKey()
- size_t worst_sizes = 0;
- size_t second_worst_sizes = 0;
- pid_t worstPid = 0; // POSIX guarantees PID != 0
-
- if (worstUidEnabledForLogid(id) && prune_->worst_uid_enabled()) {
- // Calculate threshold as 12.5% of available storage
- size_t threshold = max_size(id) / 8;
-
- if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
- stats()->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
- // per-pid filter for AID_SYSTEM sources is too complex
- } else {
- stats()->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
-
- if (worst == AID_SYSTEM && prune_->worst_pid_of_system_enabled()) {
- stats()->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
- }
- }
- }
-
- // skip if we have neither a worst UID or high priority prune rules
- if (worst == -1 && !check_high_priority) {
- break;
- }
-
- bool kick = false;
- bool leading = true; // true if starting from the oldest log entry, false if starting from
- // a specific chatty entry.
- // Perform at least one mandatory garbage collection cycle in following
- // - clear leading chatty tags
- // - coalesce chatty tags
- // - check age-out of preserved logs
- bool gc = pruneRows <= 1;
- if (!gc && (worst != -1)) {
- { // begin scope for worst found iterator
- LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
- if (found != mLastWorst[id].end() && found->second != logs().end()) {
- leading = false;
- it = found->second;
- }
- }
- if (worstPid) { // begin scope for pid worst found iterator
- // FYI: worstPid only set if !LOG_ID_EVENTS and
- // !LOG_ID_SECURITY, not going to make that assumption ...
- LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid);
- if (found != mLastWorstPidOfSystem[id].end() && found->second != logs().end()) {
- leading = false;
- it = found->second;
- }
- }
- }
- if (leading) {
- it = GetOldest(id);
- }
- static const log_time too_old{EXPIRE_HOUR_THRESHOLD * 60 * 60, 0};
- LogBufferElementCollection::iterator lastt;
- lastt = logs().end();
- --lastt;
- LogBufferElementLast last;
- while (it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (oldest && oldest->start() <= element.sequence()) {
- // Do not let chatty eliding trigger any reader mitigation
- break;
- }
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
- // below this point element->log_id() == id
-
- uint16_t dropped = element.dropped_count();
-
- // remove any leading drops
- if (leading && dropped) {
- it = Erase(it);
- continue;
- }
-
- if (dropped && last.coalesce(&element, dropped)) {
- it = Erase(it, true);
- continue;
- }
-
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag()
- : element.uid();
-
- if (check_high_priority && prune_->IsHighPriority(&element)) {
- last.clear(&element);
- it = Erase(it);
- if (dropped) {
- continue;
- }
-
- pruneRows--;
- if (pruneRows == 0) {
- break;
- }
-
- if (key == worst) {
- kick = true;
- if (worst_sizes < second_worst_sizes) {
- break;
- }
- worst_sizes -= element.msg_len();
- }
- continue;
- }
-
- if (element.realtime() < (lastt->realtime() - too_old) ||
- element.realtime() > lastt->realtime()) {
- break;
- }
-
- if (dropped) {
- last.add(&element);
- if (worstPid && ((!gc && element.pid() == worstPid) ||
- mLastWorstPidOfSystem[id].find(element.pid()) ==
- mLastWorstPidOfSystem[id].end())) {
- // element->uid() may not be AID_SYSTEM, next best
- // watermark if current one empty. id is not LOG_ID_EVENTS
- // or LOG_ID_SECURITY because of worstPid check.
- mLastWorstPidOfSystem[id][element.pid()] = it;
- }
- if ((!gc && !worstPid && (key == worst)) ||
- (mLastWorst[id].find(key) == mLastWorst[id].end())) {
- mLastWorst[id][key] = it;
- }
- ++it;
- continue;
- }
-
- if (key != worst || (worstPid && element.pid() != worstPid)) {
- leading = false;
- last.clear(&element);
- ++it;
- continue;
- }
- // key == worst below here
- // If worstPid set, then element->pid() == worstPid below here
-
- pruneRows--;
- if (pruneRows == 0) {
- break;
- }
-
- kick = true;
-
- uint16_t len = element.msg_len();
-
- // do not create any leading drops
- if (leading) {
- it = Erase(it);
- } else {
- stats()->Drop(element.ToLogStatisticsElement());
- element.SetDropped(1);
- if (last.coalesce(&element, 1)) {
- it = Erase(it, true);
- } else {
- last.add(&element);
- if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) ==
- mLastWorstPidOfSystem[id].end())) {
- // element->uid() may not be AID_SYSTEM, next best
- // watermark if current one empty. id is not
- // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
- mLastWorstPidOfSystem[id][worstPid] = it;
- }
- if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) {
- mLastWorst[id][worst] = it;
- }
- ++it;
- }
- }
- if (worst_sizes < second_worst_sizes) {
- break;
- }
- worst_sizes -= len;
- }
- last.clear();
-
- if (!kick || !prune_->worst_uid_enabled()) {
- break; // the following loop will ask bad clients to skip/drop
- }
- }
-
- // Second prune pass.
- bool skipped_low_priority_prune = false;
- bool check_low_priority =
- id != LOG_ID_SECURITY && prune_->HasLowPriorityPruneRules() && !clearAll;
- it = GetOldest(id);
- while (pruneRows > 0 && it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- it++;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- if (!skipped_low_priority_prune) KickReader(oldest, id, pruneRows);
- break;
- }
-
- if (check_low_priority && !element.dropped_count() && prune_->IsLowPriority(&element)) {
- skipped_low_priority_prune = true;
- it++;
- continue;
- }
-
- it = Erase(it);
- pruneRows--;
- }
-
- // Third prune pass.
- if (skipped_low_priority_prune && pruneRows > 0) {
- it = GetOldest(id);
- while (it != logs().end() && pruneRows > 0) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, pruneRows);
- break;
- }
-
- it = Erase(it);
- pruneRows--;
- }
- }
-
- return pruneRows == 0 || it == logs().end();
-}
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
deleted file mode 100644
index e5b8611..0000000
--- a/logd/ChattyLogBuffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <sys/types.h>
-
-#include <list>
-#include <optional>
-#include <string>
-
-#include <android-base/thread_annotations.h>
-#include <android/log.h>
-#include <private/android_filesystem_config.h>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogReaderList.h"
-#include "LogReaderThread.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogWriter.h"
-#include "LogdLock.h"
-#include "PruneList.h"
-#include "SimpleLogBuffer.h"
-
-typedef std::list<LogBufferElement> LogBufferElementCollection;
-
-class ChattyLogBuffer : public SimpleLogBuffer {
- // watermark of any worst/chatty uid processing
- typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap;
- LogBufferIteratorMap mLastWorst[LOG_ID_MAX] GUARDED_BY(logd_lock);
- // watermark of any worst/chatty pid of system processing
- typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap;
- LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX] GUARDED_BY(logd_lock);
-
- public:
- ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
- LogStatistics* stats);
- ~ChattyLogBuffer();
-
- protected:
- bool Prune(log_id_t id, unsigned long pruneRows, uid_t uid) REQUIRES(logd_lock) override;
- void LogInternal(LogBufferElement&& elem) REQUIRES(logd_lock) override;
-
- private:
- LogBufferElementCollection::iterator Erase(LogBufferElementCollection::iterator it,
- bool coalesce = false) REQUIRES(logd_lock);
-
- PruneList* prune_;
-
- // This always contains a copy of the last message logged, for deduplication.
- std::optional<LogBufferElement> last_logged_elements_[LOG_ID_MAX] GUARDED_BY(logd_lock);
- // This contains an element if duplicate messages are seen.
- // Its `dropped` count is `duplicates seen - 1`.
- std::optional<LogBufferElement> duplicate_elements_[LOG_ID_MAX] GUARDED_BY(logd_lock);
-};
diff --git a/logd/ChattyLogBufferTest.cpp b/logd/ChattyLogBufferTest.cpp
deleted file mode 100644
index e273efe..0000000
--- a/logd/ChattyLogBufferTest.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * 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 "LogBufferTest.h"
-
-class ChattyLogBufferTest : public LogBufferTest {};
-
-TEST_P(ChattyLogBufferTest, deduplication_simple) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(0, "test_tag", "duplicate"),
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "not_same"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "duplicate"),
- make_message(5, "test_tag", "not_same"),
- make_message(6, "test_tag", "duplicate"),
- make_message(7, "test_tag", "duplicate"),
- make_message(8, "test_tag", "duplicate"),
- make_message(9, "test_tag", "not_same"),
- make_message(10, "test_tag", "duplicate"),
- make_message(11, "test_tag", "duplicate"),
- make_message(12, "test_tag", "duplicate"),
- make_message(13, "test_tag", "duplicate"),
- make_message(14, "test_tag", "duplicate"),
- make_message(15, "test_tag", "duplicate"),
- make_message(16, "test_tag", "not_same"),
- make_message(100, "test_tag", "duplicate"),
- make_message(200, "test_tag", "duplicate"),
- make_message(300, "test_tag", "duplicate"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
-
- std::unique_ptr<FlushToState> flush_to_state =
- log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- }
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, "test_tag", "duplicate"),
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "not_same"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "duplicate"),
- make_message(5, "test_tag", "not_same"),
- // 3 duplicate logs together print the first, a 1 count chatty message, then the last.
- make_message(6, "test_tag", "duplicate"),
- make_message(7, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ identical 1 line", true),
- make_message(8, "test_tag", "duplicate"),
- make_message(9, "test_tag", "not_same"),
- // 6 duplicate logs together print the first, a 4 count chatty message, then the last.
- make_message(10, "test_tag", "duplicate"),
- make_message(14, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ identical 4 lines", true),
- make_message(15, "test_tag", "duplicate"),
- make_message(16, "test_tag", "not_same"),
- // duplicate logs > 1 minute apart are not deduplicated.
- make_message(100, "test_tag", "duplicate"),
- make_message(200, "test_tag", "duplicate"),
- make_message(300, "test_tag", "duplicate"),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-};
-
-TEST_P(ChattyLogBufferTest, deduplication_overflow) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- uint32_t sec = 0;
- std::vector<LogMessage> log_messages = {
- make_message(sec++, "test_tag", "normal"),
- };
- size_t expired_per_chatty_message = std::numeric_limits<uint16_t>::max();
- for (size_t i = 0; i < expired_per_chatty_message + 3; ++i) {
- log_messages.emplace_back(make_message(sec++, "test_tag", "duplicate"));
- }
- log_messages.emplace_back(make_message(sec++, "test_tag", "normal"));
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state =
- log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- }
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, "test_tag", "normal"),
- make_message(1, "test_tag", "duplicate"),
- make_message(expired_per_chatty_message + 1, "chatty",
- "uid=0\\([^\\)]+\\) [^ ]+ identical 65535 lines", true),
- make_message(expired_per_chatty_message + 2, "chatty",
- "uid=0\\([^\\)]+\\) [^ ]+ identical 1 line", true),
- make_message(expired_per_chatty_message + 3, "test_tag", "duplicate"),
- make_message(expired_per_chatty_message + 4, "test_tag", "normal"),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(ChattyLogBufferTest, deduplication_liblog) {
- auto make_message = [&](uint32_t sec, int32_t tag, int32_t count) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_EVENTS, .uid = 0};
- android_log_event_int_t liblog_event = {
- .header.tag = tag, .payload.type = EVENT_TYPE_INT, .payload.data = count};
- return {entry, std::string(reinterpret_cast<char*>(&liblog_event), sizeof(liblog_event)),
- false};
- };
-
- // LIBLOG_LOG_TAG
- std::vector<LogMessage> log_messages = {
- make_message(0, 1234, 1),
- make_message(1, LIBLOG_LOG_TAG, 3),
- make_message(2, 1234, 2),
- make_message(3, LIBLOG_LOG_TAG, 3),
- make_message(4, LIBLOG_LOG_TAG, 4),
- make_message(5, 1234, 223),
- make_message(6, LIBLOG_LOG_TAG, 2),
- make_message(7, LIBLOG_LOG_TAG, 3),
- make_message(8, LIBLOG_LOG_TAG, 4),
- make_message(9, 1234, 227),
- make_message(10, LIBLOG_LOG_TAG, 1),
- make_message(11, LIBLOG_LOG_TAG, 3),
- make_message(12, LIBLOG_LOG_TAG, 2),
- make_message(13, LIBLOG_LOG_TAG, 3),
- make_message(14, LIBLOG_LOG_TAG, 5),
- make_message(15, 1234, 227),
- make_message(16, LIBLOG_LOG_TAG, 2),
- make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
- make_message(18, LIBLOG_LOG_TAG, 3),
- make_message(19, LIBLOG_LOG_TAG, 5),
- make_message(20, 1234, 227),
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state =
- log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- }
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, 1234, 1),
- make_message(1, LIBLOG_LOG_TAG, 3),
- make_message(2, 1234, 2),
- make_message(3, LIBLOG_LOG_TAG, 3),
- make_message(4, LIBLOG_LOG_TAG, 4),
- make_message(5, 1234, 223),
- // More than 2 liblog events (3 here), sum their value into the third message.
- make_message(6, LIBLOG_LOG_TAG, 2),
- make_message(8, LIBLOG_LOG_TAG, 7),
- make_message(9, 1234, 227),
- // More than 2 liblog events (5 here), sum their value into the third message.
- make_message(10, LIBLOG_LOG_TAG, 1),
- make_message(14, LIBLOG_LOG_TAG, 13),
- make_message(15, 1234, 227),
- // int32_t max is the max for a chatty message, beyond that we must use new messages.
- make_message(16, LIBLOG_LOG_TAG, 2),
- make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
- make_message(19, LIBLOG_LOG_TAG, 8),
- make_message(20, 1234, 227),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-};
-
-TEST_P(ChattyLogBufferTest, no_leading_chatty_simple) {
- auto make_message = [&](uint32_t sec, int32_t pid, uint32_t uid, uint32_t lid, const char* tag,
- const char* msg, bool regex = false) -> LogMessage {
- logger_entry entry = {.pid = pid, .tid = 1, .sec = sec, .nsec = 1, .lid = lid, .uid = uid};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(1, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(2, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(3, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(4, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(6, 2, 2, LOG_ID_SYSTEM, "test_tag", "not duplicate2"),
- make_message(7, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(8, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(9, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(10, 1, 1, LOG_ID_MAIN, "test_tag", "not duplicate1"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- // After logging log_messages, the below is what should be in the buffer:
- // PID=1, LOG_ID_MAIN duplicate1
- // [1] PID=2, LOG_ID_SYSTEM duplicate2
- // PID=2, LOG_ID_SYSTEM chatty drop
- // PID=2, LOG_ID_SYSTEM duplicate2
- // PID=2, LOG_ID_SYSTEM not duplicate2
- // [2] PID=1, LOG_ID_MAIN chatty drop
- // [3] PID=1, LOG_ID_MAIN duplicate1
- // PID=1, LOG_ID_MAIN not duplicate1
-
- // We then read from the 2nd sequence number, starting from log message [1], but filtering out
- // everything but PID=1, which results in us starting with log message [2], which is a chatty
- // drop. Code prior to this test case would erroneously print it. The intended behavior that
- // this test checks prints logs starting from log message [3].
-
- // clang-format off
- std::vector<LogMessage> expected_log_messages = {
- make_message(9, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(10, 1, 1, LOG_ID_MAIN, "test_tag", "not duplicate1"),
- };
- FixupMessages(&expected_log_messages);
- // clang-format on
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, ~0, 1, {}, 2, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
-
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(ChattyLogBufferTest, no_leading_chatty_tail) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "duplicate"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "not_duplicate"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- // After logging log_messages, the below is what should be in the buffer:
- // "duplicate"
- // chatty
- // "duplicate"
- // "not duplicate"
-
- // We then read the tail 3 messages expecting there to not be a chatty message, meaning that we
- // should only see the last two messages.
-
- // clang-format off
- std::vector<LogMessage> expected_log_messages = {
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "not_duplicate"),
- };
- FixupMessages(&expected_log_messages);
- // clang-format on
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 3, ~0, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
-
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-INSTANTIATE_TEST_CASE_P(ChattyLogBufferTests, ChattyLogBufferTest, testing::Values("chatty"));
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
deleted file mode 100644
index 0ba1621..0000000
--- a/logd/CommandListener.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "CommandListener.h"
-
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-#include <log/log_properties.h>
-#include <private/android_filesystem_config.h>
-#include <sysutils/SocketClient.h>
-
-#include "LogPermissions.h"
-
-CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune,
- LogStatistics* stats)
- : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune), stats_(stats) {
- registerCmd(new ClearCmd(this));
- registerCmd(new GetBufSizeCmd(this));
- registerCmd(new SetBufSizeCmd(this));
- registerCmd(new GetBufSizeReadableCmd(this));
- registerCmd(new GetBufSizeUsedCmd(this));
- registerCmd(new GetStatisticsCmd(this));
- registerCmd(new SetPruneListCmd(this));
- registerCmd(new GetPruneListCmd(this));
- registerCmd(new GetEventTagCmd(this));
- registerCmd(new ReinitCmd(this));
- registerCmd(new ExitCmd(this));
-}
-
-static void setname() {
- static bool name_set;
- if (!name_set) {
- prctl(PR_SET_NAME, "logd.control");
- name_set = true;
- }
-}
-
-template <typename F>
-static int LogIdCommand(SocketClient* cli, int argc, char** argv, F&& function) {
- setname();
- if (argc < 2) {
- cli->sendMsg("Missing Argument");
- return 0;
- }
-
- int log_id;
- if (!android::base::ParseInt(argv[1], &log_id, static_cast<int>(LOG_ID_MAIN),
- static_cast<int>(LOG_ID_KERNEL))) {
- cli->sendMsg("Range Error");
- return 0;
- }
-
- function(static_cast<log_id_t>(log_id));
- return 0;
-}
-
-int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- return LogIdCommand(cli, argc, argv, [&](log_id_t id) {
- cli->sendMsg(buf()->Clear(id, uid) ? "success" : "busy");
- });
-}
-
-template <typename F>
-static int LogSizeCommand(SocketClient* cli, int argc, char** argv, F&& size_function) {
- return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
- cli->sendMsg(std::to_string(size_function(log_id)).c_str());
- });
-}
-
-int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return buf()->GetSize(id); });
-}
-
-int CommandListener::GetBufSizeReadableCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv,
- [this](log_id_t id) { return stats()->SizeReadable(id); });
-}
-
-int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return stats()->Sizes(id); });
-}
-
-int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
- char** argv) {
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
- }
-
- if (argc < 3) {
- cli->sendMsg("Missing Argument");
- return 0;
- }
- size_t size = atol(argv[2]);
-
- return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
- cli->sendMsg(buf()->SetSize(log_id, size) ? "success" : "busy");
- });
-}
-
-// This returns a string with a length prefix with the format <length>\n<data>\n\f. The length
-// prefix includes the length of the prefix itself.
-static std::string PackageString(const std::string& str) {
- size_t overhead_length = 3; // \n \n \f.
-
- // Number of digits needed to represent length(str + overhead_length).
- size_t str_size_digits = 1 + static_cast<size_t>(log10(str.size() + overhead_length));
- // Number of digits needed to represent the total size.
- size_t total_size_digits =
- 1 + static_cast<size_t>(log10(str.size() + overhead_length + str_size_digits));
-
- // If adding the size prefix causes a new digit to be required to represent the new total
- // size, add it to the 'overhead_length'. This can only happen once, since each new digit
- // allows for 10x the previous size to be recorded.
- if (total_size_digits != str_size_digits) {
- overhead_length++;
- }
-
- size_t total_size = str.size() + overhead_length + str_size_digits;
- return android::base::StringPrintf("%zu\n%s\n\f", total_size, str.c_str());
-}
-
-int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- unsigned int logMask = -1;
- pid_t pid = 0;
- if (argc > 1) {
- logMask = 0;
- for (int i = 1; i < argc; ++i) {
- static const char _pid[] = "pid=";
- if (!strncmp(argv[i], _pid, sizeof(_pid) - 1)) {
- pid = atol(argv[i] + sizeof(_pid) - 1);
- if (pid == 0) {
- cli->sendMsg("PID Error");
- return 0;
- }
- continue;
- }
-
- int id = atoi(argv[i]);
- if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
- cli->sendMsg("Range Error");
- return 0;
- }
- logMask |= 1 << id;
- }
- }
-
- cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str());
- return 0;
-}
-
-int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
- cli->sendMsg(PackageString(prune()->Format()).c_str());
- return 0;
-}
-
-int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
- }
-
- std::string str;
- for (int i = 1; i < argc; ++i) {
- if (str.length()) {
- str += " ";
- }
- str += argv[i];
- }
-
- if (!prune()->Init(str.c_str())) {
- cli->sendMsg("Invalid");
- return 0;
- }
-
- cli->sendMsg("success");
- return 0;
-}
-
-int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- const char* name = nullptr;
- const char* format = nullptr;
- const char* id = nullptr;
- for (int i = 1; i < argc; ++i) {
- static const char _name[] = "name=";
- if (!strncmp(argv[i], _name, strlen(_name))) {
- name = argv[i] + strlen(_name);
- continue;
- }
-
- static const char _format[] = "format=";
- if (!strncmp(argv[i], _format, strlen(_format))) {
- format = argv[i] + strlen(_format);
- continue;
- }
-
- static const char _id[] = "id=";
- if (!strncmp(argv[i], _id, strlen(_id))) {
- id = argv[i] + strlen(_id);
- continue;
- }
- }
-
- if (id) {
- if (format || name) {
- cli->sendMsg("can not mix id= with either format= or name=");
- return 0;
- }
- cli->sendMsg(PackageString(tags()->formatEntry(atoi(id), uid)).c_str());
- return 0;
- }
-
- cli->sendMsg(PackageString(tags()->formatGetEventTag(uid, name, format)).c_str());
-
- return 0;
-}
-
-int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
-
- LOG(INFO) << "logd reinit";
- buf()->Init();
- prune()->Init(nullptr);
-
- // This only works on userdebug and eng devices to re-read the
- // /data/misc/logd/event-log-tags file right after /data is mounted.
- // The operation is near to boot and should only happen once. There
- // are races associated with its use since it can trigger a Rebuild
- // of the file, but that is a can-not-happen since the file was not
- // read yet. More dangerous if called later, but if all is well it
- // should just skip over everything and not write any new entries.
- if (__android_log_is_debuggable()) {
- tags()->ReadFileEventLogTags(tags()->debug_event_log_tags);
- }
-
- cli->sendMsg("success");
-
- return 0;
-}
-
-int CommandListener::ExitCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
-
- cli->sendMsg("success");
- parent_->release(cli);
-
- return 0;
-}
-
-int CommandListener::getLogSocket() {
- static const char socketName[] = "logd";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) {
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
- }
-
- return sock;
-}
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
deleted file mode 100644
index 8e12634..0000000
--- a/logd/CommandListener.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <sysutils/FrameworkCommand.h>
-#include <sysutils/FrameworkListener.h>
-
-#include "LogBuffer.h"
-#include "LogListener.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "PruneList.h"
-
-class CommandListener : public FrameworkListener {
- public:
- CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics);
- virtual ~CommandListener() {}
-
- private:
- static int getLogSocket();
-
- LogBuffer* buf_;
- LogTags* tags_;
- PruneList* prune_;
- LogStatistics* stats_;
-
-#define LogCmd(name, command_string) \
- class name##Cmd : public FrameworkCommand { \
- public: \
- explicit name##Cmd(CommandListener* parent) \
- : FrameworkCommand(#command_string), parent_(parent) {} \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient* c, int argc, char** argv); \
- \
- private: \
- LogBuffer* buf() const { return parent_->buf_; } \
- LogTags* tags() const { return parent_->tags_; } \
- PruneList* prune() const { return parent_->prune_; } \
- LogStatistics* stats() const { return parent_->stats_; } \
- CommandListener* parent_; \
- }
-
- LogCmd(Clear, clear);
- LogCmd(GetBufSize, getLogSize);
- LogCmd(SetBufSize, setLogSize);
- LogCmd(GetBufSizeReadable, getLogSizeReadable);
- LogCmd(GetBufSizeUsed, getLogSizeUsed);
- LogCmd(GetStatistics, getStatistics);
- LogCmd(GetPruneList, getPruneList);
- LogCmd(SetPruneList, setPruneList);
- LogCmd(GetEventTag, getEventTag);
- LogCmd(Reinit, reinit);
- LogCmd(Exit, EXIT);
-#undef LogCmd
-};
diff --git a/logd/CompressionEngine.cpp b/logd/CompressionEngine.cpp
deleted file mode 100644
index da2628c..0000000
--- a/logd/CompressionEngine.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 "CompressionEngine.h"
-
-#include <limits>
-
-#include <android-base/logging.h>
-#include <zlib.h>
-#include <zstd.h>
-
-CompressionEngine& CompressionEngine::GetInstance() {
- static CompressionEngine* engine = new ZstdCompressionEngine();
- return *engine;
-}
-
-bool ZlibCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- int ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
- if (ret != Z_OK) {
- LOG(FATAL) << "deflateInit() failed";
- }
-
- CHECK_LE(data_length, in.size());
- CHECK_LE(in.size(), std::numeric_limits<uint32_t>::max());
- uint32_t deflate_bound = deflateBound(&strm, in.size());
-
- out.Resize(deflate_bound);
-
- strm.avail_in = data_length;
- strm.next_in = in.data();
- strm.avail_out = out.size();
- strm.next_out = out.data();
- ret = deflate(&strm, Z_FINISH);
- CHECK_EQ(ret, Z_STREAM_END);
-
- uint32_t compressed_size = strm.total_out;
- deflateEnd(&strm);
-
- out.Resize(compressed_size);
-
- return true;
-}
-
-bool ZlibCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = in.size();
- strm.next_in = in.data();
- strm.avail_out = out.size();
- strm.next_out = out.data();
-
- inflateInit(&strm);
- int ret = inflate(&strm, Z_NO_FLUSH);
-
- CHECK_EQ(strm.avail_in, 0U);
- CHECK_EQ(strm.avail_out, 0U);
- CHECK_EQ(ret, Z_STREAM_END);
- inflateEnd(&strm);
-
- return true;
-}
-
-bool ZstdCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
- CHECK_LE(data_length, in.size());
-
- size_t compress_bound = ZSTD_compressBound(data_length);
- out.Resize(compress_bound);
-
- size_t out_size = ZSTD_compress(out.data(), out.size(), in.data(), data_length, 1);
- if (ZSTD_isError(out_size)) {
- LOG(FATAL) << "ZSTD_compress failed: " << ZSTD_getErrorName(out_size);
- }
- out.Resize(out_size);
-
- return true;
-}
-
-bool ZstdCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
- size_t result = ZSTD_decompress(out.data(), out.size(), in.data(), in.size());
- if (ZSTD_isError(result)) {
- LOG(FATAL) << "ZSTD_decompress failed: " << ZSTD_getErrorName(result);
- }
- CHECK_EQ(result, out.size());
- return true;
-}
diff --git a/logd/CompressionEngine.h b/logd/CompressionEngine.h
deleted file mode 100644
index 0f760ed..0000000
--- a/logd/CompressionEngine.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 <memory>
-
-#include "SerializedData.h"
-
-class CompressionEngine {
- public:
- static CompressionEngine& GetInstance();
-
- virtual ~CompressionEngine(){};
-
- virtual bool Compress(SerializedData& in, size_t data_length, SerializedData& out) = 0;
- // Decompress the contents of `in` into `out`. `out.size()` must be set to the decompressed
- // size of the contents.
- virtual bool Decompress(SerializedData& in, SerializedData& out) = 0;
-};
-
-class ZlibCompressionEngine : public CompressionEngine {
- public:
- bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
- bool Decompress(SerializedData& in, SerializedData& out) override;
-};
-
-class ZstdCompressionEngine : public CompressionEngine {
- public:
- bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
- bool Decompress(SerializedData& in, SerializedData& out) override;
-};
\ No newline at end of file
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
deleted file mode 100644
index 0e17476..0000000
--- a/logd/LogAudit.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogAudit.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/uio.h>
-#include <syslog.h>
-
-#include <fstream>
-#include <sstream>
-
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogKlog.h"
-#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, '>'
-
-LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats)
- : SocketListener(getLogSocket(), false),
- logbuf(buf),
- fdDmesg(fdDmesg),
- 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),
- 'l',
- 'o',
- 'g',
- 'd',
- '.',
- 'a',
- 'u',
- 'd',
- 'i',
- 't',
- 'd',
- ':',
- ' ',
- 's',
- 't',
- 'a',
- 'r',
- 't',
- '\n' };
- write(fdDmesg, auditd_message, sizeof(auditd_message));
-}
-
-bool LogAudit::onDataAvailable(SocketClient* cli) {
- if (!initialized) {
- prctl(PR_SET_NAME, "logd.auditd");
- initialized = true;
- }
-
- struct audit_message rep;
-
- rep.nlh.nlmsg_type = 0;
- rep.nlh.nlmsg_len = 0;
- rep.data[0] = '\0';
-
- if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
- SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
- return false;
- }
-
- logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
-
- return true;
-}
-
-static inline bool hasMetadata(char* str, int str_len) {
- // need to check and see if str already contains bug metadata from
- // possibility of stuttering if log audit crashes and then reloads kernel
- // messages. Kernel denials that contain metadata will either end in
- // "b/[0-9]+$" or "b/[0-9]+ duplicate messages suppressed$" which will put
- // a '/' character at either 9 or 39 indices away from the end of the str.
- return str_len >= 39 &&
- (str[str_len - 9] == '/' || str[str_len - 39] == '/');
-}
-
-std::map<std::string, std::string> LogAudit::populateDenialMap() {
- std::ifstream bug_file("/vendor/etc/selinux/selinux_denial_metadata");
- std::string line;
- // allocate a map for the static map pointer in auditParse to keep track of,
- // this function only runs once
- std::map<std::string, std::string> denial_to_bug;
- if (bug_file.good()) {
- std::string scontext;
- std::string tcontext;
- std::string tclass;
- std::string bug_num;
- while (std::getline(bug_file, line)) {
- std::stringstream split_line(line);
- split_line >> scontext >> tcontext >> tclass >> bug_num;
- denial_to_bug.emplace(scontext + tcontext + tclass, bug_num);
- }
- }
- return denial_to_bug;
-}
-
-std::string LogAudit::denialParse(const std::string& denial, char terminator,
- const std::string& search_term) {
- size_t start_index = denial.find(search_term);
- if (start_index != std::string::npos) {
- start_index += search_term.length();
- return denial.substr(
- start_index, denial.find(terminator, start_index) - start_index);
- }
- return "";
-}
-
-void LogAudit::auditParse(const std::string& string, uid_t uid,
- std::string* bug_num) {
- static std::map<std::string, std::string> denial_to_bug =
- populateDenialMap();
- std::string scontext = denialParse(string, ':', "scontext=u:object_r:");
- std::string tcontext = denialParse(string, ':', "tcontext=u:object_r:");
- std::string tclass = denialParse(string, ' ', "tclass=");
- if (scontext.empty()) {
- scontext = denialParse(string, ':', "scontext=u:r:");
- }
- if (tcontext.empty()) {
- tcontext = denialParse(string, ':', "tcontext=u:r:");
- }
- auto search = denial_to_bug.find(scontext + tcontext + tclass);
- if (search != denial_to_bug.end()) {
- bug_num->assign(" " + search->second);
- } else {
- bug_num->assign("");
- }
-
- // Ensure the uid name is not null before passing it to the bug string.
- if (uid >= AID_APP_START && uid <= AID_APP_END) {
- char* uidname = android::uidToName(uid);
- if (uidname) {
- bug_num->append(" app=");
- bug_num->append(uidname);
- free(uidname);
- }
- }
-}
-
-int LogAudit::logPrint(const char* fmt, ...) {
- if (fmt == nullptr) {
- return -EINVAL;
- }
-
- va_list args;
-
- char* str = nullptr;
- va_start(args, fmt);
- int rc = vasprintf(&str, fmt, args);
- va_end(args);
-
- if (rc < 0) {
- return rc;
- }
- char* cp;
- // Work around kernels missing
- // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
- // Such kernels improperly add newlines inside audit messages.
- while ((cp = strchr(str, '\n'))) {
- *cp = ' ';
- }
-
- while ((cp = strstr(str, " "))) {
- memmove(cp, cp + 1, strlen(cp + 1) + 1);
- }
- pid_t pid = getpid();
- pid_t tid = gettid();
- uid_t uid = AID_LOGD;
- static const char pid_str[] = " pid=";
- char* pidptr = strstr(str, pid_str);
- if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
- cp = pidptr + sizeof(pid_str) - 1;
- pid = 0;
- while (isdigit(*cp)) {
- pid = (pid * 10) + (*cp - '0');
- ++cp;
- }
- tid = pid;
- uid = stats_->PidToUid(pid);
- memmove(pidptr, cp, strlen(cp) + 1);
- }
-
- bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
- static std::string denial_metadata;
- if ((fdDmesg >= 0) && initialized) {
- struct iovec iov[4];
- static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
- static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
- static const char newline[] = "\n";
-
- auditParse(str, uid, &denial_metadata);
- iov[0].iov_base = info ? const_cast<char*>(log_info) : const_cast<char*>(log_warning);
- iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
- iov[1].iov_base = str;
- iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
- iov[2].iov_len = denial_metadata.length();
- iov[3].iov_base = const_cast<char*>(newline);
- iov[3].iov_len = strlen(newline);
-
- writev(fdDmesg, iov, arraysize(iov));
- }
-
- if (!main && !events) {
- free(str);
- return 0;
- }
-
- log_time now(log_time::EPOCH);
-
- static const char audit_str[] = " audit(";
- char* timeptr = strstr(str, audit_str);
- if (timeptr && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
- (*cp == ':')) {
- memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
- memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
- } else {
- now = log_time(CLOCK_REALTIME);
- }
-
- // log to events
-
- size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
- if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
- auditParse(str, uid, &denial_metadata);
- str_len = (str_len + denial_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
- ? str_len + denial_metadata.length()
- : LOGGER_ENTRY_MAX_PAYLOAD;
- size_t message_len = str_len + sizeof(android_log_event_string_t);
-
- unsigned int notify = 0;
-
- if (events) { // begin scope for event buffer
- uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
-
- android_log_event_string_t* event =
- reinterpret_cast<android_log_event_string_t*>(buffer);
- event->header.tag = htole32(AUDITD_LOG_TAG);
- event->type = EVENT_TYPE_STRING;
- event->length = htole32(str_len);
- memcpy(event->data, str, str_len - denial_metadata.length());
- memcpy(event->data + str_len - denial_metadata.length(),
- denial_metadata.c_str(), denial_metadata.length());
-
- rc = logbuf->Log(LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
- (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
- if (rc >= 0) {
- notify |= 1 << LOG_ID_EVENTS;
- }
- // end scope for event buffer
- }
-
- // log to main
-
- static const char comm_str[] = " comm=\"";
- const char* comm = strstr(str, comm_str);
- const char* estr = str + strlen(str);
- const char* commfree = nullptr;
- if (comm) {
- estr = comm;
- comm += sizeof(comm_str) - 1;
- } else if (pid == getpid()) {
- pid = tid;
- comm = "auditd";
- } else {
- comm = commfree = stats_->PidToName(pid);
- if (!comm) {
- comm = "unknown";
- }
- }
-
- const char* ecomm = strchr(comm, '"');
- if (ecomm) {
- ++ecomm;
- str_len = ecomm - comm;
- } else {
- str_len = strlen(comm) + 1;
- ecomm = "";
- }
- size_t prefix_len = estr - str;
- if (prefix_len > LOGGER_ENTRY_MAX_PAYLOAD) {
- prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
- message_len =
- str_len + prefix_len + suffix_len + denial_metadata.length() + 2;
-
- if (main) { // begin scope for main buffer
- char newstr[message_len];
-
- *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
- strlcpy(newstr + 1, comm, str_len);
- strncpy(newstr + 1 + str_len, str, prefix_len);
- strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
- strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
- denial_metadata.c_str(), denial_metadata.length());
-
- rc = logbuf->Log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
- (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
-
- if (rc >= 0) {
- notify |= 1 << LOG_ID_MAIN;
- }
- // end scope for main buffer
- }
-
- free(const_cast<char*>(commfree));
- free(str);
-
- if (notify) {
- if (rc < 0) {
- rc = message_len;
- }
- }
-
- return rc;
-}
-
-int LogAudit::log(char* buf, size_t len) {
- char* audit = strstr(buf, " audit(");
- if (!audit || (audit >= &buf[len])) {
- return 0;
- }
-
- *audit = '\0';
-
- int rc;
- char* type = strstr(buf, "type=");
- if (type && (type < &buf[len])) {
- rc = logPrint("%s %s", type, audit + 1);
- } else {
- rc = logPrint("%s", audit + 1);
- }
- *audit = ' ';
- return rc;
-}
-
-int LogAudit::getLogSocket() {
- int fd = audit_open();
- if (fd < 0) {
- return fd;
- }
- if (audit_setup(fd, getpid()) < 0) {
- audit_close(fd);
- fd = -1;
- }
- return fd;
-}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
deleted file mode 100644
index 181920e..0000000
--- a/logd/LogAudit.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2014 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 <map>
-
-#include <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogStatistics.h"
-
-class LogAudit : public SocketListener {
- LogBuffer* logbuf;
- int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
- bool main;
- bool events;
- bool initialized;
-
- public:
- LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats);
- int log(char* buf, size_t len);
-
- protected:
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- static int getLogSocket();
- std::map<std::string, std::string> populateDenialMap();
- std::string denialParse(const std::string& denial, char terminator,
- const std::string& search_term);
- void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
- int logPrint(const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3)));
-
- LogStatistics* stats_;
-};
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
deleted file mode 100644
index 8d58523..0000000
--- a/logd/LogBuffer.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 <sys/types.h>
-
-#include <functional>
-#include <memory>
-
-#include <android-base/thread_annotations.h>
-#include <log/log.h>
-#include <log/log_read.h>
-
-#include "LogWriter.h"
-#include "LogdLock.h"
-
-// A mask to represent which log buffers a reader is watching, values are (1 << LOG_ID_MAIN), etc.
-using LogMask = uint32_t;
-constexpr uint32_t kLogMaskAll = 0xFFFFFFFF;
-
-// State that a LogBuffer may want to persist across calls to FlushTo().
-class FlushToState {
- public:
- FlushToState(uint64_t start, LogMask log_mask) : start_(start), log_mask_(log_mask) {}
- virtual ~FlushToState() {}
-
- uint64_t start() const { return start_; }
- void set_start(uint64_t start) { start_ = start; }
-
- LogMask log_mask() const { return log_mask_; }
-
- private:
- uint64_t start_;
- LogMask log_mask_;
-};
-
-// Enum for the return values of the `filter` function passed to FlushTo().
-enum class FilterResult {
- kSkip,
- kStop,
- kWrite,
-};
-
-class LogBuffer {
- public:
- virtual ~LogBuffer() {}
-
- virtual void Init() = 0;
-
- virtual 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) = 0;
-
- virtual std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask)
- REQUIRES(logd_lock) = 0;
- virtual bool FlushTo(
- LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) REQUIRES(logd_lock) = 0;
-
- virtual bool Clear(log_id_t id, uid_t uid) = 0;
- virtual size_t GetSize(log_id_t id) = 0;
- virtual bool SetSize(log_id_t id, size_t size) = 0;
-
- virtual uint64_t sequence() const = 0;
-};
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
deleted file mode 100644
index 26affa8..0000000
--- a/logd/LogBufferElement.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "LogBufferElement.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-#include "LogStatistics.h"
-#include "LogUtils.h"
-
-LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
- pid_t tid, uint64_t sequence, const char* msg, uint16_t len)
- : uid_(uid),
- pid_(pid),
- tid_(tid),
- sequence_(sequence),
- realtime_(realtime),
- msg_len_(len),
- log_id_(log_id),
- dropped_(false) {
- msg_ = new char[len];
- memcpy(msg_, msg, len);
-}
-
-LogBufferElement::LogBufferElement(const LogBufferElement& elem)
- : uid_(elem.uid_),
- pid_(elem.pid_),
- tid_(elem.tid_),
- sequence_(elem.sequence_),
- realtime_(elem.realtime_),
- msg_len_(elem.msg_len_),
- log_id_(elem.log_id_),
- dropped_(elem.dropped_) {
- if (dropped_) {
- tag_ = elem.GetTag();
- } else {
- msg_ = new char[msg_len_];
- memcpy(msg_, elem.msg_, msg_len_);
- }
-}
-
-LogBufferElement::LogBufferElement(LogBufferElement&& elem) noexcept
- : uid_(elem.uid_),
- pid_(elem.pid_),
- tid_(elem.tid_),
- sequence_(elem.sequence_),
- realtime_(elem.realtime_),
- msg_len_(elem.msg_len_),
- log_id_(elem.log_id_),
- dropped_(elem.dropped_) {
- if (dropped_) {
- tag_ = elem.GetTag();
- } else {
- msg_ = elem.msg_;
- elem.msg_ = nullptr;
- }
-}
-
-LogBufferElement::~LogBufferElement() {
- if (!dropped_) {
- delete[] msg_;
- }
-}
-
-uint32_t LogBufferElement::GetTag() const {
- // Binary buffers have no tag.
- if (!IsBinary(log_id())) {
- return 0;
- }
-
- // Dropped messages store the tag in place of msg_.
- if (dropped_) {
- return tag_;
- }
-
- return MsgToTag(msg(), msg_len());
-}
-
-LogStatisticsElement LogBufferElement::ToLogStatisticsElement() const {
- // Estimate the size of this element in the parent std::list<> by adding two void*'s
- // corresponding to the next/prev pointers and aligning to 64 bit.
- uint16_t element_in_list_size =
- (sizeof(*this) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) & -sizeof(uint64_t);
- return LogStatisticsElement{
- .uid = uid(),
- .pid = pid(),
- .tid = tid(),
- .tag = GetTag(),
- .realtime = realtime(),
- .msg = msg(),
- .msg_len = msg_len(),
- .dropped_count = dropped_count(),
- .log_id = log_id(),
- .total_len = static_cast<uint16_t>(element_in_list_size + msg_len()),
- };
-}
-
-uint16_t LogBufferElement::SetDropped(uint16_t value) {
- if (dropped_) {
- return dropped_count_ = value;
- }
-
- // The tag information is saved in msg_ data, which is in a union with tag_, used after dropped_
- // is set to true. Therefore we save the tag value aside, delete msg_, then set tag_ to the tag
- // value in its place.
- auto old_tag = GetTag();
- delete[] msg_;
- msg_ = nullptr;
-
- tag_ = old_tag;
- dropped_ = true;
- return dropped_count_ = value;
-}
-
-// caller must own and free character string
-char* android::tidToName(pid_t tid) {
- char* retval = nullptr;
- char buffer[256];
- snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
- int fd = open(buffer, O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- ssize_t ret = read(fd, buffer, sizeof(buffer));
- if (ret >= (ssize_t)sizeof(buffer)) {
- ret = sizeof(buffer) - 1;
- }
- while ((ret > 0) && isspace(buffer[ret - 1])) {
- --ret;
- }
- if (ret > 0) {
- buffer[ret] = '\0';
- retval = strdup(buffer);
- }
- close(fd);
- }
-
- // if nothing for comm, check out cmdline
- char* name = android::pidToName(tid);
- if (!retval) {
- retval = name;
- name = nullptr;
- }
-
- // check if comm is truncated, see if cmdline has full representation
- if (name) {
- // impossible for retval to be NULL if name not NULL
- size_t retval_len = strlen(retval);
- size_t name_len = strlen(name);
- // KISS: ToDo: Only checks prefix truncated, not suffix, or both
- if ((retval_len < name_len) &&
- !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
- free(retval);
- retval = name;
- } else {
- free(name);
- }
- }
- return retval;
-}
-
-// assumption: msg_ == NULL
-size_t LogBufferElement::PopulateDroppedMessage(char*& buffer, LogStatistics* stats,
- bool lastSame) {
- static const char tag[] = "chatty";
-
- if (!__android_log_is_loggable_len(ANDROID_LOG_INFO, tag, strlen(tag),
- ANDROID_LOG_VERBOSE)) {
- return 0;
- }
-
- static const char format_uid[] = "uid=%u%s%s %s %u line%s";
- const char* name = stats->UidToName(uid_);
- const char* commName = android::tidToName(tid_);
- if (!commName && (tid_ != pid_)) {
- commName = android::tidToName(pid_);
- }
- if (!commName) {
- commName = stats->PidToName(pid_);
- }
- if (name && name[0] && commName && (name[0] == commName[0])) {
- size_t len = strlen(name + 1);
- if (!strncmp(name + 1, commName + 1, len)) {
- if (commName[len + 1] == '\0') {
- free(const_cast<char*>(commName));
- commName = nullptr;
- } else {
- free(const_cast<char*>(name));
- name = nullptr;
- }
- }
- }
- if (name) {
- char* buf = nullptr;
- int result = asprintf(&buf, "(%s)", name);
- if (result != -1) {
- free(const_cast<char*>(name));
- name = buf;
- }
- }
- if (commName) {
- char* buf = nullptr;
- int result = asprintf(&buf, " %s", commName);
- if (result != -1) {
- free(const_cast<char*>(commName));
- commName = buf;
- }
- }
- // identical to below to calculate the buffer size required
- const char* type = lastSame ? "identical" : "expire";
- size_t len = snprintf(nullptr, 0, format_uid, uid_, name ? name : "", commName ? commName : "",
- type, dropped_count(), (dropped_count() > 1) ? "s" : "");
-
- size_t hdrLen;
- if (IsBinary(log_id())) {
- hdrLen = sizeof(android_log_event_string_t);
- } else {
- hdrLen = 1 + sizeof(tag);
- }
-
- buffer = static_cast<char*>(calloc(1, hdrLen + len + 1));
- if (!buffer) {
- free(const_cast<char*>(name));
- free(const_cast<char*>(commName));
- return 0;
- }
-
- size_t retval = hdrLen + len;
- if (IsBinary(log_id())) {
- android_log_event_string_t* event =
- reinterpret_cast<android_log_event_string_t*>(buffer);
-
- event->header.tag = htole32(CHATTY_LOG_TAG);
- event->type = EVENT_TYPE_STRING;
- event->length = htole32(len);
- } else {
- ++retval;
- buffer[0] = ANDROID_LOG_INFO;
- strcpy(buffer + 1, tag);
- }
-
- snprintf(buffer + hdrLen, len + 1, format_uid, uid_, name ? name : "", commName ? commName : "",
- type, dropped_count(), (dropped_count() > 1) ? "s" : "");
- free(const_cast<char*>(name));
- free(const_cast<char*>(commName));
-
- return retval;
-}
-
-bool LogBufferElement::FlushTo(LogWriter* writer, LogStatistics* stats, bool lastSame) {
- struct logger_entry entry = {};
-
- entry.hdr_size = sizeof(struct logger_entry);
- entry.lid = log_id_;
- entry.pid = pid_;
- entry.tid = tid_;
- entry.uid = uid_;
- entry.sec = realtime_.tv_sec;
- entry.nsec = realtime_.tv_nsec;
-
- char* buffer = nullptr;
- const char* msg;
- if (dropped_) {
- entry.len = PopulateDroppedMessage(buffer, stats, lastSame);
- if (!entry.len) return true;
- msg = buffer;
- } else {
- msg = msg_;
- entry.len = msg_len_;
- }
-
- bool retval = writer->Write(entry, msg);
-
- if (buffer) free(buffer);
-
- return retval;
-}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
deleted file mode 100644
index b263ca5..0000000
--- a/logd/LogBufferElement.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "LogWriter.h"
-
-#include "LogStatistics.h"
-
-#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
- // non-chatty UIDs less than this age in hours
-#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
- // chatty for the temporal expire messages
-#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
-
-class __attribute__((packed)) LogBufferElement {
- public:
- LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- uint64_t sequence, const char* msg, uint16_t len);
- LogBufferElement(const LogBufferElement& elem);
- LogBufferElement(LogBufferElement&& elem) noexcept;
- ~LogBufferElement();
-
- uint32_t GetTag() const;
- uint16_t SetDropped(uint16_t value);
-
- bool FlushTo(LogWriter* writer, LogStatistics* parent, bool lastSame);
-
- LogStatisticsElement ToLogStatisticsElement() const;
-
- log_id_t log_id() const { return static_cast<log_id_t>(log_id_); }
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
- pid_t tid() const { return tid_; }
- uint16_t msg_len() const { return dropped_ ? 0 : msg_len_; }
- const char* msg() const { return dropped_ ? nullptr : msg_; }
- uint64_t sequence() const { return sequence_; }
- log_time realtime() const { return realtime_; }
- uint16_t dropped_count() const { return dropped_ ? dropped_count_ : 0; }
-
- private:
- // assumption: mDropped == true
- size_t PopulateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame);
-
- // sized to match reality of incoming log packets
- const uint32_t uid_;
- const uint32_t pid_;
- const uint32_t tid_;
- uint64_t sequence_;
- log_time realtime_;
- union {
- char* msg_; // mDropped == false
- int32_t tag_; // mDropped == true
- };
- union {
- const uint16_t msg_len_; // mDropped == false
- uint16_t dropped_count_; // mDropped == true
- };
- const uint8_t log_id_;
- bool dropped_;
-};
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
deleted file mode 100644
index cb9f428..0000000
--- a/logd/LogBufferTest.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * 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 "LogBufferTest.h"
-
-#include <unistd.h>
-
-#include <limits>
-#include <memory>
-#include <regex>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "LogBuffer.h"
-#include "LogReaderThread.h"
-#include "LogWriter.h"
-
-using android::base::Join;
-using android::base::Split;
-using android::base::StringPrintf;
-
-char* android::uidToName(uid_t) {
- return nullptr;
-}
-
-static std::vector<std::string> CompareLoggerEntries(const logger_entry& expected,
- const logger_entry& result, bool ignore_len) {
- std::vector<std::string> errors;
- if (!ignore_len && expected.len != result.len) {
- errors.emplace_back(
- StringPrintf("len: expected %" PRIu16 " vs %" PRIu16, expected.len, result.len));
- }
- if (expected.hdr_size != result.hdr_size) {
- errors.emplace_back(StringPrintf("hdr_size: %" PRIu16 " vs %" PRIu16, expected.hdr_size,
- result.hdr_size));
- }
- if (expected.pid != result.pid) {
- errors.emplace_back(
- StringPrintf("pid: expected %" PRIi32 " vs %" PRIi32, expected.pid, result.pid));
- }
- if (expected.tid != result.tid) {
- errors.emplace_back(
- StringPrintf("tid: expected %" PRIu32 " vs %" PRIu32, expected.tid, result.tid));
- }
- if (expected.sec != result.sec) {
- errors.emplace_back(
- StringPrintf("sec: expected %" PRIu32 " vs %" PRIu32, expected.sec, result.sec));
- }
- if (expected.nsec != result.nsec) {
- errors.emplace_back(
- StringPrintf("nsec: expected %" PRIu32 " vs %" PRIu32, expected.nsec, result.nsec));
- }
- if (expected.lid != result.lid) {
- errors.emplace_back(
- StringPrintf("lid: expected %" PRIu32 " vs %" PRIu32, expected.lid, result.lid));
- }
- if (expected.uid != result.uid) {
- errors.emplace_back(
- StringPrintf("uid: expected %" PRIu32 " vs %" PRIu32, expected.uid, result.uid));
- }
- return errors;
-}
-
-static std::string MakePrintable(std::string in) {
- if (in.size() > 80) {
- in = in.substr(0, 80) + "...";
- }
- std::string result;
- for (const char c : in) {
- if (isprint(c)) {
- result.push_back(c);
- } else {
- result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
- }
- }
- return result;
-}
-
-static std::string CompareMessages(const std::string& expected, const std::string& result) {
- if (expected == result) {
- return {};
- }
- size_t diff_index = 0;
- for (; diff_index < std::min(expected.size(), result.size()); ++diff_index) {
- if (expected[diff_index] != result[diff_index]) {
- break;
- }
- }
-
- if (diff_index < 80) {
- auto expected_short = MakePrintable(expected);
- auto result_short = MakePrintable(result);
- return StringPrintf("msg: expected '%s' vs '%s'", expected_short.c_str(),
- result_short.c_str());
- }
-
- auto expected_short = MakePrintable(expected.substr(diff_index));
- auto result_short = MakePrintable(result.substr(diff_index));
- return StringPrintf("msg: index %zu: expected '%s' vs '%s'", diff_index, expected_short.c_str(),
- result_short.c_str());
-}
-
-static std::string CompareRegexMessages(const std::string& expected, const std::string& result) {
- auto expected_pieces = Split(expected, std::string("\0", 1));
- auto result_pieces = Split(result, std::string("\0", 1));
-
- if (expected_pieces.size() != 3 || result_pieces.size() != 3) {
- return StringPrintf(
- "msg: should have 3 null delimited strings found %d in expected, %d in result: "
- "'%s' vs '%s'",
- static_cast<int>(expected_pieces.size()), static_cast<int>(result_pieces.size()),
- MakePrintable(expected).c_str(), MakePrintable(result).c_str());
- }
- if (expected_pieces[0] != result_pieces[0]) {
- return StringPrintf("msg: tag/priority mismatch expected '%s' vs '%s'",
- MakePrintable(expected_pieces[0]).c_str(),
- MakePrintable(result_pieces[0]).c_str());
- }
- std::regex expected_tag_regex(expected_pieces[1]);
- if (!std::regex_search(result_pieces[1], expected_tag_regex)) {
- return StringPrintf("msg: message regex mismatch expected '%s' vs '%s'",
- MakePrintable(expected_pieces[1]).c_str(),
- MakePrintable(result_pieces[1]).c_str());
- }
- if (expected_pieces[2] != result_pieces[2]) {
- return StringPrintf("msg: nothing expected after final null character '%s' vs '%s'",
- MakePrintable(expected_pieces[2]).c_str(),
- MakePrintable(result_pieces[2]).c_str());
- }
- return {};
-}
-
-void CompareLogMessages(const std::vector<LogMessage>& expected,
- const std::vector<LogMessage>& result) {
- EXPECT_EQ(expected.size(), result.size());
- size_t end = std::min(expected.size(), result.size());
- size_t num_errors = 0;
- for (size_t i = 0; i < end; ++i) {
- auto errors =
- CompareLoggerEntries(expected[i].entry, result[i].entry, expected[i].regex_compare);
- auto msg_error = expected[i].regex_compare
- ? CompareRegexMessages(expected[i].message, result[i].message)
- : CompareMessages(expected[i].message, result[i].message);
- if (!msg_error.empty()) {
- errors.emplace_back(msg_error);
- }
- if (!errors.empty()) {
- GTEST_LOG_(ERROR) << "Mismatch log message " << i << "\n" << Join(errors, "\n");
- ++num_errors;
- }
- }
- EXPECT_EQ(0U, num_errors);
-}
-
-void FixupMessages(std::vector<LogMessage>* messages) {
- for (auto& [entry, message, _] : *messages) {
- entry.hdr_size = sizeof(logger_entry);
- entry.len = message.size();
- }
-}
-
-TEST_P(LogBufferTest, smoke) {
- std::vector<LogMessage> log_messages = {
- {{
- .pid = 1,
- .tid = 1,
- .sec = 1234,
- .nsec = 323001,
- .lid = LOG_ID_MAIN,
- .uid = 0,
- },
- "smoke test"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state =
- log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- EXPECT_EQ(2ULL, flush_to_state->start());
- }
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, smoke_with_reader_thread) {
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_KERNEL, .uid = 0},
- "third"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20004, .lid = LOG_ID_MAIN, .uid = 0},
- "fourth"},
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20005, .lid = LOG_ID_RADIO, .uid = 0},
- "fifth"},
- {{.pid = 2, .tid = 2, .sec = 10000, .nsec = 20006, .lid = LOG_ID_RADIO, .uid = 0},
- "sixth"},
- {{.pid = 3, .tid = 2, .sec = 10000, .nsec = 20007, .lid = LOG_ID_RADIO, .uid = 0},
- "seventh"},
- {{.pid = 4, .tid = 2, .sec = 10000, .nsec = 20008, .lid = LOG_ID_MAIN, .uid = 0},
- "eighth"},
- {{.pid = 5, .tid = 2, .sec = 10000, .nsec = 20009, .lid = LOG_ID_CRASH, .uid = 0},
- "nineth"},
- {{.pid = 6, .tid = 2, .sec = 10000, .nsec = 20011, .lid = LOG_ID_MAIN, .uid = 0},
- "tenth"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::lock_guard{logd_lock};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-// Generate random messages, set the 'sec' parameter explicit though, to be able to track the
-// expected order of messages.
-LogMessage GenerateRandomLogMessage(uint32_t sec) {
- auto rand_uint32 = [](int max) -> uint32_t { return rand() % max; };
- logger_entry entry = {
- .hdr_size = sizeof(logger_entry),
- .pid = rand() % 5000,
- .tid = rand_uint32(5000),
- .sec = sec,
- .nsec = rand_uint32(NS_PER_SEC),
- .lid = rand_uint32(LOG_ID_STATS),
- .uid = rand_uint32(100000),
- };
-
- // See comment in ChattyLogBuffer::Log() for why this is disallowed.
- if (entry.nsec % 1000 == 0) {
- ++entry.nsec;
- }
-
- if (entry.lid == LOG_ID_EVENTS) {
- entry.lid = LOG_ID_KERNEL;
- }
-
- std::string message;
- char priority = ANDROID_LOG_INFO + rand() % 2;
- message.push_back(priority);
-
- int tag_length = 2 + rand() % 10;
- for (int i = 0; i < tag_length; ++i) {
- message.push_back('a' + rand() % 26);
- }
- message.push_back('\0');
-
- int msg_length = 2 + rand() % 1000;
- for (int i = 0; i < msg_length; ++i) {
- message.push_back('a' + rand() % 26);
- }
- message.push_back('\0');
-
- entry.len = message.size();
-
- return {entry, message};
-}
-
-TEST_P(LogBufferTest, random_messages) {
- srand(1);
- std::vector<LogMessage> log_messages;
- for (size_t i = 0; i < 1000; ++i) {
- log_messages.emplace_back(GenerateRandomLogMessage(i));
- }
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::lock_guard{logd_lock};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, read_last_sequence) {
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "third"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 3, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::lock_guard{logd_lock};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- std::vector<LogMessage> expected_log_messages = {log_messages.back()};
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, clear_logs) {
- // Log 3 initial logs.
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "third"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- // Connect a blocking reader.
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- // Wait up to 250ms for the reader to read the first 3 logs.
- constexpr int kMaxRetryCount = 50;
- int count = 0;
- for (; count < kMaxRetryCount; ++count) {
- usleep(5000);
- auto lock = std::lock_guard{logd_lock};
- if (reader_list_.reader_threads().back()->start() == 4) {
- break;
- }
- }
- ASSERT_LT(count, kMaxRetryCount);
-
- // Clear the log buffer.
- log_buffer_->Clear(LOG_ID_MAIN, 0);
-
- // Log 3 more logs.
- std::vector<LogMessage> after_clear_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "4th"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "5th"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "6th"},
- };
- FixupMessages(&after_clear_messages);
- LogMessages(after_clear_messages);
-
- // Wait up to 250ms for the reader to read the 3 additional logs.
- for (count = 0; count < kMaxRetryCount; ++count) {
- usleep(5000);
- auto lock = std::lock_guard{logd_lock};
- if (reader_list_.reader_threads().back()->start() == 7) {
- break;
- }
- }
- ASSERT_LT(count, kMaxRetryCount);
-
- // Release the reader, wait for it to get the signal then check that it has been deleted.
- {
- auto lock = std::lock_guard{logd_lock};
- reader_list_.reader_threads().back()->Release();
- }
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::lock_guard{logd_lock};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
-
- // Check that we have read all 6 messages.
- std::vector<LogMessage> expected_log_messages = log_messages;
- expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(),
- after_clear_messages.end());
- CompareLogMessages(expected_log_messages, read_log_messages);
-
- // Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer.
- std::vector<LogMessage> read_log_messages_after_clear;
- {
- auto lock = std::lock_guard{logd_lock};
- std::unique_ptr<LogWriter> test_writer(
- new TestWriter(&read_log_messages_after_clear, nullptr));
- std::unique_ptr<FlushToState> flush_to_state =
- log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- EXPECT_EQ(7ULL, flush_to_state->start());
- }
- CompareLogMessages(after_clear_messages, read_log_messages_after_clear);
-}
-
-INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest,
- testing::Values("chatty", "serialized", "simple"));
diff --git a/logd/LogBufferTest.h b/logd/LogBufferTest.h
deleted file mode 100644
index eeeb980..0000000
--- a/logd/LogBufferTest.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "ChattyLogBuffer.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "PruneList.h"
-#include "SerializedLogBuffer.h"
-#include "SimpleLogBuffer.h"
-
-struct LogMessage {
- logger_entry entry;
- std::string message;
- bool regex_compare = false; // Only set for expected messages, when true 'message' should be
- // interpretted as a regex.
-};
-
-// Compares the ordered list of expected and result, causing a test failure with appropriate
-// information on failure.
-void CompareLogMessages(const std::vector<LogMessage>& expected,
- const std::vector<LogMessage>& result);
-// Sets hdr_size and len parameters appropriately.
-void FixupMessages(std::vector<LogMessage>* messages);
-
-class TestWriter : public LogWriter {
- public:
- TestWriter(std::vector<LogMessage>* msgs, bool* released)
- : LogWriter(0, true), msgs_(msgs), released_(released) {}
- bool Write(const logger_entry& entry, const char* message) override {
- msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false});
- return true;
- }
-
- void Release() {
- if (released_) *released_ = true;
- }
-
- std::string name() const override { return "test_writer"; }
-
- private:
- std::vector<LogMessage>* msgs_;
- bool* released_;
-};
-
-class LogBufferTest : public testing::TestWithParam<std::string> {
- protected:
- void SetUp() override {
- if (GetParam() == "chatty") {
- log_buffer_.reset(new ChattyLogBuffer(&reader_list_, &tags_, &prune_, &stats_));
- } else if (GetParam() == "serialized") {
- log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_));
- } else if (GetParam() == "simple") {
- log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_));
- } else {
- FAIL() << "Unknown buffer type selected for test";
- }
-
- log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); }
- }
-
- void LogMessages(const std::vector<LogMessage>& messages) {
- for (auto& [entry, message, _] : messages) {
- log_buffer_->Log(static_cast<log_id_t>(entry.lid), log_time(entry.sec, entry.nsec),
- entry.uid, entry.pid, entry.tid, message.c_str(), message.size());
- }
- }
-
- LogReaderList reader_list_;
- LogTags tags_;
- PruneList prune_;
- LogStatistics stats_{false, true};
- std::unique_ptr<LogBuffer> log_buffer_;
-};
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
deleted file mode 100644
index d6c7d25..0000000
--- a/logd/LogKlog.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogKlog.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/uio.h>
-#include <syslog.h>
-
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-
-#define KMSG_PRIORITY(PRI) \
- '<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
-
-static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
-
-// List of the _only_ needles we supply here to android::strnstr
-static const char suspendStr[] = "PM: suspend entry ";
-static const char resumeStr[] = "PM: suspend exit ";
-static const char suspendedStr[] = "Suspended for ";
-static const char healthdStr[] = "healthd";
-static const char batteryStr[] = ": battery ";
-static const char auditStr[] = " audit(";
-static const char klogdStr[] = "logd.klogd: ";
-
-// Parsing is hard
-
-// called if we see a '<', s is the next character, returns pointer after '>'
-static char* is_prio(char* s, ssize_t len) {
- if ((len <= 0) || !isdigit(*s++)) return nullptr;
- --len;
- static const size_t max_prio_len = (len < 4) ? len : 4;
- size_t priolen = 0;
- char c;
- while (((c = *s++)) && (++priolen <= max_prio_len)) {
- if (!isdigit(c)) return ((c == '>') && (*s == '[')) ? s : nullptr;
- }
- return nullptr;
-}
-
-// called if we see a '[', s is the next character, returns pointer after ']'
-static char* is_timestamp(char* s, ssize_t len) {
- while ((len > 0) && (*s == ' ')) {
- ++s;
- --len;
- }
- if ((len <= 0) || !isdigit(*s++)) return nullptr;
- --len;
- bool first_period = true;
- char c;
- while ((len > 0) && ((c = *s++))) {
- --len;
- if ((c == '.') && first_period) {
- first_period = false;
- } else if (!isdigit(c)) {
- return ((c == ']') && !first_period && (*s == ' ')) ? s : nullptr;
- }
- }
- return nullptr;
-}
-
-// Like strtok_r with "\r\n" except that we look for log signatures (regex)
-// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
-// *[0-9]+[.][0-9]+[]] \)
-// and split if we see a second one without a newline.
-// We allow nuls in content, monitoring the overall length and sub-length of
-// the discovered tokens.
-
-#define SIGNATURE_MASK 0xF0
-// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
-#define LESS_THAN_SIG SIGNATURE_MASK
-#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
-// space is one more than <digit> of 9
-#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
-
-char* android::log_strntok_r(char* s, ssize_t& len, char*& last,
- ssize_t& sublen) {
- sublen = 0;
- if (len <= 0) return nullptr;
- if (!s) {
- if (!(s = last)) return nullptr;
- // fixup for log signature split <,
- // LESS_THAN_SIG + <digit>
- if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
- *s = (*s & ~SIGNATURE_MASK) + '0';
- *--s = '<';
- ++len;
- }
- // fixup for log signature split [,
- // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
- if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
- *s = (*s == OPEN_BRACKET_SPACE) ? ' ' : (*s & ~SIGNATURE_MASK) + '0';
- *--s = '[';
- ++len;
- }
- }
-
- while ((len > 0) && ((*s == '\r') || (*s == '\n'))) {
- ++s;
- --len;
- }
-
- if (len <= 0) return last = nullptr;
- char *peek, *tok = s;
-
- for (;;) {
- if (len <= 0) {
- last = nullptr;
- return tok;
- }
- char c = *s++;
- --len;
- ssize_t adjust;
- switch (c) {
- case '\r':
- case '\n':
- s[-1] = '\0';
- last = s;
- return tok;
-
- case '<':
- peek = is_prio(s, len);
- if (!peek) break;
- if (s != (tok + 1)) { // not first?
- s[-1] = '\0';
- *s &= ~SIGNATURE_MASK;
- *s |= LESS_THAN_SIG; // signature for '<'
- last = s;
- return tok;
- }
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- if ((*s == '[') && ((peek = is_timestamp(s + 1, len - 1)))) {
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- }
- break;
-
- case '[':
- peek = is_timestamp(s, len);
- if (!peek) break;
- if (s != (tok + 1)) { // not first?
- s[-1] = '\0';
- if (*s == ' ') {
- *s = OPEN_BRACKET_SPACE;
- } else {
- *s &= ~SIGNATURE_MASK;
- *s |= OPEN_BRACKET_SIG; // signature for '['
- }
- last = s;
- return tok;
- }
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- break;
- }
- ++sublen;
- }
- // NOTREACHED
-}
-
-log_time LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTONIC))
- ? log_time(log_time::EPOCH)
- : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
-
-LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
- : SocketListener(fdRead, false),
- logbuf(buf),
- signature(CLOCK_MONOTONIC),
- initialized(false),
- enableLogging(true),
- auditd(auditd),
- stats_(stats) {
- static const char klogd_message[] = "%s%s%" PRIu64 "\n";
- char buffer[strlen(priority_message) + strlen(klogdStr) +
- strlen(klogd_message) + 20];
- snprintf(buffer, sizeof(buffer), klogd_message, priority_message, klogdStr,
- signature.nsec());
- write(fdWrite, buffer, strlen(buffer));
-}
-
-bool LogKlog::onDataAvailable(SocketClient* cli) {
- if (!initialized) {
- prctl(PR_SET_NAME, "logd.klogd");
- initialized = true;
- enableLogging = false;
- }
-
- char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
- ssize_t len = 0;
-
- for (;;) {
- ssize_t retval = 0;
- if (len < (ssize_t)(sizeof(buffer) - 1)) {
- retval =
- read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
- }
- if ((retval == 0) && (len <= 0)) {
- break;
- }
- if (retval < 0) {
- return false;
- }
- len += retval;
- bool full = len == (sizeof(buffer) - 1);
- char* ep = buffer + len;
- *ep = '\0';
- ssize_t sublen;
- for (char *ptr = nullptr, *tok = buffer;
- !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
- tok = nullptr) {
- if (((tok + sublen) >= ep) && (retval != 0) && full) {
- if (sublen > 0) memmove(buffer, tok, sublen);
- len = sublen;
- break;
- }
- if ((sublen > 0) && *tok) {
- log(tok, sublen);
- }
- }
- }
-
- return true;
-}
-
-void LogKlog::calculateCorrection(const log_time& monotonic,
- const char* real_string, ssize_t len) {
- static const char real_format[] = "%Y-%m-%d %H:%M:%S.%09q UTC";
- if (len < (ssize_t)(strlen(real_format) + 5)) return;
-
- log_time real(log_time::EPOCH);
- const char* ep = real.strptime(real_string, real_format);
- if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
- return;
- }
- // kernel report UTC, log_time::strptime is localtime from calendar.
- // Bionic and liblog strptime does not support %z or %Z to pick up
- // timezone so we are calculating our own correction.
- time_t now = real.tv_sec;
- struct tm tm;
- memset(&tm, 0, sizeof(tm));
- tm.tm_isdst = -1;
- localtime_r(&now, &tm);
- if ((tm.tm_gmtoff < 0) && ((-tm.tm_gmtoff) > (long)real.tv_sec)) {
- real = log_time(log_time::EPOCH);
- } else {
- real.tv_sec += tm.tm_gmtoff;
- }
- if (monotonic > real) {
- correction = log_time(log_time::EPOCH);
- } else {
- correction = real - monotonic;
- }
-}
-
-log_time LogKlog::sniffTime(const char*& buf, ssize_t len, bool reverse) {
- log_time now(log_time::EPOCH);
- if (len <= 0) return now;
-
- const char* cp = nullptr;
- if ((len > 10) && (*buf == '[')) {
- cp = now.strptime(buf, "[ %s.%q]"); // can index beyond buffer bounds
- if (cp && (cp > &buf[len - 1])) cp = nullptr;
- }
- if (cp) {
- len -= cp - buf;
- if ((len > 0) && isspace(*cp)) {
- ++cp;
- --len;
- }
- buf = cp;
-
- const char* b;
- if (((b = android::strnstr(cp, len, suspendStr))) &&
- (((b += strlen(suspendStr)) - cp) < len)) {
- len -= b - cp;
- calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, resumeStr))) &&
- (((b += strlen(resumeStr)) - cp) < len)) {
- len -= b - cp;
- calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, healthdStr))) &&
- (((b += strlen(healthdStr)) - cp) < len) &&
- ((b = android::strnstr(b, len -= b - cp, batteryStr))) &&
- (((b += strlen(batteryStr)) - cp) < len)) {
- // NB: healthd is roughly 150us late, so we use it instead to
- // trigger a check for ntp-induced or hardware clock drift.
- log_time real(CLOCK_REALTIME);
- log_time mono(CLOCK_MONOTONIC);
- correction = (real < mono) ? log_time(log_time::EPOCH) : (real - mono);
- } else if (((b = android::strnstr(cp, len, suspendedStr))) &&
- (((b += strlen(suspendStr)) - cp) < len)) {
- len -= b - cp;
- log_time real(log_time::EPOCH);
- char* endp;
- real.tv_sec = strtol(b, &endp, 10);
- if ((*endp == '.') && ((endp - b) < len)) {
- unsigned long multiplier = NS_PER_SEC;
- real.tv_nsec = 0;
- len -= endp - b;
- while (--len && isdigit(*++endp) && (multiplier /= 10)) {
- real.tv_nsec += (*endp - '0') * multiplier;
- }
- if (reverse) {
- if (real > correction) {
- correction = log_time(log_time::EPOCH);
- } else {
- correction -= real;
- }
- } else {
- correction += real;
- }
- }
- }
-
- convertMonotonicToReal(now);
- } else {
- now = log_time(CLOCK_REALTIME);
- }
- return now;
-}
-
-pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) {
- if (len <= 0) return 0;
-
- const char* cp = buf;
- // sscanf does a strlen, let's check if the string is not nul terminated.
- // pseudo out-of-bounds access since we always have an extra char on buffer.
- if (((ssize_t)strnlen(cp, len) == len) && cp[len]) {
- return 0;
- }
- // HTC kernels with modified printk "c0 1648 "
- if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
- (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
- bool gotDigit = false;
- int i;
- for (i = 4; i < 9; ++i) {
- if (isdigit(cp[i])) {
- gotDigit = true;
- } else if (gotDigit || (cp[i] != ' ')) {
- break;
- }
- }
- if ((i == 9) && (cp[i] == ' ')) {
- int pid = 0;
- char placeholder;
- if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) {
- buf = cp + 10; // skip-it-all
- return pid;
- }
- }
- }
- while (len) {
- // Mediatek kernels with modified printk
- if (*cp == '[') {
- int pid = 0;
- char placeholder;
- if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) {
- return pid;
- }
- break; // Only the first one
- }
- ++cp;
- --len;
- }
- return 0;
-}
-
-// kernel log prefix, convert to a kernel log priority number
-static int parseKernelPrio(const char*& buf, ssize_t len) {
- int pri = LOG_USER | LOG_INFO;
- const char* cp = buf;
- if ((len > 0) && (*cp == '<')) {
- pri = 0;
- while (--len && isdigit(*++cp)) {
- pri = (pri * 10) + *cp - '0';
- }
- if ((len > 0) && (*cp == '>')) {
- ++cp;
- } else {
- cp = buf;
- pri = LOG_USER | LOG_INFO;
- }
- buf = cp;
- }
- return pri;
-}
-
-// Convert kernel log priority number into an Android Logger priority number
-static int convertKernelPrioToAndroidPrio(int pri) {
- switch (pri & LOG_PRIMASK) {
- case LOG_EMERG:
- case LOG_ALERT:
- case LOG_CRIT:
- return ANDROID_LOG_FATAL;
-
- case LOG_ERR:
- return ANDROID_LOG_ERROR;
-
- case LOG_WARNING:
- return ANDROID_LOG_WARN;
-
- default:
- case LOG_NOTICE:
- case LOG_INFO:
- break;
-
- case LOG_DEBUG:
- return ANDROID_LOG_DEBUG;
- }
-
- return ANDROID_LOG_INFO;
-}
-
-static const char* strnrchr(const char* s, ssize_t len, char c) {
- const char* save = nullptr;
- for (; len > 0; ++s, len--) {
- if (*s == c) {
- save = s;
- }
- }
- return save;
-}
-
-//
-// log a message into the kernel log buffer
-//
-// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
-// them to appear correct in the logcat output:
-//
-// LOG_KERN (0):
-// <PRI>[<TIME>] <tag> ":" <message>
-// <PRI>[<TIME>] <tag> <tag> ":" <message>
-// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
-// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
-// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
-// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
-// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
-// <PRI>[<TIME>] "[INFO]"<tag> : <message>
-// <PRI>[<TIME>] "------------[ cut here ]------------" (?)
-// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---" (?)
-// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
-// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
-// <PRI+TAG>[<TIME>] (see sys/syslog.h)
-// Observe:
-// Minimum tag length = 3 NB: drops things like r5:c00bbadf, but allow PM:
-// Maximum tag words = 2
-// Maximum tag length = 16 NB: we are thinking of how ugly logcat can get.
-// Not a Tag if there is no message content.
-// leading additional spaces means no tag, inherit last tag.
-// Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
-// Drop:
-// empty messages
-// messages with ' audit(' in them if auditd is running
-// logd.klogd:
-// return -1 if message logd.klogd: <signature>
-//
-int LogKlog::log(const char* buf, ssize_t len) {
- if (auditd && android::strnstr(buf, len, auditStr)) {
- return 0;
- }
-
- const char* p = buf;
- int pri = parseKernelPrio(p, len);
-
- log_time now = sniffTime(p, len - (p - buf), false);
-
- // sniff for start marker
- const char* start = android::strnstr(p, len - (p - buf), klogdStr);
- if (start) {
- uint64_t sig = strtoll(start + strlen(klogdStr), nullptr, 10);
- if (sig == signature.nsec()) {
- if (initialized) {
- enableLogging = true;
- } else {
- enableLogging = false;
- }
- return -1;
- }
- return 0;
- }
-
- if (!enableLogging) {
- return 0;
- }
-
- // Parse pid, tid and uid
- const pid_t pid = sniffPid(p, len - (p - buf));
- const pid_t tid = pid;
- uid_t uid = AID_ROOT;
- if (pid) {
- uid = stats_->PidToUid(pid);
- }
-
- // Parse (rules at top) to pull out a tag from the incoming kernel message.
- // Some may view the following as an ugly heuristic, the desire is to
- // beautify the kernel logs into an Android Logging format; the goal is
- // admirable but costly.
- while ((p < &buf[len]) && (isspace(*p) || !*p)) {
- ++p;
- }
- if (p >= &buf[len]) { // timestamp, no content
- return 0;
- }
- start = p;
- const char* tag = "";
- const char* etag = tag;
- ssize_t taglen = len - (p - buf);
- const char* bt = p;
-
- static const char infoBrace[] = "[INFO]";
- static const ssize_t infoBraceLen = strlen(infoBrace);
- if ((taglen >= infoBraceLen) &&
- !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
- // <PRI>[<TIME>] "[INFO]"<tag> ":" message
- bt = p + infoBraceLen;
- taglen -= infoBraceLen;
- }
-
- const char* et;
- for (et = bt; (taglen > 0) && *et && (*et != ':') && !isspace(*et);
- ++et, --taglen) {
- // skip ':' within [ ... ]
- if (*et == '[') {
- while ((taglen > 0) && *et && *et != ']') {
- ++et;
- --taglen;
- }
- if (taglen <= 0) {
- break;
- }
- }
- }
- const char* cp;
- for (cp = et; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
-
- // Validate tag
- ssize_t size = et - bt;
- if ((taglen > 0) && (size > 0)) {
- if (*cp == ':') {
- // ToDo: handle case insensitive colon separated logging stutter:
- // <tag> : <tag>: ...
-
- // One Word
- tag = bt;
- etag = et;
- p = cp + 1;
- } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
- // clean up any tag stutter
- if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
- // <PRI>[<TIME>] <tag> <tag> : message
- // <PRI>[<TIME>] <tag> <tag>: message
- // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
- // <PRI>[<TIME>] <tag> '<tag><num>' : message
- // <PRI>[<TIME>] <tag> '<tag><stuff>' : message
- const char* b = cp;
- cp += size;
- taglen -= size;
- while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
- if ((taglen > 0) && (*cp == ':')) {
- tag = b;
- etag = e;
- p = cp + 1;
- }
- } else {
- // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
- static const char host[] = "_host";
- static const ssize_t hostlen = strlen(host);
- if ((size > hostlen) &&
- !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
- !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
- const char* b = cp;
- cp += size - hostlen;
- taglen -= size - hostlen;
- if (*cp == '.') {
- while ((--taglen > 0) && !isspace(*++cp) &&
- (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp);
- ++cp, --taglen) {
- }
- if ((taglen > 0) && (*cp == ':')) {
- tag = b;
- etag = e;
- p = cp + 1;
- }
- }
- } else {
- goto twoWord;
- }
- }
- } else {
- // <PRI>[<TIME>] <tag> <stuff>' : message
- twoWord:
- while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
- // Two words
- if ((taglen > 0) && (*cp == ':')) {
- tag = bt;
- etag = e;
- p = cp + 1;
- }
- }
- } // else no tag
-
- static const char cpu[] = "CPU";
- static const ssize_t cpuLen = strlen(cpu);
- static const char warning[] = "WARNING";
- static const ssize_t warningLen = strlen(warning);
- static const char error[] = "ERROR";
- static const ssize_t errorLen = strlen(error);
- static const char info[] = "INFO";
- static const ssize_t infoLen = strlen(info);
-
- size = etag - tag;
- if ((size <= 1) ||
- // register names like x9
- ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
- // register names like x18 but not driver names like en0
- ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
- // ignore
- ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
- ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
- ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
- ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
- p = start;
- etag = tag = "";
- }
-
- // Suppress additional stutter in tag:
- // eg: [143:healthd]healthd -> [143:healthd]
- taglen = etag - tag;
- // Mediatek-special printk induced stutter
- const char* mp = strnrchr(tag, taglen, ']');
- if (mp && (++mp < etag)) {
- ssize_t s = etag - mp;
- if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
- taglen = mp - tag;
- }
- }
- // Deal with sloppy and simplistic harmless p = cp + 1 etc above.
- if (len < (p - buf)) {
- p = &buf[len];
- }
- // skip leading space
- while ((p < &buf[len]) && (isspace(*p) || !*p)) {
- ++p;
- }
- // truncate trailing space or nuls
- ssize_t b = len - (p - buf);
- while ((b > 0) && (isspace(p[b - 1]) || !p[b - 1])) {
- --b;
- }
- // trick ... allow tag with empty content to be logged. log() drops empty
- if ((b <= 0) && (taglen > 0)) {
- p = " ";
- b = 1;
- }
- // This shouldn't happen, but clamp the size if it does.
- if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
- b = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- if (taglen > LOGGER_ENTRY_MAX_PAYLOAD) {
- taglen = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- // calculate buffer copy requirements
- ssize_t n = 1 + taglen + 1 + b + 1;
- // Extra checks for likely impossible cases.
- if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) {
- return -EINVAL;
- }
-
- // Careful.
- // We are using the stack to house the log buffer for speed reasons.
- // 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
- // against stack corruption and speedup, loss is truncated long-line content.
- char newstr[n];
- char* np = newstr;
-
- // Convert priority into single-byte Android logger priority
- *np = convertKernelPrioToAndroidPrio(pri);
- ++np;
-
- // Copy parsed tag following priority
- memcpy(np, tag, taglen);
- np += taglen;
- *np = '\0';
- ++np;
-
- // Copy main message to the remainder
- memcpy(np, p, b);
- np[b] = '\0';
-
- {
- // Watch out for singular race conditions with timezone causing near
- // integer quarter-hour jumps in the time and compensate accordingly.
- // Entries will be temporal within near_seconds * 2. b/21868540
- static uint32_t vote_time[3];
- vote_time[2] = vote_time[1];
- vote_time[1] = vote_time[0];
- vote_time[0] = now.tv_sec;
-
- if (vote_time[1] && vote_time[2]) {
- static const unsigned near_seconds = 10;
- static const unsigned timezones_seconds = 900;
- int diff0 = (vote_time[0] - vote_time[1]) / near_seconds;
- unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
- int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
- unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
- if ((abs1 <= 1) && // last two were in agreement on timezone
- ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
- abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
- timezones_seconds;
- now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
- }
- }
- }
-
- // Log message
- int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
-
- return rc;
-}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
deleted file mode 100644
index 56e0452..0000000
--- a/logd/LogKlog.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 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 <private/android_logger.h>
-#include <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogStatistics.h"
-
-class LogKlog : public SocketListener {
- LogBuffer* logbuf;
- const log_time signature;
- // Set once thread is started, separates KLOG_ACTION_READ_ALL
- // and KLOG_ACTION_READ phases.
- bool initialized;
- // Used during each of the above phases to control logging.
- bool enableLogging;
- // set if we are also running auditd, to filter out audit reports from
- // our copy of the kernel log
- bool auditd;
-
- static log_time correction;
-
- public:
- LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats);
- int log(const char* buf, ssize_t len);
-
- static void convertMonotonicToReal(log_time& real) { real += correction; }
-
- protected:
- log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
- pid_t sniffPid(const char*& buf, ssize_t len);
- void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- LogStatistics* stats_;
-};
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
deleted file mode 100644
index a6ab50b..0000000
--- a/logd/LogListener.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <limits.h>
-#include <sys/cdefs.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <thread>
-
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-#include "LogListener.h"
-#include "LogPermissions.h"
-
-LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
-
-bool LogListener::StartListener() {
- if (socket_ <= 0) {
- return false;
- }
- auto thread = std::thread(&LogListener::ThreadFunction, this);
- thread.detach();
- return true;
-}
-
-void LogListener::ThreadFunction() {
- prctl(PR_SET_NAME, "logd.writer");
-
- while (true) {
- HandleData();
- }
-}
-
-void LogListener::HandleData() {
- // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
- __attribute__((uninitialized)) char
- buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
- struct iovec iov = {buffer, sizeof(buffer) - 1};
-
- alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
- struct msghdr hdr = {
- nullptr, 0, &iov, 1, control, sizeof(control), 0,
- };
-
- // To clear the entire buffer is secure/safe, but this contributes to 1.68%
- // overhead under logging load. We are safe because we check counts, but
- // still need to clear null terminator
- // memset(buffer, 0, sizeof(buffer));
- ssize_t n = recvmsg(socket_, &hdr, 0);
- if (n <= (ssize_t)(sizeof(android_log_header_t))) {
- return;
- }
-
- buffer[n] = 0;
-
- struct ucred* cred = nullptr;
-
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != nullptr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS) {
- cred = (struct ucred*)CMSG_DATA(cmsg);
- break;
- }
- cmsg = CMSG_NXTHDR(&hdr, cmsg);
- }
-
- if (cred == nullptr) {
- return;
- }
-
- if (cred->uid == AID_LOGD) {
- // ignore log messages we send to ourself.
- // Such log messages are often generated by libraries we depend on
- // which use standard Android logging.
- return;
- }
-
- android_log_header_t* header =
- reinterpret_cast<android_log_header_t*>(buffer);
- log_id_t logId = static_cast<log_id_t>(header->id);
- if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
- logId == LOG_ID_KERNEL) {
- return;
- }
-
- if ((logId == LOG_ID_SECURITY) &&
- (!__android_log_security() ||
- !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
- return;
- }
-
- char* msg = ((char*)buffer) + sizeof(android_log_header_t);
- n -= sizeof(android_log_header_t);
-
- // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
- // truncated message to the logs.
-
- logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
- ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
-}
-
-int LogListener::GetLogSocket() {
- static const char socketName[] = "logdw";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) { // logd started up in init.sh
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
-
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
- return -1;
- }
- }
- return sock;
-}
diff --git a/logd/LogListener.h b/logd/LogListener.h
deleted file mode 100644
index 566af5b..0000000
--- a/logd/LogListener.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 "LogBuffer.h"
-
-class LogListener {
- public:
- explicit LogListener(LogBuffer* buf);
- bool StartListener();
-
- private:
- void ThreadFunction();
- void HandleData();
- static int GetLogSocket();
-
- int socket_;
- LogBuffer* logbuf_;
-};
diff --git a/logd/LogPermissions.cpp b/logd/LogPermissions.cpp
deleted file mode 100644
index 3fd0ea1..0000000
--- a/logd/LogPermissions.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "LogPermissions.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <private/android_filesystem_config.h>
-
-// gets a list of supplementary group IDs associated with
-// the socket peer. This is implemented by opening
-// /proc/PID/status and look for the "Group:" line.
-//
-// This function introduces races especially since status
-// can change 'shape' while reading, the net result is err
-// on lack of permission.
-//
-// Race-free alternative is to introduce pairs of sockets
-// and threads for each command and reading, one each that
-// has open permissions, and one that has restricted
-// permissions.
-
-static bool groupIsLog(char* buf) {
- char* ptr;
- static const char ws[] = " \n";
-
- for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(nullptr, ws, &ptr)) {
- errno = 0;
- gid_t Gid = strtol(buf, nullptr, 10);
- if (errno != 0) {
- return false;
- }
- if (Gid == AID_LOG) {
- return true;
- }
- }
- return false;
-}
-
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
- if ((uid == AID_ROOT) || (uid == AID_SYSTEM) || (uid == AID_LOG)) {
- return true;
- }
-
- if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
- return true;
- }
-
- // FYI We will typically be here for 'adb logcat'
- char filename[256];
- snprintf(filename, sizeof(filename), "/proc/%u/status", pid);
-
- bool ret;
- bool foundLog = false;
- bool foundGid = false;
- bool foundUid = false;
-
- //
- // Reading /proc/<pid>/status is rife with race conditions. All of /proc
- // suffers from this and its use should be minimized. However, we have no
- // choice.
- //
- // Notably the content from one 4KB page to the next 4KB page can be from a
- // change in shape even if we are gracious enough to attempt to read
- // atomically. getline can not even guarantee a page read is not split up
- // and in effect can read from different vintages of the content.
- //
- // We are finding out in the field that a 'logcat -c' via adb occasionally
- // is returned with permission denied when we did only one pass and thus
- // breaking scripts. For security we still err on denying access if in
- // doubt, but we expect the falses should be reduced significantly as
- // three times is a charm.
- //
- for (int retry = 3; !(ret = foundGid && foundUid && foundLog) && retry;
- --retry) {
- FILE* file = fopen(filename, "re");
- if (!file) {
- continue;
- }
-
- char* line = nullptr;
- size_t len = 0;
- while (getline(&line, &len, file) > 0) {
- static const char groups_string[] = "Groups:\t";
- static const char uid_string[] = "Uid:\t";
- static const char gid_string[] = "Gid:\t";
-
- if (strncmp(groups_string, line, sizeof(groups_string) - 1) == 0) {
- if (groupIsLog(line + sizeof(groups_string) - 1)) {
- foundLog = true;
- }
- } else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
- uid_t u[4] = { (uid_t)-1, (uid_t)-1, (uid_t)-1, (uid_t)-1 };
-
- sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u", &u[0],
- &u[1], &u[2], &u[3]);
-
- // Protect against PID reuse by checking that UID is the same
- if ((uid == u[0]) && (uid == u[1]) && (uid == u[2]) &&
- (uid == u[3])) {
- foundUid = true;
- }
- } else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
- gid_t g[4] = { (gid_t)-1, (gid_t)-1, (gid_t)-1, (gid_t)-1 };
-
- sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u", &g[0],
- &g[1], &g[2], &g[3]);
-
- // Protect against PID reuse by checking that GID is the same
- if ((gid == g[0]) && (gid == g[1]) && (gid == g[2]) &&
- (gid == g[3])) {
- foundGid = true;
- }
- }
- }
- free(line);
- fclose(file);
- }
-
- return ret;
-}
-
-bool clientHasLogCredentials(SocketClient* cli) {
- return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
-}
diff --git a/logd/LogPermissions.h b/logd/LogPermissions.h
deleted file mode 100644
index 3130db5..0000000
--- a/logd/LogPermissions.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <sys/types.h>
-
-#include <sysutils/SocketClient.h>
-
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
-bool clientHasLogCredentials(SocketClient* cli);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
deleted file mode 100644
index 1c6a85f..0000000
--- a/logd/LogReader.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <ctype.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <sched.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogPermissions.h"
-#include "LogReader.h"
-#include "LogUtils.h"
-#include "LogWriter.h"
-
-static bool CanReadSecurityLogs(SocketClient* client) {
- return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
-}
-
-static std::string SocketClientToName(SocketClient* client) {
- return android::base::StringPrintf("pid %d, fd %d", client->getPid(), client->getSocket());
-}
-
-class SocketLogWriter : public LogWriter {
- public:
- SocketLogWriter(LogReader* reader, SocketClient* client, bool privileged)
- : LogWriter(client->getUid(), privileged), reader_(reader), client_(client) {}
-
- bool Write(const logger_entry& entry, const char* msg) override {
- struct iovec iovec[2];
- iovec[0].iov_base = const_cast<logger_entry*>(&entry);
- iovec[0].iov_len = entry.hdr_size;
- iovec[1].iov_base = const_cast<char*>(msg);
- iovec[1].iov_len = entry.len;
-
- return client_->sendDatav(iovec, 1 + (entry.len != 0)) == 0;
- }
-
- void Release() override {
- reader_->release(client_);
- client_->decRef();
- }
-
- void Shutdown() override { shutdown(client_->getSocket(), SHUT_RDWR); }
-
- std::string name() const override { return SocketClientToName(client_); }
-
- private:
- LogReader* reader_;
- SocketClient* client_;
-};
-
-LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
- : SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
-
-// Note returning false will release the SocketClient instance.
-bool LogReader::onDataAvailable(SocketClient* cli) {
- static bool name_set;
- if (!name_set) {
- prctl(PR_SET_NAME, "logd.reader");
- name_set = true;
- }
-
- char buffer[255];
-
- int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
- if (len <= 0) {
- DoSocketDelete(cli);
- return false;
- }
- buffer[len] = '\0';
-
- // Clients are only allowed to send one command, disconnect them if they send another.
- if (DoSocketDelete(cli)) {
- return false;
- }
-
- unsigned long tail = 0;
- static const char _tail[] = " tail=";
- char* cp = strstr(buffer, _tail);
- if (cp) {
- tail = atol(cp + sizeof(_tail) - 1);
- }
-
- log_time start(log_time::EPOCH);
- static const char _start[] = " start=";
- cp = strstr(buffer, _start);
- if (cp) {
- // Parse errors will result in current time
- start.strptime(cp + sizeof(_start) - 1, "%s.%q");
- }
-
- std::chrono::steady_clock::time_point deadline = {};
- static const char _timeout[] = " timeout=";
- cp = strstr(buffer, _timeout);
- if (cp) {
- long timeout_seconds = atol(cp + sizeof(_timeout) - 1);
- deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
- }
-
- unsigned int logMask = -1;
- static const char _logIds[] = " lids=";
- cp = strstr(buffer, _logIds);
- if (cp) {
- logMask = 0;
- cp += sizeof(_logIds) - 1;
- while (*cp != '\0') {
- int val = 0;
- while (isdigit(*cp)) {
- val = val * 10 + *cp - '0';
- ++cp;
- }
- logMask |= 1 << val;
- if (*cp != ',') {
- break;
- }
- ++cp;
- }
- }
-
- pid_t pid = 0;
- static const char _pid[] = " pid=";
- cp = strstr(buffer, _pid);
- if (cp) {
- pid = atol(cp + sizeof(_pid) - 1);
- }
-
- bool nonBlock = false;
- if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
- // Allow writer to get some cycles, and wait for pending notifications
- sched_yield();
- logd_lock.lock();
- logd_lock.unlock();
- sched_yield();
- nonBlock = true;
- }
-
- bool privileged = clientHasLogCredentials(cli);
- bool can_read_security = CanReadSecurityLogs(cli);
- if (!can_read_security) {
- logMask &= ~(1 << LOG_ID_SECURITY);
- }
-
- std::unique_ptr<LogWriter> socket_log_writer(new SocketLogWriter(this, cli, privileged));
-
- uint64_t sequence = 1;
- // Convert realtime to sequence number
- if (start != log_time::EPOCH) {
- bool start_time_set = false;
- uint64_t last = sequence;
- auto log_find_start = [pid, start, &sequence, &start_time_set, &last](
- log_id_t, pid_t element_pid, uint64_t element_sequence,
- log_time element_realtime) -> FilterResult {
- if (pid && pid != element_pid) {
- return FilterResult::kSkip;
- }
- if (start == element_realtime) {
- sequence = element_sequence;
- start_time_set = true;
- return FilterResult::kStop;
- } else {
- if (start < element_realtime) {
- sequence = last;
- start_time_set = true;
- return FilterResult::kStop;
- }
- last = element_sequence;
- }
- return FilterResult::kSkip;
- };
- auto lock = std::lock_guard{logd_lock};
- auto flush_to_state = log_buffer_->CreateFlushToState(sequence, logMask);
- log_buffer_->FlushTo(socket_log_writer.get(), *flush_to_state, log_find_start);
-
- if (!start_time_set) {
- if (nonBlock) {
- return false;
- }
- sequence = log_buffer_->sequence();
- }
- }
-
- LOG(INFO) << android::base::StringPrintf(
- "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
- "start=%" PRIu64 "ns deadline=%" PRIi64 "ns",
- cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask,
- (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count()));
-
- if (start == log_time::EPOCH) {
- deadline = {};
- }
-
- auto lock = std::lock_guard{logd_lock};
- auto entry = std::make_unique<LogReaderThread>(log_buffer_, reader_list_,
- std::move(socket_log_writer), nonBlock, tail,
- logMask, pid, start, sequence, deadline);
- // release client and entry reference counts once done
- cli->incRef();
- reader_list_->reader_threads().emplace_front(std::move(entry));
-
- // Set acceptable upper limit to wait for slow reader processing b/27242723
- struct timeval t = { LOGD_SNDTIMEO, 0 };
- setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
- sizeof(t));
-
- return true;
-}
-
-bool LogReader::DoSocketDelete(SocketClient* cli) {
- auto cli_name = SocketClientToName(cli);
- auto lock = std::lock_guard{logd_lock};
- for (const auto& reader : reader_list_->reader_threads()) {
- if (reader->name() == cli_name) {
- reader->Release();
- return true;
- }
- }
- return false;
-}
-
-int LogReader::getLogSocket() {
- static const char socketName[] = "logdr";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) {
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
- }
-
- return sock;
-}
diff --git a/logd/LogReader.h b/logd/LogReader.h
deleted file mode 100644
index a4e52c4..0000000
--- a/logd/LogReader.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-#include "LogReaderThread.h"
-
-class LogReader : public SocketListener {
- public:
- explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
-
- protected:
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- static int getLogSocket();
-
- bool DoSocketDelete(SocketClient* cli);
-
- LogBuffer* log_buffer_;
- LogReaderList* reader_list_;
-};
diff --git a/logd/LogReaderList.cpp b/logd/LogReaderList.cpp
deleted file mode 100644
index 51cb3d2..0000000
--- a/logd/LogReaderList.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 "LogReaderList.h"
-
-// When we are notified a new log entry is available, inform
-// listening sockets who are watching this entry's log id.
-void LogReaderList::NotifyNewLog(LogMask log_mask) const {
- for (const auto& entry : reader_threads_) {
- if (!entry->IsWatchingMultiple(log_mask)) {
- continue;
- }
- if (entry->deadline().time_since_epoch().count() != 0) {
- continue;
- }
- entry->TriggerReader();
- }
-}
diff --git a/logd/LogReaderList.h b/logd/LogReaderList.h
deleted file mode 100644
index 39de70a..0000000
--- a/logd/LogReaderList.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 <list>
-#include <memory>
-#include <mutex>
-
-#include "LogBuffer.h"
-#include "LogReaderThread.h"
-#include "LogdLock.h"
-
-class LogReaderList {
- public:
- void NotifyNewLog(LogMask log_mask) const REQUIRES(logd_lock);
-
- std::list<std::unique_ptr<LogReaderThread>>& reader_threads() REQUIRES(logd_lock) {
- return reader_threads_;
- }
-
- private:
- std::list<std::unique_ptr<LogReaderThread>> reader_threads_ GUARDED_BY(logd_lock);
-};
\ No newline at end of file
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
deleted file mode 100644
index cf769ba..0000000
--- a/logd/LogReaderThread.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogReaderThread.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/prctl.h>
-
-#include <thread>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-#include "SerializedFlushToState.h"
-
-LogReaderThread::LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
- std::unique_ptr<LogWriter> writer, bool non_block,
- unsigned long tail, LogMask log_mask, pid_t pid,
- log_time start_time, uint64_t start,
- std::chrono::steady_clock::time_point deadline)
- : log_buffer_(log_buffer),
- reader_list_(reader_list),
- writer_(std::move(writer)),
- pid_(pid),
- tail_(tail),
- count_(0),
- index_(0),
- start_time_(start_time),
- deadline_(deadline),
- non_block_(non_block) {
- CleanSkip();
- flush_to_state_ = log_buffer_->CreateFlushToState(start, log_mask);
- auto thread = std::thread{&LogReaderThread::ThreadFunction, this};
- thread.detach();
-}
-
-void LogReaderThread::ThreadFunction() {
- prctl(PR_SET_NAME, "logd.reader.per");
-
- auto lock = std::unique_lock{logd_lock};
- auto lock_assertion = android::base::ScopedLockAssertion{logd_lock};
-
- while (!release_) {
- if (deadline_.time_since_epoch().count() != 0) {
- if (thread_triggered_condition_.wait_until(lock, deadline_) ==
- std::cv_status::timeout) {
- deadline_ = {};
- }
- if (release_) {
- break;
- }
- }
-
- if (tail_) {
- auto first_pass_state = log_buffer_->CreateFlushToState(flush_to_state_->start(),
- flush_to_state_->log_mask());
- log_buffer_->FlushTo(writer_.get(), *first_pass_state,
- [this](log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime) REQUIRES(logd_lock) {
- return FilterFirstPass(log_id, pid, sequence, realtime);
- });
- }
- bool flush_success = log_buffer_->FlushTo(
- writer_.get(), *flush_to_state_,
- [this](log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime) REQUIRES(
- logd_lock) { return FilterSecondPass(log_id, pid, sequence, realtime); });
-
- // We only ignore entries before the original start time for the first flushTo(), if we
- // get entries after this first flush before the original start time, then the client
- // wouldn't have seen them.
- // Note: this is still racy and may skip out of order events that came in since the last
- // time the client disconnected and then reconnected with the new start time. The long term
- // solution here is that clients must request events since a specific sequence number.
- start_time_.tv_sec = 0;
- start_time_.tv_nsec = 0;
-
- if (!flush_success) {
- break;
- }
-
- if (non_block_ || release_) {
- break;
- }
-
- CleanSkip();
-
- if (deadline_.time_since_epoch().count() == 0) {
- thread_triggered_condition_.wait(lock);
- }
- }
-
- writer_->Release();
-
- auto& log_reader_threads = reader_list_->reader_threads();
- auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
- [this](const auto& other) { return other.get() == this; });
-
- if (it != log_reader_threads.end()) {
- log_reader_threads.erase(it);
- }
-}
-
-// A first pass to count the number of elements
-FilterResult LogReaderThread::FilterFirstPass(log_id_t, pid_t pid, uint64_t, log_time realtime) {
- if ((!pid_ || pid_ == pid) && (start_time_ == log_time::EPOCH || start_time_ <= realtime)) {
- ++count_;
- }
-
- return FilterResult::kSkip;
-}
-
-// A second pass to send the selected elements
-FilterResult LogReaderThread::FilterSecondPass(log_id_t log_id, pid_t pid, uint64_t,
- log_time realtime) {
- if (skip_ahead_[log_id]) {
- skip_ahead_[log_id]--;
- return FilterResult::kSkip;
- }
-
- // Truncate to close race between first and second pass
- if (non_block_ && tail_ && index_ >= count_) {
- return FilterResult::kStop;
- }
-
- if (pid_ && pid_ != pid) {
- return FilterResult::kSkip;
- }
-
- if (start_time_ != log_time::EPOCH && realtime <= start_time_) {
- return FilterResult::kSkip;
- }
-
- if (release_) {
- return FilterResult::kStop;
- }
-
- if (!tail_) {
- goto ok;
- }
-
- ++index_;
-
- if (count_ > tail_ && index_ <= (count_ - tail_)) {
- return FilterResult::kSkip;
- }
-
- if (!non_block_) {
- tail_ = 0;
- }
-
-ok:
- if (!skip_ahead_[log_id]) {
- return FilterResult::kWrite;
- }
- return FilterResult::kSkip;
-}
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
deleted file mode 100644
index 96137b3..0000000
--- a/logd/LogReaderThread.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <pthread.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <chrono>
-#include <condition_variable>
-#include <list>
-#include <memory>
-
-#include <android-base/thread_annotations.h>
-#include <log/log.h>
-
-#include "LogBuffer.h"
-#include "LogWriter.h"
-#include "LogdLock.h"
-
-class LogReaderList;
-
-class LogReaderThread {
- public:
- LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
- std::unique_ptr<LogWriter> writer, bool non_block, unsigned long tail,
- LogMask log_mask, pid_t pid, log_time start_time, uint64_t sequence,
- std::chrono::steady_clock::time_point deadline);
- void TriggerReader() REQUIRES(logd_lock) { thread_triggered_condition_.notify_all(); }
-
- void TriggerSkip(log_id_t id, unsigned int skip) REQUIRES(logd_lock) { skip_ahead_[id] = skip; }
- void CleanSkip() REQUIRES(logd_lock) { memset(skip_ahead_, 0, sizeof(skip_ahead_)); }
-
- void Release() REQUIRES(logd_lock) {
- // gracefully shut down the socket.
- writer_->Shutdown();
- release_ = true;
- thread_triggered_condition_.notify_all();
- }
-
- bool IsWatching(log_id_t id) const REQUIRES(logd_lock) {
- return flush_to_state_->log_mask() & (1 << id);
- }
- bool IsWatchingMultiple(LogMask log_mask) const REQUIRES(logd_lock) {
- return flush_to_state_->log_mask() & log_mask;
- }
-
- std::string name() const REQUIRES(logd_lock) { return writer_->name(); }
- uint64_t start() const REQUIRES(logd_lock) { return flush_to_state_->start(); }
- std::chrono::steady_clock::time_point deadline() const REQUIRES(logd_lock) { return deadline_; }
- FlushToState& flush_to_state() REQUIRES(logd_lock) { return *flush_to_state_; }
-
- private:
- void ThreadFunction();
- // flushTo filter callbacks
- FilterResult FilterFirstPass(log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime)
- REQUIRES(logd_lock);
- FilterResult FilterSecondPass(log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime)
- REQUIRES(logd_lock);
-
- std::condition_variable thread_triggered_condition_;
- LogBuffer* log_buffer_;
- LogReaderList* reader_list_;
- std::unique_ptr<LogWriter> writer_ GUARDED_BY(logd_lock);
-
- // Set to true to cause the thread to end and the LogReaderThread to delete itself.
- bool release_ GUARDED_BY(logd_lock) = false;
-
- // If set to non-zero, only pids equal to this are read by the reader.
- const pid_t pid_;
- // When a reader is referencing (via start_) old elements in the log buffer, and the log
- // buffer's size grows past its memory limit, the log buffer may request the reader to skip
- // ahead a specified number of logs.
- unsigned int skip_ahead_[LOG_ID_MAX] GUARDED_BY(logd_lock);
- // LogBuffer::FlushTo() needs to store state across subsequent calls.
- std::unique_ptr<FlushToState> flush_to_state_ GUARDED_BY(logd_lock);
-
- // These next three variables are used for reading only the most recent lines aka `adb logcat
- // -t` / `adb logcat -T`.
- // tail_ is the number of most recent lines to print.
- unsigned long tail_;
- // count_ is the result of a first pass through the log buffer to determine how many total
- // messages there are.
- unsigned long count_;
- // index_ is used along with count_ to only start sending lines once index_ > (count_ - tail_)
- // and to disconnect the reader (if it is dumpAndClose, `adb logcat -t`), when index_ >= count_.
- unsigned long index_;
-
- // When a reader requests logs starting from a given timestamp, its stored here for the first
- // pass, such that logs before this time stamp that are accumulated in the buffer are ignored.
- log_time start_time_;
- // CLOCK_MONOTONIC based deadline used for log wrapping. If this deadline expires before logs
- // wrap, then wake up and send the logs to the reader anyway.
- std::chrono::steady_clock::time_point deadline_ GUARDED_BY(logd_lock);
- // If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
- const bool non_block_;
-};
diff --git a/logd/LogSize.cpp b/logd/LogSize.cpp
deleted file mode 100644
index fe829ba..0000000
--- a/logd/LogSize.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 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 <LogSize.h>
-
-#include <array>
-#include <optional>
-#include <string>
-
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-
-bool IsValidBufferSize(size_t value) {
- return kLogBufferMinSize <= value && value <= kLogBufferMaxSize;
-}
-
-static std::optional<size_t> GetBufferSizeProperty(const std::string& key) {
- std::string value = android::base::GetProperty(key, "");
- if (value.empty()) {
- return {};
- }
-
- uint32_t size;
- if (!android::base::ParseByteCount(value, &size)) {
- return {};
- }
-
- if (!IsValidBufferSize(size)) {
- return {};
- }
-
- return size;
-}
-
-size_t GetBufferSizeFromProperties(log_id_t log_id) {
- std::string buffer_name = android_log_id_to_name(log_id);
- std::array<std::string, 4> properties = {
- "persist.logd.size." + buffer_name,
- "ro.logd.size." + buffer_name,
- "persist.logd.size",
- "ro.logd.size",
- };
-
- for (const auto& property : properties) {
- if (auto size = GetBufferSizeProperty(property)) {
- return *size;
- }
- }
-
- if (android::base::GetBoolProperty("ro.config.low_ram", false)) {
- return kLogBufferMinSize;
- }
-
- return kDefaultLogBufferSize;
-}
diff --git a/logd/LogSize.h b/logd/LogSize.h
deleted file mode 100644
index d5716ff..0000000
--- a/logd/LogSize.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 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 <stddef.h>
-
-#include <log/log.h>
-
-static constexpr size_t kDefaultLogBufferSize = 256 * 1024;
-static constexpr size_t kLogBufferMinSize = 64 * 1024;
-static constexpr size_t kLogBufferMaxSize = 256 * 1024 * 1024;
-
-bool IsValidBufferSize(size_t value);
-
-// This returns the buffer size as set in system properties for use in LogBuffer::Init().
-// Note that `logcat -G` calls LogBuffer::SetSize(), which configures log buffer sizes without
-// setting these properties, so this function should never be used except for LogBuffer::Init().
-// LogBuffer::GetSize() should be used instead within logd. Other processes can use
-// android_logger_get_log_size() or `logcat -g` to query the actual allotted buffer size.
-size_t GetBufferSizeFromProperties(log_id_t log_id);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
deleted file mode 100644
index 87069b3..0000000
--- a/logd/LogStatistics.cpp
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogStatistics.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#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"
-
-static const uint64_t hourSec = 60 * 60;
-static const uint64_t monthSec = 31 * 24 * hourSec;
-
-std::atomic<size_t> LogStatistics::SizesTotal;
-
-static std::string TagNameKey(const LogStatisticsElement& element) {
- if (IsBinary(element.log_id)) {
- uint32_t tag = element.tag;
- if (tag) {
- const char* cp = android::tagToName(tag);
- if (cp) {
- return std::string(cp);
- }
- }
- return android::base::StringPrintf("[%" PRIu32 "]", tag);
- }
- const char* msg = element.msg;
- if (!msg) {
- return "chatty";
- }
- ++msg;
- uint16_t len = element.msg_len;
- len = (len <= 1) ? 0 : strnlen(msg, len - 1);
- if (!len) {
- return "<NULL>";
- }
- return std::string(msg, len);
-}
-
-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) {
- mSizes[id] = 0;
- mElements[id] = 0;
- mDroppedElements[id] = 0;
- mSizesTotal[id] = 0;
- mElementsTotal[id] = 0;
- if (start_time) {
- mOldest[id] = *start_time;
- mNewest[id] = *start_time;
- } else {
- mOldest[id] = now;
- mNewest[id] = now;
- }
- mNewestDropped[id] = now;
- }
-}
-
-namespace android {
-
-size_t sizesTotal() {
- return LogStatistics::sizesTotal();
-}
-
-// caller must own and free character string
-char* pidToName(pid_t pid) {
- char* retval = nullptr;
- if (pid == 0) { // special case from auditd/klogd for kernel
- retval = strdup("logd");
- } else {
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
- int fd = open(buffer, O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- ssize_t ret = read(fd, buffer, sizeof(buffer));
- if (ret > 0) {
- buffer[sizeof(buffer) - 1] = '\0';
- // frameworks intermediate state
- if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
- retval = strdup(buffer);
- }
- }
- close(fd);
- }
- }
- return retval;
-}
-}
-
-void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
- auto lock = std::lock_guard{lock_};
-
- mSizesTotal[log_id] += size;
- SizesTotal += size;
- ++mElementsTotal[log_id];
-}
-
-void LogStatistics::Add(LogStatisticsElement element) {
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = element.msg_len;
- }
-
- log_id_t log_id = element.log_id;
- uint16_t size = element.total_len;
- mSizes[log_id] += size;
- ++mElements[log_id];
-
- // When caller adding a chatty entry, they will have already
- // called add() and subtract() for each entry as they are
- // evaluated and trimmed, thus recording size and number of
- // elements, but we must recognize the manufactured dropped
- // entry as not contributing to the lifetime totals.
- if (element.dropped_count) {
- ++mDroppedElements[log_id];
- } else {
- mSizesTotal[log_id] += size;
- SizesTotal += size;
- ++mElementsTotal[log_id];
- }
-
- log_time stamp(element.realtime);
- if (mNewest[log_id] < stamp) {
- // A major time update invalidates the statistics :-(
- log_time diff = stamp - mNewest[log_id];
- mNewest[log_id] = stamp;
-
- if (diff.tv_sec > hourSec) {
- // approximate Do-Your-Best fixup
- diff += mOldest[log_id];
- if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
- diff = stamp;
- }
- if (diff <= stamp) {
- mOldest[log_id] = diff;
- if (mNewestDropped[log_id] < diff) {
- mNewestDropped[log_id] = diff;
- }
- }
- }
- }
-
- if (log_id == LOG_ID_KERNEL) {
- return;
- }
-
- uidTable[log_id].Add(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Add(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Add(element.pid, element);
- tidTable.Add(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Add(tag, element);
- } else {
- tagTable.Add(tag, element);
- }
- }
-
- if (!element.dropped_count) {
- tagNameTable.Add(TagNameKey(element), element);
- }
-}
-
-void LogStatistics::Subtract(LogStatisticsElement element) {
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = element.msg_len;
- }
-
- log_id_t log_id = element.log_id;
- uint16_t size = element.total_len;
- mSizes[log_id] -= size;
- --mElements[log_id];
- if (element.dropped_count) {
- --mDroppedElements[log_id];
- }
-
- if (mOldest[log_id] < element.realtime) {
- mOldest[log_id] = element.realtime;
- }
-
- if (log_id == LOG_ID_KERNEL) {
- return;
- }
-
- uidTable[log_id].Subtract(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Subtract(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Subtract(element.pid, element);
- tidTable.Subtract(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Subtract(tag, element);
- } else {
- tagTable.Subtract(tag, element);
- }
- }
-
- if (!element.dropped_count) {
- tagNameTable.Subtract(TagNameKey(element), element);
- }
-}
-
-// Atomically set an entry to drop
-// entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::Drop(LogStatisticsElement element) {
- CHECK_EQ(element.dropped_count, 0U);
-
- auto lock = std::lock_guard{lock_};
- log_id_t log_id = element.log_id;
- uint16_t size = element.msg_len;
- mSizes[log_id] -= size;
- ++mDroppedElements[log_id];
-
- if (mNewestDropped[log_id] < element.realtime) {
- mNewestDropped[log_id] = element.realtime;
- }
-
- uidTable[log_id].Drop(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Drop(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Drop(element.pid, element);
- tidTable.Drop(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Drop(tag, element);
- } else {
- tagTable.Drop(tag, element);
- }
- }
-
- tagNameTable.Subtract(TagNameKey(element), element);
-}
-
-void LogStatistics::Erase(LogStatisticsElement element) {
- CHECK_GT(element.dropped_count, 0U);
- CHECK_EQ(element.msg_len, 0U);
-
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = 0;
- }
-
- log_id_t log_id = element.log_id;
- --mElements[log_id];
- --mDroppedElements[log_id];
- mSizes[log_id] -= element.total_len;
-
- uidTable[log_id].Erase(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Erase(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Erase(element.pid, element);
- tidTable.Erase(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Erase(tag, element);
- } else {
- tagTable.Erase(tag, element);
- }
- }
-}
-
-const char* LogStatistics::UidToName(uid_t uid) const {
- auto lock = std::lock_guard{lock_};
- return UidToNameLocked(uid);
-}
-
-// caller must own and free character string
-const char* LogStatistics::UidToNameLocked(uid_t uid) const {
- // Local hard coded favourites
- if (uid == AID_LOGD) {
- return strdup("auditd");
- }
-
- // Android system
- if (uid < AID_APP) {
- // in bionic, thread safe as long as we copy the results
- struct passwd* pwd = getpwuid(uid);
- if (pwd) {
- return strdup(pwd->pw_name);
- }
- }
-
- // Parse /data/system/packages.list
- uid_t userId = uid % AID_USER_OFFSET;
- const char* name = android::uidToName(userId);
- if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
- name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
- }
- if (name) {
- return name;
- }
-
- // Android application
- if (uid >= AID_APP) {
- struct passwd* pwd = getpwuid(uid);
- if (pwd) {
- return strdup(pwd->pw_name);
- }
- }
-
- // report uid -> pid(s) -> pidToName if unique
- for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
- ++it) {
- const PidEntry& entry = it->second;
-
- if (entry.uid() == uid) {
- const char* nameTmp = entry.name();
-
- if (nameTmp) {
- if (!name) {
- name = strdup(nameTmp);
- } else if (fastcmp<strcmp>(name, nameTmp)) {
- free(const_cast<char*>(name));
- name = nullptr;
- break;
- }
- }
- }
- }
-
- // No one
- return name;
-}
-
-template <typename TKey, typename TEntry>
-void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
- int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- std::array<const TKey*, 2> max_keys;
- std::array<const TEntry*, 2> max_entries;
- table.MaxEntries(AID_ROOT, 0, max_keys, max_entries);
- if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
- return;
- }
- *worst_sizes = max_entries[0]->getSizes();
- // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
- // 100 characters.
- if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
- *worst = *max_keys[0];
- *second_worst_sizes = max_entries[1]->getSizes();
- if (*second_worst_sizes < threshold) {
- *second_worst_sizes = threshold;
- }
- }
-}
-
-void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
-}
-
-void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
-}
-
-void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- std::array<const pid_t*, 2> max_keys;
- std::array<const PidEntry*, 2> max_entries;
- pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
- if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
- return;
- }
-
- *worst = *max_keys[0];
- *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
-}
-
-// Prune at most 10% of the log entries or maxPrune, whichever is less.
-bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
- unsigned long* prune_rows) const {
- static constexpr size_t kMinPrune = 4;
- static constexpr size_t kMaxPrune = 256;
-
- auto lock = std::lock_guard{lock_};
- size_t sizes = mSizes[id];
- if (sizes <= max_size) {
- return false;
- }
- size_t size_over = sizes - ((max_size * 9) / 10);
- size_t elements = mElements[id] - mDroppedElements[id];
- size_t min_elements = elements / 100;
- if (min_elements < kMinPrune) {
- min_elements = kMinPrune;
- }
- *prune_rows = elements * size_over / sizes;
- if (*prune_rows < min_elements) {
- *prune_rows = min_elements;
- }
- if (*prune_rows > kMaxPrune) {
- *prune_rows = kMaxPrune;
- }
-
- return true;
-}
-
-std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
- bool isprune = worstUidEnabledForLogid(id);
- return formatLine(android::base::StringPrintf(name.c_str(),
- android_log_id_to_name(id)),
- std::string("Size"),
- std::string(isprune ? "+/- Pruned" : "")) +
- formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
- std::string(isprune ? "NUM" : ""));
-}
-
-// Helper to truncate name, if too long, and add name dressings
-void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
- size_t nameLen) const {
- const char* allocNameTmp = nullptr;
- if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
- if (nameTmp) {
- size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
- size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
- lenSpace - 2;
- size_t lenNameTmp = strlen(nameTmp);
- while ((len < lenNameTmp) && (lenSpace > 1)) {
- ++len;
- --lenSpace;
- }
- name += android::base::StringPrintf("%*s", (int)lenSpace, "");
- if (len < lenNameTmp) {
- name += "...";
- nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
- }
- name += nameTmp;
- free(const_cast<char*>(allocNameTmp));
- }
-}
-
-std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%u", uid);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(nullptr, uid, name, size, 6);
-
- std::string pruned = "";
- if (worstUidEnabledForLogid(id)) {
- size_t totalDropped = 0;
- for (LogStatistics::uidTable_t::const_iterator it =
- stat.uidTable[id].begin();
- it != stat.uidTable[id].end(); ++it) {
- totalDropped += it->second.dropped_count();
- }
- size_t sizes = stat.mSizes[id];
- size_t totalSize = stat.mSizesTotal[id];
- size_t totalElements = stat.mElementsTotal[id];
- float totalVirtualSize =
- (float)sizes + (float)totalDropped * totalSize / totalElements;
- size_t entrySize = getSizes();
- float virtualEntrySize = entrySize;
- int realPermille = virtualEntrySize * 1000.0 / sizes;
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- virtualEntrySize += (float)dropped * totalSize / totalElements;
- }
- int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
- int permille =
- (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
- if ((permille < -1) || (1 < permille)) {
- std::string change;
- const char* units = "%";
- const char* prefix = (permille > 0) ? "+" : "";
-
- if (permille > 999) {
- permille = (permille + 1000) / 100; // Now tenths fold
- units = "X";
- prefix = "";
- }
- if ((-99 < permille) && (permille < 99)) {
- change = android::base::StringPrintf(
- "%s%d.%u%s", prefix, permille / 10,
- ((permille < 0) ? (-permille % 10) : (permille % 10)),
- units);
- } else {
- change = android::base::StringPrintf(
- "%s%d%s", prefix, (permille + 5) / 10, units);
- }
- ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
- if ((spaces <= 0) && pruned.length()) {
- spaces = 1;
- }
- if (spaces > 0) {
- change += android::base::StringPrintf("%*s", (int)spaces, "");
- }
- pruned = change + pruned;
- }
- }
-
- std::string output = formatLine(name, size, pruned);
-
- if (uid != AID_SYSTEM) {
- return output;
- }
-
- static const size_t maximum_sorted_entries = 32;
- std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
- std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
- stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
-
- std::string byPid;
- size_t index;
- bool hasDropped = false;
- for (index = 0; index < maximum_sorted_entries; ++index) {
- const PidEntry* entry = sorted_entries[index];
- if (!entry) {
- break;
- }
- if (entry->getSizes() <= (getSizes() / 100)) {
- break;
- }
- if (entry->dropped_count()) {
- hasDropped = true;
- }
- byPid += entry->format(stat, id, *sorted_pids[index]);
- }
- if (index > 1) { // print this only if interesting
- std::string ditto("\" ");
- output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
- hasDropped ? ditto : std::string(""));
- output += byPid;
- }
-
- return output;
-}
-
-std::string PidEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("Pruned")) +
- formatLine(std::string(" PID/UID COMMAND LINE"),
- std::string("BYTES"), std::string("NUM"));
-}
-
-std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(name_, uid_, name, size, 12);
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TidEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("Pruned")) +
- formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
- std::string("NUM"));
-}
-
-std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(name_, uid_, name, size, 12);
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
- bool isprune = worstUidEnabledForLogid(id);
- return formatLine(name, std::string("Size"),
- std::string(isprune ? "Prune" : "")) +
- formatLine(std::string(" TAG/UID TAGNAME"),
- std::string("BYTES"), std::string(isprune ? "NUM" : ""));
-}
-
-std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
- std::string name;
- if (uid_ == (uid_t)-1) {
- name = android::base::StringPrintf("%7u", key());
- } else {
- name = android::base::StringPrintf("%7u/%u", key(), uid_);
- }
- const char* nameTmp = this->name();
- if (nameTmp) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
- }
-
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TagNameEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("")) +
- formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
- std::string("BYTES"), std::string(""));
-}
-
-std::string TagNameEntry::format(const LogStatistics&, log_id_t,
- const std::string& key_name) const {
- std::string name;
- std::string pidstr;
- if (pid_ != (pid_t)-1) {
- pidstr = android::base::StringPrintf("%u", pid_);
- if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
- }
- int len = 9 - pidstr.length();
- if (len < 0) len = 0;
- if (tid_ == (pid_t)-1 || tid_ == pid_) {
- name = android::base::StringPrintf("%*s", len, "");
- } else {
- name = android::base::StringPrintf("%*u", len, tid_);
- }
- name += pidstr;
- if (uid_ != (uid_t)-1) {
- name += android::base::StringPrintf("/%u", uid_);
- }
-
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- const char* nameTmp = key_name.data();
- if (nameTmp) {
- size_t lenSpace = std::max(16 - name.length(), (size_t)1);
- size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
- lenSpace - 2;
- size_t lenNameTmp = strlen(nameTmp);
- while ((len < lenNameTmp) && (lenSpace > 1)) {
- ++len;
- --lenSpace;
- }
- name += android::base::StringPrintf("%*s", (int)lenSpace, "");
- if (len < lenNameTmp) {
- name += "...";
- nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
- }
- name += nameTmp;
- }
-
- std::string pruned = "";
-
- return formatLine(name, size, pruned);
-}
-
-static std::string formatMsec(uint64_t val) {
- static const unsigned subsecDigits = 3;
- static const uint64_t sec = MS_PER_SEC;
-
- static const uint64_t minute = 60 * sec;
- static const uint64_t hour = 60 * minute;
- static const uint64_t day = 24 * hour;
-
- std::string output;
- if (val < sec) return output;
-
- if (val >= day) {
- output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
- val = (val % day) + day;
- }
- if (val >= minute) {
- if (val >= hour) {
- output += android::base::StringPrintf("%" PRIu64 ":",
- (val / hour) % (day / hour));
- }
- output += android::base::StringPrintf(
- (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
- (val / minute) % (hour / minute));
- }
- output +=
- android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
- (val / sec) % (minute / sec));
- val %= sec;
- unsigned digits = subsecDigits;
- while (digits && ((val % 10) == 0)) {
- val /= 10;
- --digits;
- }
- if (digits) {
- output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
- }
- return output;
-}
-
-template <typename TKey, typename TEntry>
-std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
- pid_t pid, const std::string& name, log_id_t id) const
- REQUIRES(lock_) {
- static const size_t maximum_sorted_entries = 32;
- std::string output;
- std::array<const TKey*, maximum_sorted_entries> sorted_keys;
- std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
- table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
- bool header_printed = false;
- for (size_t index = 0; index < maximum_sorted_entries; ++index) {
- const TEntry* entry = sorted_entries[index];
- if (!entry) {
- break;
- }
- if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
- break;
- }
- if (!header_printed) {
- output += "\n\n";
- output += entry->formatHeader(name, id);
- header_printed = true;
- }
- output += entry->format(*this, id, *sorted_keys[index]);
- }
- 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_};
-
- static const uint16_t spaces_total = 19;
-
- // Report on total logging, current and for all time
-
- std::string output = "size/num";
- size_t oldLength;
- int16_t spaces = 1;
-
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%s", spaces, "",
- android_log_id_to_name(id));
- spaces += spaces_total + oldLength - output.length();
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*sTotal", spaces, "");
-
- static const char TotalStr[] = "\nTotal";
- spaces = 10 - strlen(TotalStr);
- output += TotalStr;
-
- size_t totalSize = 0;
- size_t totalEls = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = mSizesTotal[id];
- totalSize += szs;
- size_t els = mElementsTotal[id];
- totalEls += els;
- output +=
- android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
- spaces += spaces_total + oldLength - output.length();
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
- totalEls);
-
- static const char NowStr[] = "\nNow";
- spaces = 10 - strlen(NowStr);
- output += NowStr;
-
- totalSize = 0;
- totalEls = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- size_t els = mElements[id];
- if (els) {
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = mSizes[id];
- totalSize += szs;
- totalEls += els;
- output +=
- android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
- spaces -= output.length() - oldLength;
- }
- spaces += spaces_total;
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
- totalEls);
-
- static const char SpanStr[] = "\nLogspan";
- spaces = 10 - strlen(SpanStr);
- output += SpanStr;
-
- // Total reports the greater of the individual maximum time span, or the
- // validated minimum start and maximum end time span if it makes sense.
- uint64_t minTime = UINT64_MAX;
- uint64_t maxTime = 0;
- uint64_t maxSpan = 0;
- totalSize = 0;
-
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- // validity checking
- uint64_t oldest = mOldest[id].msec();
- uint64_t newest = mNewest[id].msec();
- if (newest <= oldest) {
- spaces += spaces_total;
- continue;
- }
-
- uint64_t span = newest - oldest;
- if (span > (monthSec * MS_PER_SEC)) {
- spaces += spaces_total;
- continue;
- }
-
- // total span
- if (minTime > oldest) minTime = oldest;
- if (maxTime < newest) maxTime = newest;
- if (span > maxSpan) maxSpan = span;
- totalSize += span;
-
- uint64_t dropped = mNewestDropped[id].msec();
- if (dropped < oldest) dropped = oldest;
- if (dropped > newest) dropped = newest;
-
- oldLength = output.length();
- output += android::base::StringPrintf("%*s%s", spaces, "",
- formatMsec(span).c_str());
- unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
- if ((permille > 1) && (permille < 999)) {
- output += android::base::StringPrintf("(%u", permille / 10);
- permille %= 10;
- if (permille) {
- output += android::base::StringPrintf(".%u", permille);
- }
- output += android::base::StringPrintf("%%)");
- }
- spaces -= output.length() - oldLength;
- spaces += spaces_total;
- }
- if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
- (maxTime > maxSpan)) {
- maxSpan = maxTime;
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%s", spaces, "",
- formatMsec(maxSpan).c_str());
-
- static const char OverheadStr[] = "\nOverhead";
- spaces = 10 - strlen(OverheadStr);
- output += OverheadStr;
-
- totalSize = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- size_t els = mElements[id];
- if (els) {
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = 0;
- if (overhead_[id]) {
- szs = *overhead_[id];
- } else if (track_total_size_) {
- szs = mSizes[id];
- } else {
- // Legacy fallback for Chatty without track_total_size_
- // Estimate the size of this element in the parent std::list<> by adding two void*'s
- // corresponding to the next/prev pointers and aligning to 64 bit.
- static const size_t overhead =
- (sizeof(LogBufferElement) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) &
- -sizeof(uint64_t);
- szs = mSizes[id] + els * overhead;
- }
- totalSize += szs;
- output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
- spaces -= output.length() - oldLength;
- }
- spaces += spaces_total;
- }
- totalSize += sizeOf();
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
-
- // Report on Chattiest
-
- std::string name;
-
- // Chattiest by application (UID)
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
- : "Logging for your UID in %s log buffer:";
- output += FormatTable(uidTable[id], uid, pid, name, id);
- }
-
- if (enable) {
- name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
- : "Logging for this PID:";
- output += FormatTable(pidTable, uid, pid, name);
- name = "Chattiest TIDs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tidTable, uid, pid, name);
- }
-
- if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
- name = "Chattiest events log buffer TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
- }
-
- if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
- name = "Chattiest security log buffer TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
- }
-
- if (enable) {
- name = "Chattiest TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tagNameTable, uid, pid, name);
- }
-
- return output;
-}
-
-namespace android {
-
-uid_t pidToUid(pid_t pid) {
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
- FILE* fp = fopen(buffer, "re");
- if (fp) {
- while (fgets(buffer, sizeof(buffer), fp)) {
- int uid = AID_LOGD;
- char space = 0;
- if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
- isspace(space)) {
- fclose(fp);
- return uid;
- }
- }
- fclose(fp);
- }
- return AID_LOGD; // associate this with the logger
-}
-}
-
-uid_t LogStatistics::PidToUid(pid_t pid) {
- auto lock = std::lock_guard{lock_};
- return pidTable.Add(pid)->second.uid();
-}
-
-// caller must free character string
-const char* LogStatistics::PidToName(pid_t pid) const {
- auto lock = std::lock_guard{lock_};
- // An inconvenient truth ... getName() can alter the object
- pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
- const char* name = writablePidTable.Add(pid)->second.name();
- if (!name) {
- return nullptr;
- }
- return strdup(name);
-}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
deleted file mode 100644
index faf9283..0000000
--- a/logd/LogStatistics.h
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Copyright (C) 2014 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 <ctype.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <algorithm> // std::max
-#include <array>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-#include <android/log.h>
-#include <log/log_time.h>
-#include <private/android_filesystem_config.h>
-#include <utils/FastStrcmp.h>
-
-#include "LogUtils.h"
-
-#define log_id_for_each(i) \
- for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
-
-class LogStatistics;
-class UidEntry;
-class PidEntry;
-
-struct LogStatisticsElement {
- uid_t uid;
- pid_t pid;
- pid_t tid;
- uint32_t tag;
- log_time realtime;
- const char* msg;
- uint16_t msg_len;
- uint16_t dropped_count;
- log_id_t log_id;
- uint16_t total_len;
-};
-
-template <typename TKey, typename TEntry>
-class LogHashtable {
- std::unordered_map<TKey, TEntry> map;
-
- size_t bucket_size() const {
- size_t count = 0;
- for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
- size_t bucket_size = map.bucket_size(idx);
- if (bucket_size == 0) bucket_size = 1;
- count += bucket_size;
- }
- float load_factor = map.max_load_factor();
- if (load_factor < 1.0) return count;
- return count * load_factor;
- }
-
- static const size_t unordered_map_per_entry_overhead = sizeof(void*);
- static const size_t unordered_map_bucket_overhead = sizeof(void*);
-
- public:
- size_t size() const {
- return map.size();
- }
-
- // Estimate unordered_map memory usage.
- size_t sizeOf() const {
- return sizeof(*this) +
- (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
- (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
- }
-
- typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
- typedef
- typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
-
- // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
- // entries are found, their positions are set to nullptr.
- template <size_t len>
- void MaxEntries(uid_t uid, pid_t pid, std::array<const TKey*, len>& out_keys,
- std::array<const TEntry*, len>& out_entries) const {
- out_keys.fill(nullptr);
- out_entries.fill(nullptr);
- for (const auto& [key, entry] : map) {
- uid_t entry_uid = 0;
- if constexpr (std::is_same_v<TEntry, UidEntry>) {
- entry_uid = key;
- } else {
- entry_uid = entry.uid();
- }
- if (uid != AID_ROOT && uid != entry_uid) {
- continue;
- }
- pid_t entry_pid = 0;
- if constexpr (std::is_same_v<TEntry, PidEntry>) {
- entry_pid = key;
- } else {
- entry_pid = entry.pid();
- }
- if (pid && entry_pid && pid != entry_pid) {
- continue;
- }
-
- size_t sizes = entry.getSizes();
- ssize_t index = len - 1;
- while ((!out_entries[index] || sizes > out_entries[index]->getSizes()) && --index >= 0)
- ;
- if (++index < (ssize_t)len) {
- size_t num = len - index - 1;
- if (num) {
- memmove(&out_keys[index + 1], &out_keys[index], num * sizeof(const TKey*));
- memmove(&out_entries[index + 1], &out_entries[index],
- num * sizeof(const TEntry*));
- }
- out_keys[index] = &key;
- out_entries[index] = &entry;
- }
- }
- }
-
- iterator Add(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it == map.end()) {
- it = map.insert(std::make_pair(key, TEntry(element))).first;
- } else {
- it->second.Add(element);
- }
- return it;
- }
-
- iterator Add(const TKey& key) {
- iterator it = map.find(key);
- if (it == map.end()) {
- it = map.insert(std::make_pair(key, TEntry(key))).first;
- } else {
- it->second.Add(key);
- }
- return it;
- }
-
- void Subtract(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end() && it->second.Subtract(element)) {
- map.erase(it);
- }
- }
-
- void Drop(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end()) {
- it->second.Drop(element);
- }
- }
-
- void Erase(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end()) {
- it->second.Erase(element);
- }
- }
-
- iterator begin() { return map.begin(); }
- const_iterator begin() const { return map.begin(); }
- iterator end() { return map.end(); }
- const_iterator end() const { return map.end(); }
-};
-
-class EntryBase {
- public:
- EntryBase() : size_(0) {}
- explicit EntryBase(const LogStatisticsElement& element) : size_(element.total_len) {}
-
- size_t getSizes() const { return size_; }
-
- void Add(const LogStatisticsElement& element) { size_ += element.total_len; }
- bool Subtract(const LogStatisticsElement& element) {
- size_ -= element.total_len;
- return size_ == 0;
- }
- void Drop(const LogStatisticsElement& element) { size_ -= element.msg_len; }
- void Erase(const LogStatisticsElement& element) { size_ -= element.total_len; }
-
- static constexpr size_t PRUNED_LEN = 14;
- static constexpr size_t TOTAL_LEN = 80;
-
- static std::string formatLine(const std::string& name,
- const std::string& size,
- const std::string& pruned) {
- ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
- ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
-
- std::string ret = android::base::StringPrintf(
- "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
- (int)drop_len, pruned.c_str());
- // remove any trailing spaces
- size_t pos = ret.size();
- size_t len = 0;
- while (pos && isspace(ret[--pos])) ++len;
- if (len) ret.erase(pos + 1, len);
- return ret + "\n";
- }
-
- private:
- size_t size_;
-};
-
-class EntryBaseDropped : public EntryBase {
- public:
- EntryBaseDropped() : dropped_(0) {}
- explicit EntryBaseDropped(const LogStatisticsElement& element)
- : EntryBase(element), dropped_(element.dropped_count) {}
-
- size_t dropped_count() const { return dropped_; }
-
- void Add(const LogStatisticsElement& element) {
- dropped_ += element.dropped_count;
- EntryBase::Add(element);
- }
- bool Subtract(const LogStatisticsElement& element) {
- dropped_ -= element.dropped_count;
- return EntryBase::Subtract(element) && dropped_ == 0;
- }
- void Drop(const LogStatisticsElement& element) {
- dropped_ += 1;
- EntryBase::Drop(element);
- }
-
- private:
- size_t dropped_;
-};
-
-class UidEntry : public EntryBaseDropped {
- public:
- explicit UidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), pid_(element.pid) {}
-
- pid_t pid() const { return pid_; }
-
- void Add(const LogStatisticsElement& element) {
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, uid_t uid) const;
-
- private:
- pid_t pid_;
-};
-
-namespace android {
-uid_t pidToUid(pid_t pid);
-}
-
-class PidEntry : public EntryBaseDropped {
- public:
- explicit PidEntry(pid_t pid)
- : EntryBaseDropped(),
- uid_(android::pidToUid(pid)),
- name_(android::pidToName(pid)) {}
- explicit PidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), uid_(element.uid), name_(android::pidToName(element.pid)) {}
- PidEntry(const PidEntry& element)
- : EntryBaseDropped(element),
- uid_(element.uid_),
- name_(element.name_ ? strdup(element.name_) : nullptr) {}
- ~PidEntry() { free(name_); }
-
- uid_t uid() const { return uid_; }
- const char* name() const { return name_; }
-
- void Add(pid_t new_pid) {
- if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
- free(name_);
- name_ = nullptr;
- }
- if (!name_) {
- name_ = android::pidToName(new_pid);
- }
- }
-
- void Add(const LogStatisticsElement& element) {
- uid_t incoming_uid = element.uid;
- if (uid() != incoming_uid) {
- uid_ = incoming_uid;
- free(name_);
- name_ = android::pidToName(element.pid);
- } else {
- Add(element.pid);
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
-
- private:
- uid_t uid_;
- char* name_;
-};
-
-class TidEntry : public EntryBaseDropped {
- public:
- TidEntry(pid_t tid, pid_t pid)
- : EntryBaseDropped(),
- pid_(pid),
- uid_(android::pidToUid(tid)),
- name_(android::tidToName(tid)) {}
- explicit TidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element),
- pid_(element.pid),
- uid_(element.uid),
- name_(android::tidToName(element.tid)) {}
- TidEntry(const TidEntry& element)
- : EntryBaseDropped(element),
- pid_(element.pid_),
- uid_(element.uid_),
- name_(element.name_ ? strdup(element.name_) : nullptr) {}
- ~TidEntry() { free(name_); }
-
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
- const char* name() const { return name_; }
-
- void Add(pid_t incomingTid) {
- if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
- free(name_);
- name_ = nullptr;
- }
- if (!name_) {
- name_ = android::tidToName(incomingTid);
- }
- }
-
- void Add(const LogStatisticsElement& element) {
- uid_t incoming_uid = element.uid;
- pid_t incoming_pid = element.pid;
- if (uid() != incoming_uid || pid() != incoming_pid) {
- uid_ = incoming_uid;
- pid_ = incoming_pid;
- free(name_);
- name_ = android::tidToName(element.tid);
- } else {
- Add(element.tid);
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
-
- private:
- pid_t pid_;
- uid_t uid_;
- char* name_;
-};
-
-class TagEntry : public EntryBaseDropped {
- public:
- explicit TagEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
-
- uint32_t key() const { return tag_; }
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
- const char* name() const { return android::tagToName(tag_); }
-
- void Add(const LogStatisticsElement& element) {
- if (uid_ != element.uid) {
- uid_ = -1;
- }
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, uint32_t) const;
-
- private:
- const uint32_t tag_;
- pid_t pid_;
- uid_t uid_;
-};
-
-class TagNameEntry : public EntryBase {
- public:
- explicit TagNameEntry(const LogStatisticsElement& element)
- : EntryBase(element), tid_(element.tid), pid_(element.pid), uid_(element.uid) {}
-
- pid_t tid() const { return tid_; }
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
-
- void Add(const LogStatisticsElement& element) {
- if (uid_ != element.uid) {
- uid_ = -1;
- }
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- if (tid_ != element.tid) {
- tid_ = -1;
- }
- EntryBase::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, const std::string& key_name) const;
-
- private:
- pid_t tid_;
- pid_t pid_;
- uid_t uid_;
-};
-
-class LogStatistics {
- friend UidEntry;
- friend PidEntry;
- friend TidEntry;
-
- size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
- static std::atomic<size_t> SizesTotal;
- bool enable;
-
- // uid to size list
- typedef LogHashtable<uid_t, UidEntry> uidTable_t;
- uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
-
- // pid of system to size list
- typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
- pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
-
- // pid to uid list
- typedef LogHashtable<pid_t, PidEntry> pidTable_t;
- pidTable_t pidTable GUARDED_BY(lock_);
-
- // tid to uid list
- typedef LogHashtable<pid_t, TidEntry> tidTable_t;
- tidTable_t tidTable GUARDED_BY(lock_);
-
- // tag list
- typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
- tagTable_t tagTable GUARDED_BY(lock_);
-
- // security tag list
- tagTable_t securityTagTable GUARDED_BY(lock_);
-
- // global tag list
- typedef LogHashtable<std::string, TagNameEntry> tagNameTable_t;
- tagNameTable_t tagNameTable;
-
- size_t sizeOf() const REQUIRES(lock_) {
- size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
- tagTable.sizeOf() + securityTagTable.sizeOf() +
- tagNameTable.sizeOf() +
- (pidTable.size() * sizeof(pidTable_t::iterator)) +
- (tagTable.size() * sizeof(tagTable_t::iterator));
- for (const auto& it : pidTable) {
- const char* name = it.second.name();
- if (name) size += strlen(name) + 1;
- }
- for (const auto& it : tidTable) {
- const char* name = it.second.name();
- if (name) size += strlen(name) + 1;
- }
- for (const auto& it : tagNameTable) {
- size += sizeof(std::string);
- size_t len = it.first.size();
- // Account for short string optimization: if the string's length is <= 22 bytes for 64
- // bit or <= 10 bytes for 32 bit, then there is no additional allocation.
- if ((sizeof(std::string) == 24 && len > 22) ||
- (sizeof(std::string) != 24 && len > 10)) {
- size += len;
- }
- }
- log_id_for_each(id) {
- size += uidTable[id].sizeOf();
- size += uidTable[id].size() * sizeof(uidTable_t::iterator);
- size += pidSystemTable[id].sizeOf();
- size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
- }
- return size;
- }
-
- public:
- 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_);
-
- // Add is for adding an element to the log buffer. It may be a chatty element in the case of
- // log deduplication. Add the total size of the element to statistics.
- void Add(LogStatisticsElement entry) EXCLUDES(lock_);
- // Subtract is for removing an element from the log buffer. It may be a chatty element.
- // Subtract the total size of the element from statistics.
- void Subtract(LogStatisticsElement entry) EXCLUDES(lock_);
- // Drop is for converting a normal element into a chatty element. entry->setDropped(1) must
- // follow this call. Subtract only msg_len from statistics, since a chatty element will remain.
- void Drop(LogStatisticsElement entry) EXCLUDES(lock_);
- // Erase is for coalescing two chatty elements into one. Erase() is called on the element that
- // is removed from the log buffer. Subtract the total size of the element, which is by
- // definition only the size of the LogBufferElement + list overhead for chatty elements.
- void Erase(LogStatisticsElement element) EXCLUDES(lock_);
-
- void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
- void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
- void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
-
- bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
- EXCLUDES(lock_);
-
- // Return the consumed size of the given buffer.
- size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
- auto lock = std::lock_guard{lock_};
- if (overhead_[id]) {
- return *overhead_[id];
- }
- return mSizes[id];
- }
-
- // Return the uncompressed size of the contents of the given buffer.
- size_t SizeReadable(log_id_t id) const EXCLUDES(lock_) {
- auto lock = std::lock_guard{lock_};
- return mSizes[id];
- }
-
- // TODO: Get rid of this entirely.
- static size_t sizesTotal() {
- 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_);
- uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
- const char* UidToName(uid_t uid) const EXCLUDES(lock_);
-
- void set_overhead(log_id_t id, size_t size) {
- auto lock = std::lock_guard{lock_};
- overhead_[id] = size;
- }
-
- private:
- template <typename TKey, typename TEntry>
- void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
- int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
- template <typename TKey, typename TEntry>
- std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
- const std::string& name = std::string(""),
- log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
- void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
- size_t nameLen) const REQUIRES(lock_);
- const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
-
- mutable std::mutex lock_;
- bool track_total_size_;
-
- std::optional<size_t> overhead_[LOG_ID_MAX] GUARDED_BY(lock_);
-};
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
deleted file mode 100644
index 6ab3b48..0000000
--- a/logd/LogTags.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * Copyright (C) 2017 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 <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/scopeguard.h>
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-#include <log/log_event_list.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogUtils.h"
-
-using android::base::make_scope_guard;
-
-static LogTags* logtags;
-
-const char LogTags::system_event_log_tags[] = "/system/etc/event-log-tags";
-const char LogTags::dynamic_event_log_tags[] = "/dev/event-log-tags";
-// Only for debug
-const char LogTags::debug_event_log_tags[] = "/data/misc/logd/event-log-tags";
-
-// Sniff for first uid=%d in utf8z comment string
-static uid_t sniffUid(const char* comment, const char* endp) {
- if (!comment) return AID_ROOT;
-
- if (*comment == '#') ++comment;
- while ((comment < endp) && (*comment != '\n') && isspace(*comment))
- ++comment;
- static const char uid_str[] = "uid=";
- if (((comment + strlen(uid_str)) >= endp) ||
- fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
- !isdigit(comment[strlen(uid_str)]))
- return AID_ROOT;
- char* cp;
- unsigned long Uid = strtoul(comment + 4, &cp, 10);
- if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
-
- return Uid;
-}
-
-// Checks for file corruption, and report false if there was no need
-// to rebuild the referenced file. Failure to rebuild is only logged,
-// does not cause a return value of false.
-bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
- int fd;
-
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- if (tag2total.begin() == tag2total.end()) {
- return false;
- }
-
- file2watermark_const_iterator iwater = file2watermark.find(filename);
- if (iwater == file2watermark.end()) {
- return false;
- }
-
- struct stat sb;
- if (!stat(filename, &sb) && ((size_t)sb.st_size >= iwater->second)) {
- return false;
- }
-
- // dump what we already know back into the file?
- fd = TEMP_FAILURE_RETRY(open(
- filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
- if (fd >= 0) {
- time_t now = time(nullptr);
- struct tm tm;
- localtime_r(&now, &tm);
- char timebuf[20];
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
- android::base::WriteStringToFd(
- android::base::StringPrintf(
- "# Rebuilt %.20s, content owned by logd\n", timebuf),
- fd);
- for (const auto& it : tag2total) {
- android::base::WriteStringToFd(
- formatEntry_locked(it.first, AID_ROOT), fd);
- }
- close(fd);
- }
- }
-
- if (warn) {
- if (fd < 0) {
- LOG(ERROR) << filename << " failed to rebuild";
- } else {
- LOG(ERROR) << filename << " missing, damaged or truncated; rebuilt";
- }
- }
-
- if (fd >= 0) {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- struct stat sb;
- if (!stat(filename, &sb)) file2watermark[filename] = sb.st_size;
- }
-
- return true;
-}
-
-void LogTags::AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source,
- bool warn) {
- std::string Key = Name;
- if (Format.length()) Key += "+" + Format;
-
- bool update = !source || !!strcmp(source, system_event_log_tags);
- bool newOne;
-
- {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
-
- // unlikely except for dupes, or updates to uid list (more later)
- if (itot != tag2total.end()) update = false;
-
- newOne = tag2name.find(tag) == tag2name.end();
- key2tag[Key] = tag;
-
- if (Format.length()) {
- if (key2tag.find(Name) == key2tag.end()) {
- key2tag[Name] = tag;
- }
- tag2format[tag] = Format;
- }
- tag2name[tag] = Name;
-
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut != tag2uid.end()) {
- if (uid == AID_ROOT) {
- tag2uid.erase(ut);
- update = true;
- } else if (ut->second.find(uid) == ut->second.end()) {
- const_cast<uid_list&>(ut->second).emplace(uid);
- update = true;
- }
- } else if (newOne && (uid != AID_ROOT)) {
- tag2uid[tag].emplace(uid);
- update = true;
- }
-
- // updatePersist -> trigger output on modified
- // content, reset tag2total if available
- if (update && (itot != tag2total.end())) tag2total[tag] = 0;
- }
-
- if (update) {
- WritePersistEventLogTags(tag, uid, source);
- } else if (warn && !newOne && source) {
- // For the files, we want to report dupes.
- LOG(DEBUG) << "Multiple tag " << tag << " " << Name << " " << Format << " " << source;
- }
-}
-
-// Read the event log tags file, and build up our internal database
-void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
- bool etc = !strcmp(filename, system_event_log_tags);
-
- if (!etc) {
- RebuildFileEventLogTags(filename, warn);
- }
- std::string content;
- if (android::base::ReadFileToString(filename, &content)) {
- char* cp = (char*)content.c_str();
- char* endp = cp + content.length();
-
- {
- android::RWLock::AutoRLock writeLock(rwlock);
-
- file2watermark[filename] = content.length();
- }
-
- char* lineStart = cp;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = cp;
- } else if (lineStart) {
- if (*cp == '#') {
- /* comment; just scan to end */
- lineStart = nullptr;
- } else if (isdigit(*cp)) {
- unsigned long Tag = strtoul(cp, &cp, 10);
- if (warn && (Tag > emptyTag)) {
- LOG(WARNING) << "tag too large " << Tag;
- }
- while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
- if (cp >= endp) break;
- if (*cp == '\n') continue;
- const char* name = cp;
- /* Determine whether it is a valid tag name [a-zA-Z0-9_] */
- bool hasAlpha = false;
- while ((cp < endp) && (isalnum(*cp) || (*cp == '_'))) {
- if (!isdigit(*cp)) hasAlpha = true;
- ++cp;
- }
- std::string Name(name, cp - name);
-#ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
- static const size_t maximum_official_tag_name_size = 24;
- if (warn && (Name.length() > maximum_official_tag_name_size)) {
- LOG(WARNING) << "tag name too long " << Name;
- }
-#endif
- if (hasAlpha &&
- ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
- if (Tag > emptyTag) {
- if (*cp != '\n') lineStart = nullptr;
- continue;
- }
- while ((cp < endp) && (*cp != '\n') && isspace(*cp))
- ++cp;
- const char* format = cp;
- uid_t uid = AID_ROOT;
- while ((cp < endp) && (*cp != '\n')) {
- if (*cp == '#') {
- uid = sniffUid(cp, endp);
- lineStart = nullptr;
- break;
- }
- ++cp;
- }
- while ((cp > format) && isspace(cp[-1])) {
- --cp;
- lineStart = nullptr;
- }
- std::string Format(format, cp - format);
-
- AddEventLogTags((uint32_t)Tag, uid, Name, Format,
- filename, warn);
- } else {
- if (warn) {
- LOG(ERROR) << android::base::StringPrintf("tag name invalid %.*s",
- (int)(cp - name + 1), name);
- }
- lineStart = nullptr;
- }
- } else if (!isspace(*cp)) {
- break;
- }
- }
- cp++;
- }
- } else if (warn) {
-#ifdef __ANDROID__
- LOG(ERROR) << "Cannot read " << filename;
-#endif
- }
-}
-
-// Extract a 4-byte value from a byte stream.
-static inline uint32_t get4LE(const char* msg) {
- const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
-
-// Additional persistent sources for invented log tags. Read the
-// special pmsg event for log tags, and build up our internal
-// database with any found.
-void LogTags::ReadPersistEventLogTags() {
- struct logger_list* logger_list =
- android_logger_list_alloc(ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0, (pid_t)0);
- if (!logger_list) return;
-
- struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
- struct logger* s = android_logger_open(logger_list, LOG_ID_SECURITY);
- if (!e && !s) {
- android_logger_list_free(logger_list);
- return;
- }
-
- for (;;) {
- struct log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- if (ret <= 0) break;
-
- const char* msg = log_msg.msg();
- if (!msg) continue;
- if (log_msg.entry.len <= sizeof(uint32_t)) continue;
- uint32_t Tag = get4LE(msg);
- if (Tag != TAG_DEF_LOG_TAG) continue;
- uid_t uid = log_msg.entry.uid;
-
- std::string Name;
- std::string Format;
- android_log_list_element elem;
- {
- auto ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_LIST) {
- continue;
- }
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_INT) {
- continue;
- }
- Tag = elem.data.int32;
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_STRING) {
- continue;
- }
- Name = std::string(elem.data.string, elem.len);
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_STRING) {
- continue;
- }
- Format = std::string(elem.data.string, elem.len);
- elem = android_log_read_next(ctx);
- }
- if ((elem.type != EVENT_TYPE_LIST_STOP) || !elem.complete) continue;
-
- AddEventLogTags(Tag, uid, Name, Format);
- }
- android_logger_list_free(logger_list);
-}
-
-LogTags::LogTags() {
- ReadFileEventLogTags(system_event_log_tags);
- // Following will likely fail on boot, but is required if logd restarts
- ReadFileEventLogTags(dynamic_event_log_tags, false);
- if (__android_log_is_debuggable()) {
- ReadFileEventLogTags(debug_event_log_tags, false);
- }
- ReadPersistEventLogTags();
-
- logtags = this;
-}
-
-// Converts an event tag into a name
-const char* LogTags::tagToName(uint32_t tag) const {
- tag2name_const_iterator it;
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- it = tag2name.find(tag);
- if ((it == tag2name.end()) || (it->second.length() == 0)) return nullptr;
-
- return it->second.c_str();
-}
-
-// Prototype in LogUtils.h allowing external access to our database.
-//
-// This must be a pure reader to our database, as everything else is
-// guaranteed single-threaded except this access point which is
-// asynchonous and can be multithreaded and thus rentrant. The
-// object's rwlock is only used to guarantee atomic access to the
-// unordered_map to prevent corruption, with a requirement to be a
-// low chance of contention for this call. If we end up changing
-// this algorithm resulting in write, then we should use a different
-// lock than the object's rwlock to protect groups of associated
-// actions.
-const char* android::tagToName(uint32_t tag) {
- LogTags* me = logtags;
-
- if (!me) return nullptr;
- me->WritePmsgEventLogTags(tag);
- return me->tagToName(tag);
-}
-
-// converts an event tag into a format
-const char* LogTags::tagToFormat(uint32_t tag) const {
- tag2format_const_iterator iform;
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- iform = tag2format.find(tag);
- if (iform == tag2format.end()) return nullptr;
-
- return iform->second.c_str();
-}
-
-// converts a name into an event tag
-uint32_t LogTags::nameToTag(const char* name) const {
- uint32_t ret = emptyTag;
-
- // Bug: Only works for a single entry, we can have multiple entries,
- // one for each format, so we find first entry recorded, or entry with
- // no format associated with it.
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- key2tag_const_iterator ik = key2tag.find(std::string(name));
- if (ik != key2tag.end()) ret = ik->second;
-
- return ret;
-}
-
-// Caller must perform locks, can be under reader (for pre-check) or
-// writer lock. We use this call to invent a new deterministically
-// random tag, unique is cleared if no conflicts. If format is NULL,
-// we are in readonly mode.
-uint32_t LogTags::nameToTag_locked(const std::string& name, const char* format,
- bool& unique) {
- key2tag_const_iterator ik;
-
- bool write = format != nullptr;
- unique = write;
-
- if (!write) {
- // Bug: Only works for a single entry, we can have multiple entries,
- // one for each format, so we find first entry recorded, or entry with
- // no format associated with it.
- ik = key2tag.find(name);
- if (ik == key2tag.end()) return emptyTag;
- return ik->second;
- }
-
- std::string Key(name);
- if (*format) Key += std::string("+") + format;
-
- ik = key2tag.find(Key);
- if (ik != key2tag.end()) {
- unique = false;
- return ik->second;
- }
-
- size_t Hash = key2tag.hash_function()(Key);
- uint32_t Tag = Hash;
- // This sets an upper limit on the conflics we are allowed to deal with.
- for (unsigned i = 0; i < 256;) {
- tag2name_const_iterator it = tag2name.find(Tag);
- if (it == tag2name.end()) return Tag;
- std::string localKey(it->second);
- tag2format_const_iterator iform = tag2format.find(Tag);
- if ((iform == tag2format.end()) && iform->second.length()) {
- localKey += "+" + iform->second;
- }
- unique = !!it->second.compare(localKey);
- if (!unique) return Tag; // unlikely except in a race
-
- ++i;
- // Algorithm to convert hash to next tag
- if (i < 32) {
- Tag = (Hash >> i);
- // size_t is 32 bits, or upper word zero, rotate
- if ((sizeof(Hash) <= 4) || ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
- Tag |= Hash << (32 - i);
- }
- } else {
- Tag = Hash + i - 31;
- }
- }
- return emptyTag;
-}
-
-static int openFile(const char* name, int mode, bool warning) {
- int fd = TEMP_FAILURE_RETRY(open(name, mode));
- if (fd < 0 && warning) {
- PLOG(ERROR) << "Failed to open " << name;
- }
- return fd;
-}
-
-void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
- android::RWLock::AutoRLock readLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
- if (itot == tag2total.end()) return; // source is a static entry
-
- size_t lastTotal = itot->second;
-
- // Every 16K (half the smallest configurable pmsg buffer size) record
- static const size_t rate_to_pmsg = 16 * 1024;
- if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
- return;
- }
-
- static int pmsg_fd = -1;
- if (pmsg_fd < 0) {
- pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- // unlikely, but deal with partners with borken pmsg
- if (pmsg_fd < 0) return;
- }
-
- std::string Name = tag2name[tag];
- tag2format_const_iterator iform = tag2format.find(tag);
- std::string Format = (iform != tag2format.end()) ? iform->second : "";
-
- auto ctx = create_android_logger(TAG_DEF_LOG_TAG);
- auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
- if (android_log_write_int32(ctx, static_cast<int32_t>(tag) < 0) ||
- android_log_write_string8_len(ctx, Name.c_str(), Name.size()) < 0 ||
- android_log_write_string8_len(ctx, Format.c_str(), Format.size()) < 0) {
- return;
- }
-
- const char* cp = nullptr;
- ssize_t len = android_log_write_list_buffer(ctx, &cp);
-
- if (len <= 0 || cp == nullptr) {
- return;
- }
-
- std::string buffer(cp, len);
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsgHeader;
- * // what we provide to file
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- android_log_header_t header = {
- .id = LOG_ID_EVENTS,
- .tid = static_cast<uint16_t>(android::base::GetThreadId()),
- .realtime.tv_sec = static_cast<uint32_t>(ts.tv_sec),
- .realtime.tv_nsec = static_cast<uint32_t>(ts.tv_nsec),
- };
-
- uint32_t outTag = TAG_DEF_LOG_TAG;
- outTag = get4LE((const char*)&outTag);
-
- android_pmsg_log_header_t pmsgHeader = {
- .magic = LOGGER_MAGIC,
- .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) + sizeof(outTag) +
- buffer.length()),
- .uid = (uint16_t)AID_ROOT,
- .pid = (uint16_t)getpid(),
- };
-
- struct iovec Vec[] = { { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
- { (unsigned char*)&header, sizeof(header) },
- { (unsigned char*)&outTag, sizeof(outTag) },
- { (unsigned char*)const_cast<char*>(buffer.data()),
- buffer.length() } };
-
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut == tag2uid.end()) {
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- } else if (uid != AID_ROOT) {
- pmsgHeader.uid = (uint16_t)uid;
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- } else {
- for (auto& it : ut->second) {
- pmsgHeader.uid = (uint16_t)it;
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- }
- }
-}
-
-void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode =
- O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
-
- int fd = openFile(dynamic_event_log_tags, mode, true);
- if (fd < 0) return;
-
- android::RWLock::AutoWLock writeLock(rwlock);
-
- std::string ret = formatEntry_locked(tag, uid, false);
- android::base::WriteStringToFd(ret, fd);
- close(fd);
-
- size_t size = 0;
- file2watermark_const_iterator iwater;
-
- iwater = file2watermark.find(dynamic_event_log_tags);
- if (iwater != file2watermark.end()) size = iwater->second;
-
- file2watermark[dynamic_event_log_tags] = size + ret.length();
-}
-
-void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode =
- O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
-
- static bool one = true;
- int fd = openFile(debug_event_log_tags, mode, one);
- one = fd >= 0;
- if (!one) return;
-
- android::RWLock::AutoWLock writeLock(rwlock);
-
- std::string ret = formatEntry_locked(tag, uid, false);
- android::base::WriteStringToFd(ret, fd);
- close(fd);
-
- size_t size = 0;
- file2watermark_const_iterator iwater;
-
- iwater = file2watermark.find(debug_event_log_tags);
- if (iwater != file2watermark.end()) size = iwater->second;
-
- file2watermark[debug_event_log_tags] = size + ret.length();
-}
-
-// How we maintain some runtime or reboot stickiness
-void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
- const char* source) {
- // very unlikely
- bool etc = source && !strcmp(source, system_event_log_tags);
- if (etc) return;
-
- bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
- bool debug = (!dynamic && source && !strcmp(source, debug_event_log_tags)) ||
- !__android_log_is_debuggable();
-
- WritePmsgEventLogTags(tag, uid);
-
- size_t lastTotal = 0;
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
- if (itot != tag2total.end()) lastTotal = itot->second;
- }
-
- if (lastTotal == 0) { // denotes first time for this one
- if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
- WriteDynamicEventLogTags(tag, uid);
- }
-
- if (!debug && !RebuildFileEventLogTags(debug_event_log_tags)) {
- WriteDebugEventLogTags(tag, uid);
- }
- }
-
- lastTotal = LogStatistics::sizesTotal();
- if (!lastTotal) ++lastTotal;
-
- // record totals for next watermark.
- android::RWLock::AutoWLock writeLock(rwlock);
- tag2total[tag] = lastTotal;
-}
-
-// nameToTag converts a name into an event tag. If format is NULL, then we
-// are in readonly mode.
-uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
- std::string Name = std::string(name);
- bool write = format != nullptr;
- bool updateUid = uid != AID_ROOT;
- bool updateFormat = format && *format;
- bool unique;
- uint32_t Tag;
-
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- Tag = nameToTag_locked(Name, format, unique);
- if (updateUid && (Tag != emptyTag) && !unique) {
- tag2uid_const_iterator ut = tag2uid.find(Tag);
- if (updateUid) {
- if ((ut != tag2uid.end()) &&
- (ut->second.find(uid) == ut->second.end())) {
- unique = write; // write passthrough to update uid counts
- if (!write) Tag = emptyTag; // deny read access
- }
- } else {
- unique = write && (ut != tag2uid.end());
- }
- }
- }
-
- if (Tag == emptyTag) return Tag;
- WritePmsgEventLogTags(Tag, uid); // record references periodically
- if (!unique) return Tag;
-
- bool updateWrite = false;
- bool updateTag;
-
- // Special case of AddEventLogTags, checks per-uid counter which makes
- // no sense there, and is also optimized somewhat to reduce write times.
- {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- // double check after switch from read lock to write lock for Tag
- updateTag = tag2name.find(Tag) == tag2name.end();
- // unlikely, either update, race inviting conflict or multiple uids
- if (!updateTag) {
- Tag = nameToTag_locked(Name, format, unique);
- if (Tag == emptyTag) return Tag;
- // is it multiple uid's setting this value
- if (!unique) {
- tag2uid_const_iterator ut = tag2uid.find(Tag);
- if (updateUid) {
- // Add it to the uid list
- if ((ut == tag2uid.end()) ||
- (ut->second.find(uid) != ut->second.end())) {
- return Tag;
- }
- const_cast<uid_list&>(ut->second).emplace(uid);
- updateWrite = true;
- } else {
- if (ut == tag2uid.end()) return Tag;
- // (system) adding a global one, erase the uid list
- tag2uid.erase(ut);
- updateWrite = true;
- }
- }
- }
-
- // Update section
- size_t count;
- if (updateUid) {
- count = 0;
- uid2count_const_iterator ci = uid2count.find(uid);
- if (ci != uid2count.end()) {
- count = ci->second;
- if (count >= max_per_uid) {
- if (!updateWrite) return emptyTag;
- // If we are added to the per-Uid perms, leak the Tag
- // if it already exists.
- updateUid = false;
- updateTag = false;
- updateFormat = false;
- }
- }
- }
-
- // updateWrite -> trigger output on modified content, reset tag2total
- // also sets static to dynamic entries if they are alterred,
- // only occurs if they have a uid, and runtime adds another uid.
- if (updateWrite) tag2total[Tag] = 0;
-
- if (updateTag) {
- // mark as a dynamic entry, but do not upset current total counter
- tag2total_const_iterator itot = tag2total.find(Tag);
- if (itot == tag2total.end()) tag2total[Tag] = 0;
-
- if (*format) {
- key2tag[Name + "+" + format] = Tag;
- if (key2tag.find(Name) == key2tag.end()) key2tag[Name] = Tag;
- } else {
- key2tag[Name] = Tag;
- }
- tag2name[Tag] = Name;
- }
- if (updateFormat) tag2format[Tag] = format;
-
- if (updateUid) {
- tag2uid[Tag].emplace(uid);
- uid2count[uid] = count + 1;
- }
- }
-
- if (updateTag || updateFormat || updateWrite) {
- WritePersistEventLogTags(Tag, uid);
- }
-
- return Tag;
-}
-
-std::string LogTags::formatEntry(uint32_t tag, uid_t uid, const char* name,
- const char* format) {
- if (!format || !format[0]) {
- return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
- }
- size_t len = (strlen(name) + 7) / 8;
- static const char tabs[] = "\t\t\t";
- if (len > strlen(tabs)) len = strlen(tabs);
- std::string Uid;
- if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
- return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n", tag, name,
- &tabs[len], format, Uid.c_str());
-}
-
-std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
- bool authenticate) {
- const char* name = tag2name[tag].c_str();
-
- const char* format = "";
- tag2format_const_iterator iform = tag2format.find(tag);
- if (iform != tag2format.end()) format = iform->second.c_str();
-
- // Access permission test, do not report dynamic entries
- // that do not belong to us.
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut == tag2uid.end()) {
- return formatEntry(tag, AID_ROOT, name, format);
- }
- if (uid != AID_ROOT) {
- if (authenticate && (ut->second.find(uid) == ut->second.end())) {
- return std::string("");
- }
- return formatEntry(tag, uid, name, format);
- }
-
- // Show all, one for each registered uid (we are group root)
- std::string ret;
- for (auto& it : ut->second) {
- ret += formatEntry(tag, it, name, format);
- }
- return ret;
-}
-
-std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
- android::RWLock::AutoRLock readLock(rwlock);
- return formatEntry_locked(tag, uid);
-}
-
-std::string LogTags::formatGetEventTag(uid_t uid, const char* name,
- const char* format) {
- bool all = name && (name[0] == '*') && !name[1];
- bool list = !name || all;
- std::string ret;
-
- if (!list) {
- // switch to read entry only if format == "*"
- if (format && (format[0] == '*') && !format[1]) format = nullptr;
-
- // WAI: for null format, only works for a single entry, we can have
- // multiple entries, one for each format, so we find first entry
- // recorded, or entry with no format associated with it.
- // We may desire to print all that match the name, but we did not
- // add a mapping table for that and the cost is too high.
- uint32_t tag = nameToTag(uid, name, format);
- if (tag == emptyTag) return std::string("-1 ESRCH");
- if (uid == AID_ROOT) {
- android::RWLock::AutoRLock readLock(rwlock);
-
- // first uid in list so as to manufacture an accurate reference
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if ((ut != tag2uid.end()) &&
- (ut->second.begin() != ut->second.end())) {
- uid = *(ut->second.begin());
- }
- }
- ret = formatEntry(tag, uid, name, format ?: tagToFormat(tag));
- if (!ret.length()) return std::string("-1 ESRCH");
- return ret;
- }
-
- android::RWLock::AutoRLock readLock(rwlock);
- if (all) {
- // everything under the sun
- for (const auto& it : tag2name) {
- ret += formatEntry_locked(it.first, uid);
- }
- } else {
- // set entries are dynamic
- for (const auto& it : tag2total) {
- ret += formatEntry_locked(it.first, uid);
- }
- }
- return ret;
-}
diff --git a/logd/LogTags.h b/logd/LogTags.h
deleted file mode 100644
index cce700c..0000000
--- a/logd/LogTags.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string>
-#include <unordered_map>
-#include <unordered_set>
-
-#include <private/android_filesystem_config.h>
-#include <utils/RWLock.h>
-
-class LogTags {
- // This lock protects all the unordered_map accesses below. It
- // is a reader/writer lock so that contentions are kept to a
- // minimum since writes are rare, even administratably when
- // reads are extended. Resist the temptation to use the writer
- // lock to protect anything outside the following unordered_maps
- // as that would increase the reader contentions. Use a separate
- // mutex to protect the other entities.
- android::RWLock rwlock;
-
- // key is Name + "+" + Format
- std::unordered_map<std::string, uint32_t> key2tag;
- typedef std::unordered_map<std::string, uint32_t>::const_iterator
- key2tag_const_iterator;
-
- // Allows us to manage access permissions based on uid registrants
- // Global entries are specifically erased.
- typedef std::unordered_set<uid_t> uid_list;
- std::unordered_map<uint32_t, uid_list> tag2uid;
- typedef std::unordered_map<uint32_t, uid_list>::const_iterator
- tag2uid_const_iterator;
-
- std::unordered_map<uint32_t, std::string> tag2name;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator
- tag2name_const_iterator;
-
- std::unordered_map<uint32_t, std::string> tag2format;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator
- tag2format_const_iterator;
-
- static const size_t max_per_uid = 256; // Put a cap on the tags per uid
- std::unordered_map<uid_t, size_t> uid2count;
- typedef std::unordered_map<uid_t, size_t>::const_iterator
- uid2count_const_iterator;
-
- // Dynamic entries are assigned
- std::unordered_map<uint32_t, size_t> tag2total;
- typedef std::unordered_map<uint32_t, size_t>::const_iterator
- tag2total_const_iterator;
-
- // emplace unique tag
- uint32_t nameToTag(uid_t uid, const char* name, const char* format);
- // find unique or associated tag
- uint32_t nameToTag_locked(const std::string& name, const char* format,
- bool& unique);
-
- // Record expected file watermarks to detect corruption.
- std::unordered_map<std::string, size_t> file2watermark;
- typedef std::unordered_map<std::string, size_t>::const_iterator
- file2watermark_const_iterator;
-
- void ReadPersistEventLogTags();
-
- // format helpers
- // format a single entry, does not need object data
- static std::string formatEntry(uint32_t tag, uid_t uid, const char* name,
- const char* format);
- // caller locks, database lookup, authenticate against uid
- std::string formatEntry_locked(uint32_t tag, uid_t uid,
- bool authenticate = true);
-
- bool RebuildFileEventLogTags(const char* filename, bool warn = true);
-
- void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source = nullptr,
- bool warn = false);
-
- void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
- void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
- // push tag details to persistent storage
- void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
- const char* source = nullptr);
-
- static const uint32_t emptyTag = uint32_t(-1);
-
- public:
- static const char system_event_log_tags[];
- static const char dynamic_event_log_tags[];
- // Only for userdebug and eng
- static const char debug_event_log_tags[];
-
- LogTags();
-
- void WritePmsgEventLogTags(uint32_t tag, uid_t uid = AID_ROOT);
- void ReadFileEventLogTags(const char* filename, bool warn = true);
-
- // reverse lookup from tag
- const char* tagToName(uint32_t tag) const;
- const char* tagToFormat(uint32_t tag) const;
- std::string formatEntry(uint32_t tag, uid_t uid);
- // find associated tag
- uint32_t nameToTag(const char* name) const;
-
- // emplace tag if necessary, provide event-log-tag formated output in string
- std::string formatGetEventTag(uid_t uid, const char* name,
- const char* format);
-};
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
deleted file mode 100644
index c0f62d3..0000000
--- a/logd/LogUtils.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012-2015 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 <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <private/android_logger.h>
-#include <utils/FastStrcmp.h>
-
-// Hijack this header as a common include file used by most all sources
-// to report some utilities defined here and there.
-
-#define LOGD_SNDTIMEO 32
-
-namespace android {
-
-// Furnished in main.cpp. Caller must own and free returned value
-char* uidToName(uid_t uid);
-
-// Caller must own and free returned value
-char* pidToName(pid_t pid);
-char* tidToName(pid_t tid);
-
-// Furnished in LogTags.cpp. Thread safe.
-const char* tagToName(uint32_t tag);
-
-// Furnished by LogKlog.cpp
-char* log_strntok_r(char* s, ssize_t& len, char*& saveptr, ssize_t& sublen);
-
-// needle should reference a string longer than 1 character
-static inline const char* strnstr(const char* s, ssize_t len,
- const char* needle) {
- if (len <= 0) return nullptr;
-
- const char c = *needle++;
- const size_t needleLen = strlen(needle);
- do {
- do {
- if (len <= (ssize_t)needleLen) return nullptr;
- --len;
- } while (*s++ != c);
- } while (fastcmp<memcmp>(s, needle, needleLen));
- s--;
- return s;
-}
-}
-
-// Returns true if the log buffer is meant for binary logs.
-static inline bool IsBinary(log_id_t log_id) {
- return log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY;
-}
-
-// Returns the numeric log tag for binary log messages.
-static inline uint32_t MsgToTag(const char* msg, uint16_t msg_len) {
- if (msg_len < sizeof(android_event_header_t)) {
- return 0;
- }
-
- return reinterpret_cast<const android_event_header_t*>(msg)->tag;
-}
-
-static inline bool worstUidEnabledForLogid(log_id_t id) {
- return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
- (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
-}
diff --git a/logd/LogWriter.h b/logd/LogWriter.h
deleted file mode 100644
index d43c604..0000000
--- a/logd/LogWriter.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 <string>
-
-#include <log/log_read.h>
-
-// An interface for writing logs to a reader.
-class LogWriter {
- public:
- LogWriter(uid_t uid, bool privileged) : uid_(uid), privileged_(privileged) {}
- virtual ~LogWriter() {}
-
- virtual bool Write(const logger_entry& entry, const char* msg) = 0;
- virtual void Shutdown() {}
- virtual void Release() {}
-
- virtual std::string name() const = 0;
- uid_t uid() const { return uid_; }
-
- bool privileged() const { return privileged_; }
-
- private:
- uid_t uid_;
-
- // If this writer sees logs from all UIDs or only its own UID. See clientHasLogCredentials().
- bool privileged_;
-};
\ No newline at end of file
diff --git a/logd/LogdLock.cpp b/logd/LogdLock.cpp
deleted file mode 100644
index 16a37a5..0000000
--- a/logd/LogdLock.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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/LICENSE2.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 "LogdLock.h"
-
-std::mutex logd_lock;
diff --git a/logd/LogdLock.h b/logd/LogdLock.h
deleted file mode 100644
index 6f637c8..0000000
--- a/logd/LogdLock.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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/LICENSE2.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 <mutex>
-
-extern std::mutex logd_lock;
diff --git a/logd/OWNERS b/logd/OWNERS
deleted file mode 100644
index 2394e32..0000000
--- a/logd/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-cferris@google.com
-tomcherry@google.com
diff --git a/logd/PruneList.cpp b/logd/PruneList.cpp
deleted file mode 100644
index c3859f3..0000000
--- a/logd/PruneList.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2014 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 "PruneList.h"
-
-#include <ctype.h>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-bool Prune::Matches(LogBufferElement* element) const {
- return (uid_ == UID_ALL || uid_ == element->uid()) &&
- (pid_ == PID_ALL || pid_ == element->pid());
-}
-
-std::string Prune::Format() const {
- if (uid_ != UID_ALL) {
- if (pid_ != PID_ALL) {
- return android::base::StringPrintf("%u/%u", uid_, pid_);
- }
- return android::base::StringPrintf("%u", uid_);
- }
- if (pid_ != PID_ALL) {
- return android::base::StringPrintf("/%u", pid_);
- }
- // NB: pid_ == PID_ALL can not happen if uid_ == UID_ALL
- return std::string("/");
-}
-
-PruneList::PruneList() {
- Init(nullptr);
-}
-
-bool PruneList::Init(const char* str) {
- high_priority_prune_.clear();
- low_priority_prune_.clear();
-
- // default here means take ro.logd.filter, persist.logd.filter then internal default in order.
- if (str && !strcmp(str, "default")) {
- str = nullptr;
- }
- if (str && !strcmp(str, "disable")) {
- str = "";
- }
-
- std::string filter;
-
- if (str) {
- filter = str;
- } else {
- filter = android::base::GetProperty("ro.logd.filter", "default");
- auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
- // default here means take ro.logd.filter
- if (persist_filter != "default") {
- filter = persist_filter;
- }
- }
-
- // default here means take internal default.
- if (filter == "default") {
- filter = "~! ~1000/!";
- }
- if (filter == "disable") {
- filter = "";
- }
-
- worst_uid_enabled_ = false;
- worst_pid_of_system_enabled_ = false;
-
- for (str = filter.c_str(); *str; ++str) {
- if (isspace(*str)) {
- continue;
- }
-
- std::list<Prune>* list;
- if (*str == '~' || *str == '!') { // ~ supported, ! undocumented
- ++str;
- // special case, prune the worst UID of those using at least 1/8th of the buffer.
- if (*str == '!') {
- worst_uid_enabled_ = true;
- ++str;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- LOG(ERROR) << "Nothing expected after '~!', but found '" << str << "'";
- return false;
- }
- continue;
- }
- // special case, translated to worst PID of System at priority
- static const char WORST_SYSTEM_PID[] = "1000/!";
- if (!strncmp(str, WORST_SYSTEM_PID, sizeof(WORST_SYSTEM_PID) - 1)) {
- worst_pid_of_system_enabled_ = true;
- str += sizeof(WORST_SYSTEM_PID) - 1;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- LOG(ERROR) << "Nothing expected after '~1000/!', but found '" << str << "'";
- return false;
- }
- continue;
- }
- if (!*str) {
- LOG(ERROR) << "Expected UID or PID after '~', but found nothing";
- return false;
- }
- list = &high_priority_prune_;
- } else {
- list = &low_priority_prune_;
- }
-
- uid_t uid = Prune::UID_ALL;
- if (isdigit(*str)) {
- uid = 0;
- do {
- uid = uid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
-
- pid_t pid = Prune::PID_ALL;
- if (*str == '/') {
- ++str;
- if (isdigit(*str)) {
- pid = 0;
- do {
- pid = pid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
- }
-
- if (uid == Prune::UID_ALL && pid == Prune::PID_ALL) {
- LOG(ERROR) << "Expected UID/PID combination, but found none";
- return false;
- }
-
- if (*str && !isspace(*str)) {
- LOG(ERROR) << "Nothing expected after UID/PID combination, but found '" << str << "'";
- return false;
- }
-
- list->emplace_back(uid, pid);
- if (!*str) {
- break;
- }
- }
-
- return true;
-}
-
-std::string PruneList::Format() const {
- std::vector<std::string> prune_rules;
-
- if (worst_uid_enabled_) {
- prune_rules.emplace_back("~!");
- }
- if (worst_pid_of_system_enabled_) {
- prune_rules.emplace_back("~1000/!");
- }
- for (const auto& rule : low_priority_prune_) {
- prune_rules.emplace_back(rule.Format());
- }
- for (const auto& rule : high_priority_prune_) {
- prune_rules.emplace_back("~" + rule.Format());
- }
- return android::base::Join(prune_rules, " ");
-}
-
-bool PruneList::IsHighPriority(LogBufferElement* element) const {
- for (const auto& rule : high_priority_prune_) {
- if (rule.Matches(element)) {
- return true;
- }
- }
- return false;
-}
-
-bool PruneList::IsLowPriority(LogBufferElement* element) const {
- for (const auto& rule : low_priority_prune_) {
- if (rule.Matches(element)) {
- return true;
- }
- }
- return false;
-}
diff --git a/logd/PruneList.h b/logd/PruneList.h
deleted file mode 100644
index 94de5c5..0000000
--- a/logd/PruneList.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 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 <sys/types.h>
-
-#include <string.h>
-#include <list>
-
-#include "LogBufferElement.h"
-
-class Prune {
- public:
- static const uid_t UID_ALL = (uid_t)-1;
- static const pid_t PID_ALL = (pid_t)-1;
-
- Prune(uid_t uid, pid_t pid) : uid_(uid), pid_(pid) {}
-
- bool Matches(LogBufferElement* element) const;
- std::string Format() const;
-
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
-
- private:
- const uid_t uid_;
- const pid_t pid_;
-};
-
-class PruneList {
- public:
- PruneList();
-
- bool Init(const char* str);
- std::string Format() const;
-
- bool IsHighPriority(LogBufferElement* element) const;
- bool IsLowPriority(LogBufferElement* element) const;
-
- bool HasHighPriorityPruneRules() const { return !high_priority_prune_.empty(); }
- bool HasLowPriorityPruneRules() const { return !low_priority_prune_.empty(); }
-
- bool worst_uid_enabled() const { return worst_uid_enabled_; }
- bool worst_pid_of_system_enabled() const { return worst_pid_of_system_enabled_; }
-
- private:
- std::list<Prune> high_priority_prune_;
- std::list<Prune> low_priority_prune_;
-
- bool worst_uid_enabled_;
- bool worst_pid_of_system_enabled_;
-};
diff --git a/logd/README.auditd b/logd/README.auditd
deleted file mode 100644
index 3f614a3..0000000
--- a/logd/README.auditd
+++ /dev/null
@@ -1,17 +0,0 @@
-Auditd Daemon
-
-The audit daemon is a simplified version of its desktop
-counterpart designed to gather the audit logs from the
-audit kernel subsystem. The audit subsystem of the kernel
-includes Linux Security Modules (LSM) messages as well.
-
-To enable the audit subsystem, you must add this to your
-kernel config:
-CONFIG_AUDIT=y
-
-To enable a LSM, you must consult that LSM's documentation, the
-example below is for SELinux:
-CONFIG_SECURITY_SELINUX=y
-
-This does not include possible dependencies that may need to be
-satisfied for that particular LSM.
diff --git a/logd/README.compression.md b/logd/README.compression.md
deleted file mode 100644
index 4ba634a..0000000
--- a/logd/README.compression.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Log Compression instead of Chatty in Android S
-
-## The problem
-
-* Log buffer space is precious, but suffers from the tragedy of the commons
-* Log spam fills the buffers making them less useful in logcat/bugreports
-* “Spam” is often in the eye of the beholder: which messages are important depends on what you’re trying to debug
-
-## The idea
-
-* Chatty isn’t helping as much as we’d hoped, and is surprisingly expensive
-* Compress logs to make more efficient use of the buffer
-* Address the root cause of log spam at its source:
- * Do not hide log spam at runtime, which de-incentivize fixes
- * Add presubmit coverage similar to SELinux violations to keep log spam down
-
----
-
-## Chatty in Theory
-
-* Delete messages classified as spam to extend the range of logs from other sources
-* “Spam” defined as:
- * Logs from UIDs whose logs consume over 12.5% of a log buffer
- * Back-to-back exact duplicate messages
-
-## Chatty in Practice
-
-* Developer confusion about missing and de-duplicated logs
-* Lowered incentive to fix the root cause of bad logging behavior
-* High CPU overhead
-* Memory usage greatly exceeds configured buffer size
-* Only marginal increase in log range
-
----
-
-## Log Compression in Theory
-
-* Store many more logs in the same log buffer size => better for diagnosis
-* Memory usage stays below configured log size => better system health
-* No gaps in logs, no de-duplicated logs => no developer confusion
-* No hiding bad behavior => increased accountability/incentive to fix root causes
-
-## Log Compression Preliminary Results
-
-* Captured 2, 5 day periods of full time personal usage of Pixel 4 and replayed the logs offline
-* Compression vs Chatty:
- * **3.5x more log messages on average**
- * **50% less CPU usage**
- * **50% less memory usage**
-
----
-
-## Log Messages in 1MB
-
-* The number of log messages still available in logcat after ‘Message Count’ messages have been logged to a 1MB log buffer
-* Note: ‘Simple’ is the Chatty code without log spam detection and without de-duplication.
-
-
-
----
-
-## CPU Time
-
-* Total CPU time on ARM64 (Walleye) and 32bit x86 (Cuttlefish)
-* X axis represents different log buffer size configurations.
- * Chatty uses significantly more CPU time at 1MB (the default Pixel configuration)
- * Chatty scales poorly with increased log buffer sizes
-* Note: “simple” isn’t “compression without actually compressing”, it’s “chatty without doing the chatty elimination”, which is why “simple” is more expensive than “compression” on walleye.
-
-
-
-
----
-
-## Memory Usage
-
-* The memory used by ‘Message Count’ messages, on both Walleye and Cuttlefish
-* Note: Chatty does not consider the metadata (UID, PID, timestamp, etc) in its calculation of log buffer size, so a 1MB log buffer will consume more than 1MB. Note that there are 8 log buffers, 5 of which are typically filled.
-
-
-
diff --git a/logd/README.property b/logd/README.property
deleted file mode 100644
index 8fd7f48..0000000
--- a/logd/README.property
+++ /dev/null
@@ -1,72 +0,0 @@
-The properties that logd and friends react to are:
-
-name type default description
-ro.logd.auditd bool true Enable selinux audit daemon
-ro.logd.auditd.dmesg bool true selinux audit messages sent to dmesg.
-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
-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
-logd.logpersistd string persist Enable logpersist daemon, "logcatd"
- turns on logcat -f in logd context.
- Responds to logcatd, clear and stop.
-logd.logpersistd.buffer persist logpersistd buffers to collect
-logd.logpersistd.size persist logpersistd size in MB
-logd.logpersistd.rotate_kbytes persist logpersistd outout file size in KB.
-persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
- turns on logcat -f in logd context.
-persist.logd.logpersistd.buffer all logpersistd buffers to collect
-persist.logd.logpersistd.size 256 logpersistd size in MB
-persist.logd.logpersistd.count 256 sets max number of rotated logs to <count>.
-persist.logd.logpersistd.rotate_kbytes 1024 logpersistd output file size in KB
-persist.logd.size number ro Global default size of the buffer for
- all log ids at initial startup, at
- runtime use: logcat -b all -G <value>
-ro.logd.size number svelte default for persist.logd.size. Larger
- platform default sizes than 256KB are
- known to not scale well under log spam
- pressure. Address the spam first,
- resist increasing the log buffer.
-persist.logd.size.<buffer> number ro Size of the buffer for <buffer> log
-ro.logd.size.<buffer> number svelte default for persist.logd.size.<buffer>
-ro.config.low_ram bool false if true, logd.statistics,
- ro.logd.kernel default false,
- logd.size 64K instead of 256K.
-persist.logd.filter string Pruning filter to optimize content.
- At runtime use: logcat -P "<string>"
-ro.logd.filter string "~! ~1000/!" default for persist.logd.filter.
- This default means to prune the
- oldest entries of chattiest UID, and
- the chattiest PID of system
- (1000, or AID_SYSTEM).
-log.tag string persist The global logging level, VERBOSE,
- DEBUG, INFO, WARN, ERROR, ASSERT or
- SILENT. Only the first character is
- the key character.
-persist.log.tag string build default for log.tag
-log.tag.<tag> string persist The <tag> specific logging level.
-persist.log.tag.<tag> string build default for log.tag.<tag>
-
-logd.buffer_type string (empty) Set the log buffer type. Current choices are 'simple',
- 'chatty', or 'serialized'. Defaults to 'chatty' if empty.
-
-NB:
-- auto - managed by /init
-- svelte - see ro.config.low_ram 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.
-- number - support multipliers (K or M) for convenience. Range is limited
- to between 64K and 256M for log buffer sizes. Individual log buffer ids
- such as main, system, ... override global default.
-- Pruning filter rules are specified as UID, UID/PID or /PID. A '~' prefix indicates that elements
- matching the rule should be pruned with higher priority otherwise they're pruned with lower
- priority. All other pruning activity is oldest first. Special case ~! represents an automatic
- pruning for the noisiest UID as determined by the current statistics. Special case ~1000/!
- represents pruning of the worst PID within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
diff --git a/logd/README.replay.md b/logd/README.replay.md
deleted file mode 100644
index 5f7ec9e..0000000
--- a/logd/README.replay.md
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index f18c422..0000000
--- a/logd/RecordedLogMessage.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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
deleted file mode 100644
index f5991f3..0000000
--- a/logd/RecordingLogBuffer.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 49a0aba..0000000
--- a/logd/RecordingLogBuffer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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
deleted file mode 100644
index bad8c56..0000000
--- a/logd/ReplayMessages.cpp
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * 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 {
- auto lock = std::lock_guard{logd_lock};
- 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{logd_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/SerializedData.h b/logd/SerializedData.h
deleted file mode 100644
index d3d1e18..0000000
--- a/logd/SerializedData.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 <sys/types.h>
-
-#include <algorithm>
-#include <memory>
-
-// This class is used instead of std::string or std::vector because their clear(), erase(), etc
-// functions don't actually deallocate. shrink_to_fit() does deallocate but is not guaranteed to
-// work and swapping with an empty string/vector is clunky.
-class SerializedData {
- public:
- SerializedData() {}
- SerializedData(size_t size) : data_(new uint8_t[size]), size_(size) {}
-
- void Resize(size_t new_size) {
- if (size_ == 0) {
- data_.reset(new uint8_t[new_size]);
- size_ = new_size;
- } else if (new_size == 0) {
- data_.reset();
- size_ = 0;
- } else if (new_size != size_) {
- std::unique_ptr<uint8_t[]> new_data(new uint8_t[new_size]);
- size_t copy_size = std::min(size_, new_size);
- memcpy(new_data.get(), data_.get(), copy_size);
- data_.swap(new_data);
- size_ = new_size;
- }
- }
-
- uint8_t* data() { return data_.get(); }
- const uint8_t* data() const { return data_.get(); }
- size_t size() const { return size_; }
-
- private:
- std::unique_ptr<uint8_t[]> data_;
- size_t size_ = 0;
-};
\ No newline at end of file
diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp
deleted file mode 100644
index 30276ff..0000000
--- a/logd/SerializedFlushToState.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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 "SerializedFlushToState.h"
-
-#include <limits>
-
-#include <android-base/logging.h>
-
-SerializedFlushToState::SerializedFlushToState(uint64_t start, LogMask log_mask,
- std::list<SerializedLogChunk>* logs)
- : FlushToState(start, log_mask), logs_(logs) {
- log_id_for_each(i) {
- if (((1 << i) & log_mask) == 0) {
- continue;
- }
- logs_needed_from_next_position_[i] = true;
- }
-}
-
-SerializedFlushToState::~SerializedFlushToState() {
- log_id_for_each(i) {
- if (log_positions_[i]) {
- log_positions_[i]->buffer_it->DecReaderRefCount();
- }
- }
-}
-
-void SerializedFlushToState::CreateLogPosition(log_id_t log_id) {
- CHECK(!logs_[log_id].empty());
- LogPosition log_position;
- auto it = logs_[log_id].begin();
- while (it != logs_[log_id].end() && start() > it->highest_sequence_number()) {
- ++it;
- }
- if (it == logs_[log_id].end()) {
- --it;
- }
- it->IncReaderRefCount();
- log_position.buffer_it = it;
-
- // Find the offset of the first log with sequence number >= start().
- int read_offset = 0;
- while (read_offset < it->write_offset()) {
- const auto* entry = it->log_entry(read_offset);
- if (entry->sequence() >= start()) {
- break;
- }
- read_offset += entry->total_len();
- }
- log_position.read_offset = read_offset;
-
- log_positions_[log_id].emplace(log_position);
-}
-
-void SerializedFlushToState::UpdateLogsNeeded(log_id_t log_id) {
- auto& buffer_it = log_positions_[log_id]->buffer_it;
- auto read_offset = log_positions_[log_id]->read_offset;
-
- // If there is another log to read in this buffer, let it be read.
- if (read_offset < buffer_it->write_offset()) {
- logs_needed_from_next_position_[log_id] = false;
- } else if (read_offset == buffer_it->write_offset()) {
- // If there are no more logs to read in this buffer and it's the last buffer, then
- // set logs_needed_from_next_position_ to wait until more logs get logged.
- if (buffer_it == std::prev(logs_[log_id].end())) {
- 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();
- ++buffer_it;
- buffer_it->IncReaderRefCount();
- log_positions_[log_id]->read_offset = 0;
- if (buffer_it->write_offset() == 0) {
- logs_needed_from_next_position_[log_id] = true;
- } else {
- logs_needed_from_next_position_[log_id] = false;
- }
- }
- } else {
- // read_offset > buffer_it->write_offset() should never happen.
- LOG(FATAL) << "read_offset (" << read_offset << ") > buffer_it->write_offset() ("
- << buffer_it->write_offset() << ")";
- }
-}
-
-void SerializedFlushToState::CheckForNewLogs() {
- log_id_for_each(i) {
- if (!logs_needed_from_next_position_[i]) {
- continue;
- }
- if (!log_positions_[i]) {
- if (logs_[i].empty()) {
- continue;
- }
- CreateLogPosition(i);
- }
- UpdateLogsNeeded(i);
- }
-}
-
-bool SerializedFlushToState::HasUnreadLogs() {
- CheckForNewLogs();
- log_id_for_each(i) {
- if (log_positions_[i] && !logs_needed_from_next_position_[i]) {
- return true;
- }
- }
- return false;
-}
-
-LogWithId SerializedFlushToState::PopNextUnreadLog() {
- uint64_t min_sequence = std::numeric_limits<uint64_t>::max();
- log_id_t log_id;
- const SerializedLogEntry* entry = nullptr;
- log_id_for_each(i) {
- if (!log_positions_[i] || logs_needed_from_next_position_[i]) {
- continue;
- }
- if (log_positions_[i]->log_entry()->sequence() < min_sequence) {
- log_id = i;
- entry = log_positions_[i]->log_entry();
- min_sequence = entry->sequence();
- }
- }
- CHECK_NE(nullptr, entry);
-
- log_positions_[log_id]->read_offset += entry->total_len();
-
- logs_needed_from_next_position_[log_id] = true;
-
- return {log_id, entry};
-}
-
-void SerializedFlushToState::Prune(log_id_t log_id,
- const std::list<SerializedLogChunk>::iterator& buffer_it) {
- // If we don't have a position for this log or if we're not referencing buffer_it, ignore.
- if (!log_positions_[log_id].has_value() || log_positions_[log_id]->buffer_it != buffer_it) {
- return;
- }
-
- // Decrease the ref count since we're deleting our reference.
- buffer_it->DecReaderRefCount();
-
- // Delete in the reference.
- log_positions_[log_id].reset();
-
- // Finally set logs_needed_from_next_position_, so CheckForNewLogs() will re-create the
- // log_position_ object during the next read.
- logs_needed_from_next_position_[log_id] = true;
-}
diff --git a/logd/SerializedFlushToState.h b/logd/SerializedFlushToState.h
deleted file mode 100644
index 1a69f7b..0000000
--- a/logd/SerializedFlushToState.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 <bitset>
-#include <list>
-#include <queue>
-
-#include "LogBuffer.h"
-#include "LogdLock.h"
-#include "SerializedLogChunk.h"
-#include "SerializedLogEntry.h"
-
-struct LogPosition {
- std::list<SerializedLogChunk>::iterator buffer_it;
- int read_offset;
-
- const SerializedLogEntry* log_entry() const { return buffer_it->log_entry(read_offset); }
-};
-
-struct LogWithId {
- log_id_t log_id;
- const SerializedLogEntry* entry;
-};
-
-// This class tracks the specific point where a FlushTo client has read through the logs. It
-// directly references the std::list<> iterators from the parent SerializedLogBuffer and the offset
-// into each log chunk where it has last read. All interactions with this class, except for its
-// construction, must be done with SerializedLogBuffer::lock_ held.
-class SerializedFlushToState : public FlushToState {
- public:
- // Initializes this state object. For each log buffer set in log_mask, this sets
- // logs_needed_from_next_position_.
- SerializedFlushToState(uint64_t start, LogMask log_mask, std::list<SerializedLogChunk>* logs)
- REQUIRES(logd_lock);
-
- // Decrease the reference of all referenced logs. This happens when a reader is disconnected.
- ~SerializedFlushToState() override;
-
- // Updates the state of log_positions_ and logs_needed_from_next_position_ then returns true if
- // there are any unread logs, false otherwise.
- bool HasUnreadLogs() REQUIRES(logd_lock);
-
- // Returns the next unread log and sets logs_needed_from_next_position_ to indicate that we're
- // waiting for more logs from the associated log buffer.
- LogWithId PopNextUnreadLog() REQUIRES(logd_lock);
-
- // If the parent log buffer prunes logs, the reference that this class contains may become
- // invalid, so this must be called first to drop the reference to buffer_it, if any.
- void Prune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& buffer_it)
- REQUIRES(logd_lock);
-
- private:
- // Set logs_needed_from_next_position_[i] to indicate if log_positions_[i] points to an unread
- // log or to the point at which the next log will appear.
- void UpdateLogsNeeded(log_id_t log_id) REQUIRES(logd_lock);
-
- // Create a LogPosition object for the given log_id by searching through the log chunks for the
- // first chunk and then first log entry within that chunk that is greater or equal to start().
- void CreateLogPosition(log_id_t log_id) REQUIRES(logd_lock);
-
- // Checks to see if any log buffers set in logs_needed_from_next_position_ have new logs and
- // calls UpdateLogsNeeded() if so.
- void CheckForNewLogs() REQUIRES(logd_lock);
-
- std::list<SerializedLogChunk>* logs_ GUARDED_BY(logd_lock) = nullptr;
- // An optional structure that contains an iterator to the serialized log buffer and offset into
- // it that this logger should handle next.
- std::optional<LogPosition> log_positions_[LOG_ID_MAX] GUARDED_BY(logd_lock);
- // A bit for each log that is set if a given log_id has no logs or if this client has read all
- // of its logs. In order words: `logs_[i].empty() || (buffer_it == std::prev(logs_.end) &&
- // next_log_position == logs_write_position_)`. These will be re-checked in each
- // loop in case new logs came in.
- std::bitset<LOG_ID_MAX> logs_needed_from_next_position_ GUARDED_BY(logd_lock) = {};
-};
diff --git a/logd/SerializedFlushToStateTest.cpp b/logd/SerializedFlushToStateTest.cpp
deleted file mode 100644
index f41de37..0000000
--- a/logd/SerializedFlushToStateTest.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * 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 "SerializedFlushToState.h"
-
-#include <map>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-
-using android::base::Join;
-using android::base::StringPrintf;
-
-constexpr size_t kChunkSize = 3 * 4096;
-
-class SerializedFlushToStateTest : public testing::Test {
- protected:
- void SetUp() override {
- // This test spams many unneeded INFO logs, so we suppress them.
- old_log_severity_ = android::base::SetMinimumLogSeverity(android::base::WARNING);
- }
- void TearDown() override { android::base::SetMinimumLogSeverity(old_log_severity_); }
-
- std::string TestReport(const std::vector<uint64_t>& expected, const std::vector<uint64_t>& read)
- REQUIRES(logd_lock) {
- auto sequence_to_log_id = [&](uint64_t sequence) -> int {
- for (const auto& [log_id, sequences] : sequence_numbers_per_buffer_) {
- if (std::find(sequences.begin(), sequences.end(), sequence) != sequences.end()) {
- return log_id;
- }
- }
- return -1;
- };
-
- std::map<int, std::vector<uint64_t>> missing_sequences;
- std::vector<uint64_t> missing_expected;
- std::set_difference(expected.begin(), expected.end(), read.begin(), read.end(),
- std::back_inserter(missing_expected));
- for (uint64_t sequence : missing_expected) {
- int log_id = sequence_to_log_id(sequence);
- missing_sequences[log_id].emplace_back(sequence);
- }
-
- std::map<int, std::vector<uint64_t>> extra_sequences;
- std::vector<uint64_t> extra_read;
- std::set_difference(read.begin(), read.end(), expected.begin(), expected.end(),
- std::back_inserter(extra_read));
- for (uint64_t sequence : extra_read) {
- int log_id = sequence_to_log_id(sequence);
- extra_sequences[log_id].emplace_back(sequence);
- }
-
- std::vector<std::string> errors;
- for (const auto& [log_id, sequences] : missing_sequences) {
- errors.emplace_back(
- StringPrintf("Log id %d missing %zu sequences", log_id, sequences.size()));
- }
-
- for (const auto& [log_id, sequences] : extra_sequences) {
- errors.emplace_back(
- StringPrintf("Log id %d has extra %zu sequences", log_id, sequences.size()));
- }
-
- return Join(errors, ", ");
- }
-
- // Read sequence numbers in order from SerializedFlushToState for every mask combination and all
- // sequence numbers from 0 through the highest logged sequence number + 1.
- // This assumes that all of the logs have already been written.
- void TestAllReading() REQUIRES(logd_lock) {
- uint64_t max_sequence = sequence_ + 1;
- uint32_t max_mask = (1 << LOG_ID_MAX) - 1;
- for (uint64_t sequence = 0; sequence < max_sequence; ++sequence) {
- for (uint32_t mask = 0; mask < max_mask; ++mask) {
- auto state = SerializedFlushToState{sequence, mask, log_chunks_};
- TestReading(sequence, mask, state);
- }
- }
- }
-
- // Similar to TestAllReading() except that it doesn't assume any logs are in the buffer, instead
- // it calls write_logs() in a loop for sequence/mask combination. It clears log_chunks_ and
- // sequence_numbers_per_buffer_ between calls, such that only the sequence numbers written in
- // the previous call to write_logs() are expected.
- void TestAllReadingWithFutureMessages(const std::function<bool(int)>& write_logs)
- REQUIRES(logd_lock) {
- uint64_t max_sequence = sequence_ + 1;
- uint32_t max_mask = (1 << LOG_ID_MAX) - 1;
- for (uint64_t sequence = 1; sequence < max_sequence; ++sequence) {
- for (uint32_t mask = 1; mask < max_mask; ++mask) {
- log_id_for_each(i) { log_chunks_[i].clear(); }
- auto state = SerializedFlushToState{sequence, mask, log_chunks_};
- int loop_count = 0;
- while (write_logs(loop_count++)) {
- TestReading(sequence, mask, state);
- sequence_numbers_per_buffer_.clear();
- }
- }
- }
- }
-
- void TestReading(uint64_t start, LogMask log_mask, SerializedFlushToState& state)
- REQUIRES(logd_lock) {
- std::vector<uint64_t> expected_sequence;
- log_id_for_each(i) {
- if (((1 << i) & log_mask) == 0) {
- continue;
- }
- for (const auto& sequence : sequence_numbers_per_buffer_[i]) {
- if (sequence >= start) {
- expected_sequence.emplace_back(sequence);
- }
- }
- }
- std::sort(expected_sequence.begin(), expected_sequence.end());
-
- std::vector<uint64_t> read_sequence;
-
- while (state.HasUnreadLogs()) {
- auto top = state.PopNextUnreadLog();
- read_sequence.emplace_back(top.entry->sequence());
- }
-
- EXPECT_TRUE(std::is_sorted(read_sequence.begin(), read_sequence.end()));
-
- EXPECT_EQ(expected_sequence.size(), read_sequence.size());
-
- EXPECT_EQ(expected_sequence, read_sequence)
- << "start: " << start << " log_mask: " << log_mask << " "
- << TestReport(expected_sequence, read_sequence);
- }
-
- // Add a chunk with the given messages to the a given log buffer. Keep track of the sequence
- // numbers for future validation. Optionally mark the block as having finished writing.
- void AddChunkWithMessages(bool finish_writing, int buffer,
- const std::vector<std::string>& messages) REQUIRES(logd_lock) {
- auto chunk = SerializedLogChunk{kChunkSize};
- for (const auto& message : messages) {
- auto sequence = sequence_++;
- sequence_numbers_per_buffer_[buffer].emplace_back(sequence);
- ASSERT_TRUE(chunk.CanLog(message.size() + 1));
- chunk.Log(sequence, log_time(), 0, 1, 1, message.c_str(), message.size() + 1);
- }
- if (finish_writing) {
- chunk.FinishWriting();
- }
- log_chunks_[buffer].emplace_back(std::move(chunk));
- }
-
- android::base::LogSeverity old_log_severity_;
- std::map<int, std::vector<uint64_t>> sequence_numbers_per_buffer_;
- std::list<SerializedLogChunk> log_chunks_[LOG_ID_MAX];
- uint64_t sequence_ = 1;
-};
-
-// 0: multiple chunks, with variable number of entries, with/without finishing writing
-// 1: 1 chunk with 1 log and finished writing
-// 2: 1 chunk with 1 log and not finished writing
-// 3: 1 chunk with 0 logs and not finished writing
-// 4: 1 chunk with 0 logs and finished writing (impossible, but SerializedFlushToState handles it)
-// 5-7: 0 chunks
-TEST_F(SerializedFlushToStateTest, smoke) {
- auto lock = std::lock_guard{logd_lock};
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"3rd"});
- AddChunkWithMessages(false, 0, {"4th"});
- AddChunkWithMessages(true, 0, {"4th", "5th", "more", "even", "more", "go", "here"});
- AddChunkWithMessages(false, 2, {"6th"});
- AddChunkWithMessages(true, 0, {"7th"});
- AddChunkWithMessages(false, 3, {});
- AddChunkWithMessages(true, 4, {});
-
- TestAllReading();
-}
-
-TEST_F(SerializedFlushToStateTest, random) {
- auto lock = std::lock_guard{logd_lock};
- srand(1);
- for (int count = 0; count < 20; ++count) {
- unsigned int num_messages = 1 + rand() % 15;
- auto messages = std::vector<std::string>{num_messages, "same message"};
-
- bool compress = rand() % 2;
- int buf = rand() % LOG_ID_MAX;
-
- AddChunkWithMessages(compress, buf, messages);
- }
-
- TestAllReading();
-}
-
-// Same start as smoke, but we selectively write logs to the buffers and ensure they're read.
-TEST_F(SerializedFlushToStateTest, future_writes) {
- auto lock = std::lock_guard{logd_lock};
- auto write_logs = [&](int loop_count) REQUIRES(logd_lock) {
- switch (loop_count) {
- case 0:
- // Initial writes.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"3rd"});
- AddChunkWithMessages(false, 0, {"4th"});
- AddChunkWithMessages(true, 0, {"4th", "5th", "more", "even", "more", "go", "here"});
- AddChunkWithMessages(false, 2, {"6th"});
- AddChunkWithMessages(true, 0, {"7th"});
- AddChunkWithMessages(false, 3, {});
- AddChunkWithMessages(true, 4, {});
- break;
- case 1:
- // Smoke test, add a simple chunk.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- break;
- case 2:
- // Add chunks to all but one of the logs.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"1st", "2nd"});
- AddChunkWithMessages(true, 2, {"1st", "2nd"});
- AddChunkWithMessages(true, 3, {"1st", "2nd"});
- AddChunkWithMessages(true, 4, {"1st", "2nd"});
- AddChunkWithMessages(true, 5, {"1st", "2nd"});
- AddChunkWithMessages(true, 6, {"1st", "2nd"});
- break;
- case 3:
- // Finally add chunks to all logs.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"1st", "2nd"});
- AddChunkWithMessages(true, 2, {"1st", "2nd"});
- AddChunkWithMessages(true, 3, {"1st", "2nd"});
- AddChunkWithMessages(true, 4, {"1st", "2nd"});
- AddChunkWithMessages(true, 5, {"1st", "2nd"});
- AddChunkWithMessages(true, 6, {"1st", "2nd"});
- AddChunkWithMessages(true, 7, {"1st", "2nd"});
- break;
- default:
- return false;
- }
- return true;
- };
-
- TestAllReadingWithFutureMessages(write_logs);
-}
-
-TEST_F(SerializedFlushToStateTest, no_dangling_references) {
- auto lock = std::lock_guard{logd_lock};
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 0, {"3rd", "4th"});
-
- auto state = SerializedFlushToState{1, kLogMaskAll, log_chunks_};
-
- ASSERT_EQ(log_chunks_[0].size(), 2U);
- auto first_chunk = log_chunks_[0].begin();
- auto second_chunk = std::next(first_chunk);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto first_log = state.PopNextUnreadLog();
- EXPECT_STREQ(first_log.entry->msg(), "1st");
- EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto second_log = state.PopNextUnreadLog();
- EXPECT_STREQ(second_log.entry->msg(), "2nd");
- EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto third_log = state.PopNextUnreadLog();
- EXPECT_STREQ(third_log.entry->msg(), "3rd");
- EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto fourth_log = state.PopNextUnreadLog();
- EXPECT_STREQ(fourth_log.entry->msg(), "4th");
- EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
-
- EXPECT_FALSE(state.HasUnreadLogs());
-}
-
-TEST(SerializedFlushToState, Prune) {
- auto lock = std::lock_guard{logd_lock};
- auto chunk = SerializedLogChunk{kChunkSize};
- chunk.Log(1, log_time(), 0, 1, 1, "abc", 3);
- chunk.Log(2, log_time(), 0, 1, 1, "abc", 3);
- chunk.Log(3, log_time(), 0, 1, 1, "abc", 3);
- chunk.FinishWriting();
-
- std::list<SerializedLogChunk> log_chunks[LOG_ID_MAX];
- log_chunks[LOG_ID_MAIN].emplace_back(std::move(chunk));
-
- auto state = SerializedFlushToState{1, kLogMaskAll, log_chunks};
- ASSERT_TRUE(state.HasUnreadLogs());
-
- state.Prune(LOG_ID_MAIN, log_chunks[LOG_ID_MAIN].begin());
-}
diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp
deleted file mode 100644
index aa80864..0000000
--- a/logd/SerializedLogBuffer.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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 "SerializedLogBuffer.h"
-
-#include <sys/prctl.h>
-
-#include <limits>
-
-#include <android-base/logging.h>
-#include <android-base/scopeguard.h>
-
-#include "LogSize.h"
-#include "LogStatistics.h"
-#include "SerializedFlushToState.h"
-
-SerializedLogBuffer::SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags,
- LogStatistics* stats)
- : reader_list_(reader_list), tags_(tags), stats_(stats) {
- Init();
-}
-
-void SerializedLogBuffer::Init() {
- log_id_for_each(i) {
- if (!SetSize(i, GetBufferSizeFromProperties(i))) {
- SetSize(i, kLogBufferMinSize);
- }
- }
-
- // Release any sleeping reader threads to dump their current content.
- auto lock = std::lock_guard{logd_lock};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- reader_thread->TriggerReader();
- }
-}
-
-bool SerializedLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
- if (log_id == LOG_ID_SECURITY) {
- return true;
- }
-
- int prio = ANDROID_LOG_INFO;
- const char* tag = nullptr;
- size_t tag_len = 0;
- if (IsBinary(log_id)) {
- int32_t tag_int = MsgToTag(msg, len);
- tag = tags_->tagToName(tag_int);
- if (tag) {
- tag_len = strlen(tag);
- }
- } else {
- prio = *msg;
- tag = msg + 1;
- tag_len = strnlen(tag, len - 1);
- }
- return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
-}
-
-int SerializedLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- if (log_id >= LOG_ID_MAX || len == 0) {
- return -EINVAL;
- }
-
- if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
- len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
-
- if (!ShouldLog(log_id, msg, len)) {
- stats_->AddTotal(log_id, len);
- return -EACCES;
- }
-
- auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
-
- auto lock = std::lock_guard{logd_lock};
-
- if (logs_[log_id].empty()) {
- logs_[log_id].push_back(SerializedLogChunk(max_size_[log_id] / 4));
- }
-
- auto total_len = sizeof(SerializedLogEntry) + len;
- if (!logs_[log_id].back().CanLog(total_len)) {
- logs_[log_id].back().FinishWriting();
- logs_[log_id].push_back(SerializedLogChunk(max_size_[log_id] / 4));
- }
-
- auto entry = logs_[log_id].back().Log(sequence, realtime, uid, pid, tid, msg, len);
- stats_->Add(entry->ToLogStatisticsElement(log_id));
-
- MaybePrune(log_id);
-
- reader_list_->NotifyNewLog(1 << log_id);
- return len;
-}
-
-void SerializedLogBuffer::MaybePrune(log_id_t log_id) {
- size_t total_size = GetSizeUsed(log_id);
- size_t after_size = total_size;
- if (total_size > max_size_[log_id]) {
- Prune(log_id, total_size - max_size_[log_id], 0);
- after_size = GetSizeUsed(log_id);
- LOG(VERBOSE) << "Pruned Logs from log_id: " << log_id << ", previous size: " << total_size
- << " after size: " << after_size;
- }
-
- stats_->set_overhead(log_id, after_size);
-}
-
-void SerializedLogBuffer::RemoveChunkFromStats(log_id_t log_id, SerializedLogChunk& chunk) {
- chunk.IncReaderRefCount();
- int read_offset = 0;
- while (read_offset < chunk.write_offset()) {
- auto* entry = chunk.log_entry(read_offset);
- stats_->Subtract(entry->ToLogStatisticsElement(log_id));
- read_offset += entry->total_len();
- }
- chunk.DecReaderRefCount();
-}
-
-void SerializedLogBuffer::NotifyReadersOfPrune(
- log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk) {
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- auto& state = reinterpret_cast<SerializedFlushToState&>(reader_thread->flush_to_state());
- state.Prune(log_id, chunk);
- }
-}
-
-void SerializedLogBuffer::Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) {
- auto& log_buffer = logs_[log_id];
- auto it = log_buffer.begin();
- while (it != log_buffer.end()) {
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (!reader_thread->IsWatching(log_id)) {
- continue;
- }
-
- if (reader_thread->deadline().time_since_epoch().count() != 0) {
- // Always wake up wrapped readers when pruning. 'Wrapped' readers are an
- // optimization that allows the reader to wait until logs starting at a specified
- // time stamp are about to be pruned. This is error-prone however, since if that
- // timestamp is about to be pruned, the reader is not likely to read the messages
- // fast enough to not back-up logd. Instead, we can achieve an nearly-as-efficient
- // but not error-prune batching effect by waking the reader whenever any chunk is
- // about to be pruned.
- reader_thread->TriggerReader();
- }
-
- // Some readers may be still reading from this log chunk, log a warning that they are
- // about to lose logs.
- // TODO: We should forcefully disconnect the reader instead, such that the reader itself
- // has an indication that they've lost logs.
- if (reader_thread->start() <= it->highest_sequence_number()) {
- LOG(WARNING) << "Skipping entries from slow reader, " << reader_thread->name()
- << ", from LogBuffer::Prune()";
- }
- }
-
- // Increment ahead of time since we're going to erase this iterator from the list.
- auto it_to_prune = it++;
-
- // Readers may have a reference to the chunk to track their last read log_position.
- // Notify them to delete the reference.
- NotifyReadersOfPrune(log_id, it_to_prune);
-
- if (uid != 0) {
- // Reorder the log buffer to remove logs from the given UID. If there are no logs left
- // in the buffer after the removal, delete it.
- if (it_to_prune->ClearUidLogs(uid, log_id, stats_)) {
- log_buffer.erase(it_to_prune);
- }
- } else {
- size_t buffer_size = it_to_prune->PruneSize();
- RemoveChunkFromStats(log_id, *it_to_prune);
- log_buffer.erase(it_to_prune);
- if (buffer_size >= bytes_to_free) {
- return;
- }
- bytes_to_free -= buffer_size;
- }
- }
-}
-
-std::unique_ptr<FlushToState> SerializedLogBuffer::CreateFlushToState(uint64_t start,
- LogMask log_mask) {
- return std::make_unique<SerializedFlushToState>(start, log_mask, logs_);
-}
-
-bool SerializedLogBuffer::FlushTo(
- LogWriter* writer, FlushToState& abstract_state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) {
- auto& state = reinterpret_cast<SerializedFlushToState&>(abstract_state);
-
- while (state.HasUnreadLogs()) {
- LogWithId top = state.PopNextUnreadLog();
- auto* entry = top.entry;
- auto log_id = top.log_id;
-
- if (entry->sequence() < state.start()) {
- continue;
- }
- state.set_start(entry->sequence());
-
- if (!writer->privileged() && entry->uid() != writer->uid()) {
- continue;
- }
-
- if (filter) {
- auto ret = filter(log_id, entry->pid(), entry->sequence(), entry->realtime());
- if (ret == FilterResult::kSkip) {
- continue;
- }
- if (ret == FilterResult::kStop) {
- break;
- }
- }
-
- // We copy the log entry such that we can flush it without the lock. We never block pruning
- // waiting for this Flush() to complete.
- constexpr size_t kMaxEntrySize = sizeof(*entry) + LOGGER_ENTRY_MAX_PAYLOAD + 1;
- unsigned char entry_copy[kMaxEntrySize] __attribute__((uninitialized));
- CHECK_LT(entry->msg_len(), LOGGER_ENTRY_MAX_PAYLOAD + 1);
- memcpy(entry_copy, entry, sizeof(*entry) + entry->msg_len());
- logd_lock.unlock();
-
- if (!reinterpret_cast<SerializedLogEntry*>(entry_copy)->Flush(writer, log_id)) {
- logd_lock.lock();
- return false;
- }
-
- logd_lock.lock();
- }
-
- state.set_start(state.start() + 1);
- return true;
-}
-
-bool SerializedLogBuffer::Clear(log_id_t id, uid_t uid) {
- auto lock = std::lock_guard{logd_lock};
- Prune(id, ULONG_MAX, uid);
-
- // Clearing SerializedLogBuffer never waits for readers and therefore is always successful.
- return true;
-}
-
-size_t SerializedLogBuffer::GetSizeUsed(log_id_t id) {
- size_t total_size = 0;
- for (const auto& chunk : logs_[id]) {
- total_size += chunk.PruneSize();
- }
- return total_size;
-}
-
-size_t SerializedLogBuffer::GetSize(log_id_t id) {
- auto lock = std::lock_guard{logd_lock};
- return max_size_[id];
-}
-
-// New SerializedLogChunk objects will be allocated according to the new size, but older one are
-// unchanged. MaybePrune() is called on the log buffer to reduce it to an appropriate size if the
-// new size is lower.
-bool SerializedLogBuffer::SetSize(log_id_t id, size_t size) {
- // Reasonable limits ...
- if (!IsValidBufferSize(size)) {
- return false;
- }
-
- auto lock = std::lock_guard{logd_lock};
- max_size_[id] = size;
-
- MaybePrune(id);
-
- return true;
-}
diff --git a/logd/SerializedLogBuffer.h b/logd/SerializedLogBuffer.h
deleted file mode 100644
index 239a81e..0000000
--- a/logd/SerializedLogBuffer.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 <atomic>
-#include <bitset>
-#include <list>
-#include <mutex>
-#include <queue>
-#include <thread>
-#include <vector>
-
-#include <android-base/thread_annotations.h>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogdLock.h"
-#include "SerializedLogChunk.h"
-#include "SerializedLogEntry.h"
-
-class SerializedLogBuffer final : public LogBuffer {
- public:
- SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats);
- void Init() override;
-
- 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;
- std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask)
- REQUIRES(logd_lock) override;
- bool FlushTo(LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter)
- REQUIRES(logd_lock) override;
-
- bool Clear(log_id_t id, uid_t uid) override;
- size_t GetSize(log_id_t id) override;
- bool SetSize(log_id_t id, size_t size) override;
-
- uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
-
- private:
- bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
- void MaybePrune(log_id_t log_id) REQUIRES(logd_lock);
- void Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) REQUIRES(logd_lock);
- void NotifyReadersOfPrune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk)
- REQUIRES(logd_lock);
- void RemoveChunkFromStats(log_id_t log_id, SerializedLogChunk& chunk);
- size_t GetSizeUsed(log_id_t id) REQUIRES(logd_lock);
-
- LogReaderList* reader_list_;
- LogTags* tags_;
- LogStatistics* stats_;
-
- size_t max_size_[LOG_ID_MAX] GUARDED_BY(logd_lock) = {};
- std::list<SerializedLogChunk> logs_[LOG_ID_MAX] GUARDED_BY(logd_lock);
-
- std::atomic<uint64_t> sequence_ = 1;
-};
diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp
deleted file mode 100644
index 1ffe7a8..0000000
--- a/logd/SerializedLogChunk.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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 "SerializedLogChunk.h"
-
-#include <android-base/logging.h>
-
-#include "CompressionEngine.h"
-
-SerializedLogChunk::~SerializedLogChunk() {
- CHECK_EQ(reader_ref_count_, 0U);
-}
-
-void SerializedLogChunk::Compress() {
- CHECK_EQ(compressed_log_.size(), 0U);
- CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
- LOG(VERBOSE) << "Compressed Log, buffer max size: " << contents_.size()
- << " size used: " << write_offset_
- << " compressed size: " << compressed_log_.size();
-}
-
-// TODO: Develop a better reference counting strategy to guard against the case where the writer is
-// much faster than the reader, and we needlessly compess / decompress the logs.
-void SerializedLogChunk::IncReaderRefCount() {
- if (++reader_ref_count_ != 1 || writer_active_) {
- return;
- }
- contents_.Resize(write_offset_);
- CompressionEngine::GetInstance().Decompress(compressed_log_, contents_);
-}
-
-void SerializedLogChunk::DecReaderRefCount() {
- CHECK_NE(reader_ref_count_, 0U);
- if (--reader_ref_count_ != 0) {
- return;
- }
- if (!writer_active_) {
- contents_.Resize(0);
- }
-}
-
-bool SerializedLogChunk::ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats) {
- CHECK_EQ(reader_ref_count_, 0U);
- if (write_offset_ == 0) {
- return true;
- }
-
- IncReaderRefCount();
-
- int read_offset = 0;
- int new_write_offset = 0;
- while (read_offset < write_offset_) {
- const auto* entry = log_entry(read_offset);
- if (entry->uid() == uid) {
- read_offset += entry->total_len();
- if (stats != nullptr) {
- stats->Subtract(entry->ToLogStatisticsElement(log_id));
- }
- continue;
- }
- size_t entry_total_len = entry->total_len();
- if (read_offset != new_write_offset) {
- memmove(contents_.data() + new_write_offset, contents_.data() + read_offset,
- entry_total_len);
- }
- read_offset += entry_total_len;
- new_write_offset += entry_total_len;
- }
-
- if (new_write_offset == 0) {
- DecReaderRefCount();
- return true;
- }
-
- // Clear the old compressed logs and set write_offset_ appropriately to compress the new
- // partially cleared log.
- if (new_write_offset != write_offset_) {
- write_offset_ = new_write_offset;
- if (!writer_active_) {
- compressed_log_.Resize(0);
- Compress();
- }
- }
-
- DecReaderRefCount();
-
- return false;
-}
-
-bool SerializedLogChunk::CanLog(size_t len) {
- return write_offset_ + len <= contents_.size();
-}
-
-SerializedLogEntry* SerializedLogChunk::Log(uint64_t sequence, log_time realtime, uid_t uid,
- pid_t pid, pid_t tid, const char* msg, uint16_t len) {
- auto new_log_address = contents_.data() + write_offset_;
- auto* entry = new (new_log_address) SerializedLogEntry(uid, pid, tid, sequence, realtime, len);
- memcpy(entry->msg(), msg, len);
- write_offset_ += entry->total_len();
- highest_sequence_number_ = sequence;
- return entry;
-}
diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h
deleted file mode 100644
index 645433d..0000000
--- a/logd/SerializedLogChunk.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 <sys/types.h>
-
-#include <android-base/logging.h>
-
-#include "LogWriter.h"
-#include "SerializedData.h"
-#include "SerializedLogEntry.h"
-
-class SerializedLogChunk {
- public:
- explicit SerializedLogChunk(size_t size) : contents_(size) {}
- SerializedLogChunk(SerializedLogChunk&& other) noexcept = default;
- ~SerializedLogChunk();
-
- void Compress();
- void IncReaderRefCount();
- 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);
-
- bool CanLog(size_t len);
- SerializedLogEntry* Log(uint64_t sequence, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len);
-
- // If this buffer has been compressed, we only consider its compressed size when accounting for
- // memory consumption for pruning. This is since the uncompressed log is only by used by
- // readers, and thus not a representation of how much these logs cost to keep in memory.
- size_t PruneSize() const {
- return sizeof(*this) + (compressed_log_.size() ?: contents_.size());
- }
-
- void FinishWriting() {
- writer_active_ = false;
- Compress();
- if (reader_ref_count_ == 0) {
- contents_.Resize(0);
- }
- }
-
- const SerializedLogEntry* log_entry(int offset) const {
- CHECK(writer_active_ || reader_ref_count_ > 0);
- return reinterpret_cast<const SerializedLogEntry*>(data() + offset);
- }
- const uint8_t* data() const { return contents_.data(); }
- int write_offset() const { return write_offset_; }
- uint64_t highest_sequence_number() const { return highest_sequence_number_; }
-
- // Exposed for testing
- uint32_t reader_ref_count() const { return reader_ref_count_; }
-
- private:
- // The decompressed contents of this log buffer. Deallocated when the ref_count reaches 0 and
- // writer_active_ is false.
- SerializedData contents_;
- int write_offset_ = 0;
- uint32_t reader_ref_count_ = 0;
- bool writer_active_ = true;
- uint64_t highest_sequence_number_ = 1;
- SerializedData compressed_log_;
-};
diff --git a/logd/SerializedLogChunkTest.cpp b/logd/SerializedLogChunkTest.cpp
deleted file mode 100644
index 862c3fe..0000000
--- a/logd/SerializedLogChunkTest.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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 "SerializedLogChunk.h"
-
-#include <limits>
-
-#include <android-base/stringprintf.h>
-#include <android/log.h>
-#include <gtest/gtest.h>
-
-using android::base::StringPrintf;
-
-TEST(SerializedLogChunk, smoke) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_EQ(chunk_size + sizeof(SerializedLogChunk), chunk.PruneSize());
-
- static const char log_message[] = "log message";
- size_t expected_total_len = sizeof(SerializedLogEntry) + sizeof(log_message);
- ASSERT_TRUE(chunk.CanLog(expected_total_len));
- EXPECT_TRUE(chunk.CanLog(chunk_size));
- EXPECT_FALSE(chunk.CanLog(chunk_size + 1));
-
- log_time time(CLOCK_REALTIME);
- auto* entry = chunk.Log(1234, time, 0, 1, 2, log_message, sizeof(log_message));
- ASSERT_NE(nullptr, entry);
-
- EXPECT_EQ(1234U, entry->sequence());
- EXPECT_EQ(time, entry->realtime());
- EXPECT_EQ(0U, entry->uid());
- EXPECT_EQ(1, entry->pid());
- EXPECT_EQ(2, entry->tid());
- EXPECT_EQ(sizeof(log_message), entry->msg_len());
- EXPECT_STREQ(log_message, entry->msg());
- EXPECT_EQ(expected_total_len, entry->total_len());
-
- EXPECT_FALSE(chunk.CanLog(chunk_size));
- EXPECT_EQ(static_cast<int>(expected_total_len), chunk.write_offset());
- EXPECT_EQ(1234U, chunk.highest_sequence_number());
-}
-
-TEST(SerializedLogChunk, fill_log_exactly) {
- static const char log_message[] = "this is a log message";
- size_t individual_message_size = sizeof(SerializedLogEntry) + sizeof(log_message);
- size_t chunk_size = individual_message_size * 3;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_EQ(chunk_size + sizeof(SerializedLogChunk), chunk.PruneSize());
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(1, log_time(), 1000, 1, 1, log_message, sizeof(log_message)));
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(2, log_time(), 1000, 2, 1, log_message, sizeof(log_message)));
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(3, log_time(), 1000, 3, 1, log_message, sizeof(log_message)));
-
- EXPECT_FALSE(chunk.CanLog(1));
-}
-
-TEST(SerializedLogChunk, three_logs) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
-
- chunk.Log(2, log_time(0x1234, 0x5678), 0x111, 0x222, 0x333, "initial message",
- strlen("initial message"));
- chunk.Log(3, log_time(0x2345, 0x6789), 0x444, 0x555, 0x666, "second message",
- strlen("second message"));
- auto uint64_t_max = std::numeric_limits<uint64_t>::max();
- auto uint32_t_max = std::numeric_limits<uint32_t>::max();
- chunk.Log(uint64_t_max, log_time(uint32_t_max, uint32_t_max), uint32_t_max, uint32_t_max,
- uint32_t_max, "last message", strlen("last message"));
-
- static const char expected_buffer_data[] =
- "\x11\x01\x00\x00\x22\x02\x00\x00\x33\x03\x00\x00" // UID PID TID
- "\x02\x00\x00\x00\x00\x00\x00\x00" // Sequence
- "\x34\x12\x00\x00\x78\x56\x00\x00" // Timestamp
- "\x0F\x00initial message" // msg_len + message
- "\x44\x04\x00\x00\x55\x05\x00\x00\x66\x06\x00\x00" // UID PID TID
- "\x03\x00\x00\x00\x00\x00\x00\x00" // Sequence
- "\x45\x23\x00\x00\x89\x67\x00\x00" // Timestamp
- "\x0E\x00second message" // msg_len + message
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // UID PID TID
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // Sequence
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // Timestamp
- "\x0C\x00last message"; // msg_len + message
-
- for (size_t i = 0; i < sizeof(expected_buffer_data); ++i) {
- EXPECT_EQ(static_cast<uint8_t>(expected_buffer_data[i]), chunk.data()[i])
- << "position: " << i;
- }
-}
-
-// Check that the CHECK() in DecReaderRefCount() if the ref count goes bad is caught.
-TEST(SerializedLogChunk, catch_DecCompressedRef_CHECK) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_DEATH({ chunk.DecReaderRefCount(); }, "");
-}
-
-// Check that the CHECK() in ClearUidLogs() if the ref count is greater than 0 is caught.
-TEST(SerializedLogChunk, catch_ClearUidLogs_CHECK) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- chunk.IncReaderRefCount();
- EXPECT_DEATH({ chunk.ClearUidLogs(1000, LOG_ID_MAIN, nullptr); }, "");
- chunk.DecReaderRefCount();
-}
-
-class UidClearTest : public testing::TestWithParam<bool> {
- protected:
- template <typename Write, typename Check>
- void Test(const Write& write, const Check& check, bool expected_result) {
- write(chunk_);
-
- bool finish_writing = GetParam();
- if (finish_writing) {
- chunk_.FinishWriting();
- }
- EXPECT_EQ(expected_result, chunk_.ClearUidLogs(kUidToClear, LOG_ID_MAIN, nullptr));
- if (finish_writing) {
- chunk_.IncReaderRefCount();
- }
-
- check(chunk_);
-
- if (finish_writing) {
- chunk_.DecReaderRefCount();
- }
- }
-
- static constexpr size_t kChunkSize = 10 * 4096;
- static constexpr uid_t kUidToClear = 1000;
- static constexpr uid_t kOtherUid = 1234;
-
- SerializedLogChunk chunk_{kChunkSize};
-};
-
-// Test that ClearUidLogs() is a no-op if there are no logs of that UID in the buffer.
-TEST_P(UidClearTest, no_logs_in_chunk) {
- auto write = [](SerializedLogChunk&) {};
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-// Test that ClearUidLogs() is a no-op if there are no logs of that UID in the buffer.
-TEST_P(UidClearTest, no_logs_from_uid) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(1, log_time(), kOtherUid, 1, 2, msg, sizeof(msg));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- auto* entry = chunk.log_entry(0);
- EXPECT_STREQ(msg, entry->msg());
- };
-
- Test(write, check, false);
-}
-
-// Test that ClearUidLogs() returns true if all logs in a given buffer correspond to the given UID.
-TEST_P(UidClearTest, all_single) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(1, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- };
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-// Test that ClearUidLogs() returns true if all logs in a given buffer correspond to the given UID.
-TEST_P(UidClearTest, all_multiple) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(2, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- chunk.Log(3, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- chunk.Log(4, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- };
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-static std::string MakePrintable(const uint8_t* in, size_t length) {
- std::string result;
- for (size_t i = 0; i < length; ++i) {
- uint8_t c = in[i];
- if (isprint(c)) {
- result.push_back(c);
- } else {
- result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
- }
- }
- return result;
-}
-
-// This test clears UID logs at the beginning and end of the buffer, as well as two back to back
-// logs in the interior.
-TEST_P(UidClearTest, clear_beginning_and_end) {
- static const char msg1[] = "this is a log message";
- static const char msg2[] = "non-cleared message";
- static const char msg3[] = "back to back cleared messages";
- static const char msg4[] = "second in a row gone";
- static const char msg5[] = "but we save this one";
- static const char msg6[] = "and this 1!";
- static const char msg7[] = "the last one goes too";
- auto write = [](SerializedLogChunk& chunk) {
- ASSERT_NE(nullptr, chunk.Log(1, log_time(), kUidToClear, 1, 2, msg1, sizeof(msg1)));
- ASSERT_NE(nullptr, chunk.Log(2, log_time(), kOtherUid, 1, 2, msg2, sizeof(msg2)));
- ASSERT_NE(nullptr, chunk.Log(3, log_time(), kUidToClear, 1, 2, msg3, sizeof(msg3)));
- ASSERT_NE(nullptr, chunk.Log(4, log_time(), kUidToClear, 1, 2, msg4, sizeof(msg4)));
- ASSERT_NE(nullptr, chunk.Log(5, log_time(), kOtherUid, 1, 2, msg5, sizeof(msg5)));
- ASSERT_NE(nullptr, chunk.Log(6, log_time(), kOtherUid, 1, 2, msg6, sizeof(msg6)));
- ASSERT_NE(nullptr, chunk.Log(7, log_time(), kUidToClear, 1, 2, msg7, sizeof(msg7)));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- size_t read_offset = 0;
- auto* entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg2, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg5, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg6, entry->msg()) << MakePrintable(chunk.data(), chunk.write_offset());
- read_offset += entry->total_len();
-
- EXPECT_EQ(static_cast<int>(read_offset), chunk.write_offset());
- };
- Test(write, check, false);
-}
-
-// This tests the opposite case of beginning_and_end, in which we don't clear the beginning or end
-// logs. There is a single log pruned in the middle instead of back to back logs.
-TEST_P(UidClearTest, save_beginning_and_end) {
- static const char msg1[] = "saved first message";
- static const char msg2[] = "cleared interior message";
- static const char msg3[] = "last message stays";
- auto write = [](SerializedLogChunk& chunk) {
- ASSERT_NE(nullptr, chunk.Log(1, log_time(), kOtherUid, 1, 2, msg1, sizeof(msg1)));
- ASSERT_NE(nullptr, chunk.Log(2, log_time(), kUidToClear, 1, 2, msg2, sizeof(msg2)));
- ASSERT_NE(nullptr, chunk.Log(3, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- size_t read_offset = 0;
- auto* entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg1, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg3, entry->msg());
- read_offset += entry->total_len();
-
- EXPECT_EQ(static_cast<int>(read_offset), chunk.write_offset());
- };
- Test(write, check, false);
-}
-
-INSTANTIATE_TEST_CASE_P(UidClearTests, UidClearTest, testing::Values(true, false));
-
-// b/166187079: ClearUidLogs() should not compress the log if writer_active_ is true
-TEST(SerializedLogChunk, ClearUidLogs_then_FinishWriting) {
- static constexpr size_t kChunkSize = 10 * 4096;
- static constexpr uid_t kUidToClear = 1000;
- static constexpr uid_t kOtherUid = 1234;
-
- SerializedLogChunk chunk{kChunkSize};
- static const char msg1[] = "saved first message";
- static const char msg2[] = "cleared interior message";
- static const char msg3[] = "last message stays";
- ASSERT_NE(nullptr, chunk.Log(1, log_time(), kOtherUid, 1, 2, msg1, sizeof(msg1)));
- ASSERT_NE(nullptr, chunk.Log(2, log_time(), kUidToClear, 1, 2, msg2, sizeof(msg2)));
- ASSERT_NE(nullptr, chunk.Log(3, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
-
- chunk.ClearUidLogs(kUidToClear, LOG_ID_MAIN, nullptr);
-
- ASSERT_NE(nullptr, chunk.Log(4, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
-
- chunk.FinishWriting();
- // The next line would violate a CHECK() during decompression with the faulty code.
- chunk.IncReaderRefCount();
- chunk.DecReaderRefCount();
-}
diff --git a/logd/SerializedLogEntry.h b/logd/SerializedLogEntry.h
deleted file mode 100644
index 2f2c244..0000000
--- a/logd/SerializedLogEntry.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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 <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-#include <log/log_read.h>
-
-#include "LogStatistics.h"
-#include "LogWriter.h"
-
-// These structs are packed into a single chunk of memory for each log type within a
-// SerializedLogChunk object. Their message is contained immediately at the end of the struct. The
-// address of the next log in the buffer is *this + sizeof(SerializedLogEntry) + msg_len_. If that
-// value would overflow the chunk of memory associated with the SerializedLogChunk object, then a
-// new SerializedLogChunk must be allocated to contain the next SerializedLogEntry.
-class __attribute__((packed)) SerializedLogEntry {
- public:
- SerializedLogEntry(uid_t uid, pid_t pid, pid_t tid, uint64_t sequence, log_time realtime,
- uint16_t len)
- : uid_(uid),
- pid_(pid),
- tid_(tid),
- sequence_(sequence),
- realtime_(realtime),
- msg_len_(len) {}
- SerializedLogEntry(const SerializedLogEntry& elem) = delete;
- SerializedLogEntry& operator=(const SerializedLogEntry& elem) = delete;
- ~SerializedLogEntry() {
- // Never place anything in this destructor. This class is in place constructed and never
- // destructed.
- }
-
- LogStatisticsElement ToLogStatisticsElement(log_id_t log_id) const {
- return LogStatisticsElement{
- .uid = uid(),
- .pid = pid(),
- .tid = tid(),
- .tag = IsBinary(log_id) ? MsgToTag(msg(), msg_len()) : 0,
- .realtime = realtime(),
- .msg = msg(),
- .msg_len = msg_len(),
- .dropped_count = 0,
- .log_id = log_id,
- .total_len = total_len(),
- };
- }
-
- bool Flush(LogWriter* writer, log_id_t log_id) const {
- struct logger_entry entry = {};
-
- entry.hdr_size = sizeof(struct logger_entry);
- entry.lid = log_id;
- entry.pid = pid();
- entry.tid = tid();
- entry.uid = uid();
- entry.sec = realtime().tv_sec;
- entry.nsec = realtime().tv_nsec;
- entry.len = msg_len();
-
- return writer->Write(entry, msg());
- }
-
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
- pid_t tid() const { return tid_; }
- uint16_t msg_len() const { return msg_len_; }
- uint64_t sequence() const { return sequence_; }
- log_time realtime() const { return realtime_; }
-
- char* msg() { return reinterpret_cast<char*>(this) + sizeof(*this); }
- const char* msg() const { return reinterpret_cast<const char*>(this) + sizeof(*this); }
- uint16_t total_len() const { return sizeof(*this) + msg_len_; }
-
- private:
- const uint32_t uid_;
- const uint32_t pid_;
- const uint32_t tid_;
- const uint64_t sequence_;
- const log_time realtime_;
- const uint16_t msg_len_;
-};
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
deleted file mode 100644
index 55b31f8..0000000
--- a/logd/SimpleLogBuffer.cpp
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * 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 "SimpleLogBuffer.h"
-
-#include <android-base/logging.h>
-
-#include "LogBufferElement.h"
-#include "LogSize.h"
-
-SimpleLogBuffer::SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
- : reader_list_(reader_list), tags_(tags), stats_(stats) {
- Init();
-}
-
-SimpleLogBuffer::~SimpleLogBuffer() {}
-
-void SimpleLogBuffer::Init() {
- log_id_for_each(i) {
- if (!SetSize(i, GetBufferSizeFromProperties(i))) {
- SetSize(i, kLogBufferMinSize);
- }
- }
-
- // Release any sleeping reader threads to dump their current content.
- auto lock = std::lock_guard{logd_lock};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- reader_thread->TriggerReader();
- }
-}
-
-std::list<LogBufferElement>::iterator SimpleLogBuffer::GetOldest(log_id_t log_id) {
- auto it = logs().begin();
- if (oldest_[log_id]) {
- it = *oldest_[log_id];
- }
- while (it != logs().end() && it->log_id() != log_id) {
- it++;
- }
- if (it != logs().end()) {
- oldest_[log_id] = it;
- }
- return it;
-}
-
-bool SimpleLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
- if (log_id == LOG_ID_SECURITY) {
- return true;
- }
-
- int prio = ANDROID_LOG_INFO;
- const char* tag = nullptr;
- size_t tag_len = 0;
- if (IsBinary(log_id)) {
- int32_t numeric_tag = MsgToTag(msg, len);
- tag = tags_->tagToName(numeric_tag);
- if (tag) {
- tag_len = strlen(tag);
- }
- } else {
- prio = *msg;
- tag = msg + 1;
- tag_len = strnlen(tag, len - 1);
- }
- return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
-}
-
-int SimpleLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- if (log_id >= LOG_ID_MAX) {
- return -EINVAL;
- }
-
- if (!ShouldLog(log_id, msg, len)) {
- // Log traffic received to total
- stats_->AddTotal(log_id, len);
- return -EACCES;
- }
-
- // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
- // This prevents any chance that an outside source can request an
- // exact entry with time specified in ms or us precision.
- if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
-
- auto lock = std::lock_guard{logd_lock};
- auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
- LogInternal(LogBufferElement(log_id, realtime, uid, pid, tid, sequence, msg, len));
- return len;
-}
-
-void SimpleLogBuffer::LogInternal(LogBufferElement&& elem) {
- log_id_t log_id = elem.log_id();
-
- logs_.emplace_back(std::move(elem));
- stats_->Add(logs_.back().ToLogStatisticsElement());
- MaybePrune(log_id);
- reader_list_->NotifyNewLog(1 << log_id);
-}
-
-// These extra parameters are only required for chatty, but since they're a no-op for
-// SimpleLogBuffer, it's easier to include them here, then to duplicate FlushTo() for
-// ChattyLogBuffer.
-class ChattyFlushToState : public FlushToState {
- public:
- ChattyFlushToState(uint64_t start, LogMask log_mask) : FlushToState(start, log_mask) {}
-
- pid_t* last_tid() { return last_tid_; }
-
- bool drop_chatty_messages() const { return drop_chatty_messages_; }
- void set_drop_chatty_messages(bool value) { drop_chatty_messages_ = value; }
-
- private:
- pid_t last_tid_[LOG_ID_MAX] = {};
- bool drop_chatty_messages_ = true;
-};
-
-std::unique_ptr<FlushToState> SimpleLogBuffer::CreateFlushToState(uint64_t start,
- LogMask log_mask) {
- return std::make_unique<ChattyFlushToState>(start, log_mask);
-}
-
-bool SimpleLogBuffer::FlushTo(
- LogWriter* writer, FlushToState& abstract_state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) {
- auto& state = reinterpret_cast<ChattyFlushToState&>(abstract_state);
-
- std::list<LogBufferElement>::iterator it;
- if (state.start() <= 1) {
- // client wants to start from the beginning
- it = logs_.begin();
- } else {
- // Client wants to start from some specified time. Chances are
- // we are better off starting from the end of the time sorted list.
- for (it = logs_.end(); it != logs_.begin();
- /* do nothing */) {
- --it;
- if (it->sequence() == state.start()) {
- break;
- } else if (it->sequence() < state.start()) {
- it++;
- break;
- }
- }
- }
-
- for (; it != logs_.end(); ++it) {
- LogBufferElement& element = *it;
-
- state.set_start(element.sequence());
-
- if (!writer->privileged() && element.uid() != writer->uid()) {
- continue;
- }
-
- if (((1 << element.log_id()) & state.log_mask()) == 0) {
- continue;
- }
-
- if (filter) {
- FilterResult ret =
- filter(element.log_id(), element.pid(), element.sequence(), element.realtime());
- if (ret == FilterResult::kSkip) {
- continue;
- }
- if (ret == FilterResult::kStop) {
- break;
- }
- }
-
- // drop_chatty_messages is initialized to true, so if the first message that we attempt to
- // flush is a chatty message, we drop it. Once we see a non-chatty message it gets set to
- // false to let further chatty messages be printed.
- if (state.drop_chatty_messages()) {
- if (element.dropped_count() != 0) {
- continue;
- }
- state.set_drop_chatty_messages(false);
- }
-
- bool same_tid = state.last_tid()[element.log_id()] == element.tid();
- // Dropped (chatty) immediately following a valid log from the same source in the same log
- // buffer indicates we have a multiple identical squash. chatty that differs source is due
- // to spam filter. chatty to chatty of different source is also due to spam filter.
- state.last_tid()[element.log_id()] =
- (element.dropped_count() && !same_tid) ? 0 : element.tid();
-
- logd_lock.unlock();
- // We never prune logs equal to or newer than any LogReaderThreads' `start` value, so the
- // `element` pointer is safe here without the lock
- if (!element.FlushTo(writer, stats_, same_tid)) {
- logd_lock.lock();
- return false;
- }
- logd_lock.lock();
- }
-
- state.set_start(state.start() + 1);
- return true;
-}
-
-bool SimpleLogBuffer::Clear(log_id_t id, uid_t uid) {
- // Try three times to clear, then disconnect the readers and try one final time.
- for (int retry = 0; retry < 3; ++retry) {
- {
- auto lock = std::lock_guard{logd_lock};
- if (Prune(id, ULONG_MAX, uid)) {
- return true;
- }
- }
- sleep(1);
- }
- // Check if it is still busy after the sleep, we try to prune one entry, not another clear run,
- // so we are looking for the quick side effect of the return value to tell us if we have a
- // _blocked_ reader.
- bool busy = false;
- {
- auto lock = std::lock_guard{logd_lock};
- busy = !Prune(id, 1, uid);
- }
- // It is still busy, disconnect all readers.
- if (busy) {
- auto lock = std::lock_guard{logd_lock};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (reader_thread->IsWatching(id)) {
- LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
- << ", from LogBuffer::clear()";
- reader_thread->Release();
- }
- }
- }
- auto lock = std::lock_guard{logd_lock};
- return Prune(id, ULONG_MAX, uid);
-}
-
-// get the total space allocated to "id"
-size_t SimpleLogBuffer::GetSize(log_id_t id) {
- auto lock = std::lock_guard{logd_lock};
- size_t retval = max_size_[id];
- return retval;
-}
-
-// set the total space allocated to "id"
-bool SimpleLogBuffer::SetSize(log_id_t id, size_t size) {
- // Reasonable limits ...
- if (!IsValidBufferSize(size)) {
- return false;
- }
-
- auto lock = std::lock_guard{logd_lock};
- max_size_[id] = size;
- return true;
-}
-
-void SimpleLogBuffer::MaybePrune(log_id_t id) {
- unsigned long prune_rows;
- if (stats_->ShouldPrune(id, max_size_[id], &prune_rows)) {
- Prune(id, prune_rows, 0);
- }
-}
-
-bool SimpleLogBuffer::Prune(log_id_t id, unsigned long prune_rows, uid_t caller_uid) {
- // Don't prune logs that are newer than the point at which any reader threads are reading from.
- LogReaderThread* oldest = nullptr;
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (!reader_thread->IsWatching(id)) {
- continue;
- }
- if (!oldest || oldest->start() > reader_thread->start() ||
- (oldest->start() == reader_thread->start() &&
- reader_thread->deadline().time_since_epoch().count() != 0)) {
- oldest = reader_thread.get();
- }
- }
-
- auto it = GetOldest(id);
-
- while (it != logs_.end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
-
- if (caller_uid != 0 && element.uid() != caller_uid) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, prune_rows);
- return false;
- }
-
- stats_->Subtract(element.ToLogStatisticsElement());
- it = Erase(it);
- if (--prune_rows == 0) {
- return true;
- }
- }
- return true;
-}
-
-std::list<LogBufferElement>::iterator SimpleLogBuffer::Erase(
- std::list<LogBufferElement>::iterator it) {
- bool oldest_is_it[LOG_ID_MAX];
- log_id_for_each(i) { oldest_is_it[i] = oldest_[i] && it == *oldest_[i]; }
-
- it = logs_.erase(it);
-
- log_id_for_each(i) {
- if (oldest_is_it[i]) {
- if (__predict_false(it == logs().end())) {
- oldest_[i] = std::nullopt;
- } else {
- oldest_[i] = it; // Store the next iterator even if it does not correspond to
- // the same log_id, as a starting point for GetOldest().
- }
- }
- }
-
- return it;
-}
-
-// If the selected reader is blocking our pruning progress, decide on
-// what kind of mitigation is necessary to unblock the situation.
-void SimpleLogBuffer::KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows) {
- if (stats_->Sizes(id) > (2 * max_size_[id])) { // +100%
- // A misbehaving or slow reader has its connection
- // dropped if we hit too much memory pressure.
- LOG(WARNING) << "Kicking blocked reader, " << reader->name()
- << ", from LogBuffer::kickMe()";
- reader->Release();
- } else if (reader->deadline().time_since_epoch().count() != 0) {
- // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
- reader->TriggerReader();
- } else {
- // tell slow reader to skip entries to catch up
- LOG(WARNING) << "Skipping " << prune_rows << " entries from slow reader, " << reader->name()
- << ", from LogBuffer::kickMe()";
- reader->TriggerSkip(id, prune_rows);
- }
-}
diff --git a/logd/SimpleLogBuffer.h b/logd/SimpleLogBuffer.h
deleted file mode 100644
index 51779ab..0000000
--- a/logd/SimpleLogBuffer.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 <atomic>
-#include <list>
-#include <mutex>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogdLock.h"
-
-class SimpleLogBuffer : public LogBuffer {
- public:
- SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats);
- ~SimpleLogBuffer();
- void Init() override final;
-
- 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;
- std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask)
- REQUIRES(logd_lock) override;
- bool FlushTo(LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter)
- REQUIRES(logd_lock) override;
-
- bool Clear(log_id_t id, uid_t uid) override;
- size_t GetSize(log_id_t id) override;
- bool SetSize(log_id_t id, size_t size) override final;
-
- uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
-
- protected:
- virtual bool Prune(log_id_t id, unsigned long prune_rows, uid_t uid) REQUIRES(logd_lock);
- virtual void LogInternal(LogBufferElement&& elem) REQUIRES(logd_lock);
-
- // Returns an iterator to the oldest element for a given log type, or logs_.end() if
- // there are no logs for the given log type. Requires logs_logd_lock to be held.
- std::list<LogBufferElement>::iterator GetOldest(log_id_t log_id) REQUIRES(logd_lock);
- std::list<LogBufferElement>::iterator Erase(std::list<LogBufferElement>::iterator it)
- REQUIRES(logd_lock);
- void KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows)
- REQUIRES(logd_lock);
-
- LogStatistics* stats() { return stats_; }
- LogReaderList* reader_list() { return reader_list_; }
- size_t max_size(log_id_t id) REQUIRES_SHARED(logd_lock) { return max_size_[id]; }
- std::list<LogBufferElement>& logs() { return logs_; }
-
- private:
- bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
- void MaybePrune(log_id_t id) REQUIRES(logd_lock);
-
- LogReaderList* reader_list_;
- LogTags* tags_;
- LogStatistics* stats_;
-
- std::atomic<uint64_t> sequence_ = 1;
-
- size_t max_size_[LOG_ID_MAX] GUARDED_BY(logd_lock);
- std::list<LogBufferElement> logs_ GUARDED_BY(logd_lock);
- // Keeps track of the iterator to the oldest log message of a given log type, as an
- // optimization when pruning logs. Use GetOldest() to retrieve.
- std::optional<std::list<LogBufferElement>::iterator> oldest_[LOG_ID_MAX] GUARDED_BY(logd_lock);
-};
diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp
deleted file mode 100644
index 98bb02d..0000000
--- a/logd/auditctl.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2019 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 <android-base/parseint.h>
-#include <error.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "libaudit.h"
-
-static void usage(const char* cmdline) {
- fprintf(stderr, "Usage: %s [-r rate]\n", cmdline);
-}
-
-static void do_update_rate(uint32_t rate) {
- int fd = audit_open();
- if (fd == -1) {
- error(EXIT_FAILURE, errno, "Unable to open audit socket");
- }
- int result = audit_rate_limit(fd, rate);
- close(fd);
- if (result < 0) {
- fprintf(stderr, "Can't update audit rate limit: %d\n", result);
- exit(EXIT_FAILURE);
- }
-}
-
-int main(int argc, char* argv[]) {
- uint32_t rate = 0;
- bool update_rate = false;
- int opt;
-
- while ((opt = getopt(argc, argv, "r:")) != -1) {
- switch (opt) {
- case 'r':
- if (!android::base::ParseUint<uint32_t>(optarg, &rate)) {
- error(EXIT_FAILURE, errno, "Invalid Rate");
- }
- update_rate = true;
- break;
- default: /* '?' */
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- }
-
- // In the future, we may add other options to auditctl
- // so this if statement will expand.
- // if (!update_rate && !update_backlog && !update_whatever) ...
- if (!update_rate) {
- fprintf(stderr, "Nothing to do\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (update_rate) {
- do_update_rate(rate);
- }
-
- return 0;
-}
diff --git a/logd/doc_images/cpu_cuttlefish.png b/logd/doc_images/cpu_cuttlefish.png
deleted file mode 100644
index 8d809ca..0000000
--- a/logd/doc_images/cpu_cuttlefish.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/cpu_walleye.png b/logd/doc_images/cpu_walleye.png
deleted file mode 100644
index 39c951b..0000000
--- a/logd/doc_images/cpu_walleye.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/memory_usage.png b/logd/doc_images/memory_usage.png
deleted file mode 100644
index 434d6d3..0000000
--- a/logd/doc_images/memory_usage.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/total_log_count.png b/logd/doc_images/total_log_count.png
deleted file mode 100644
index e73c2c1..0000000
--- a/logd/doc_images/total_log_count.png
+++ /dev/null
Binary files differ
diff --git a/logd/event.logtags b/logd/event.logtags
deleted file mode 100644
index fa13a62..0000000
--- a/logd/event.logtags
+++ /dev/null
@@ -1,39 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-1003 auditd (avc|3)
-1004 chatty (dropped|3)
-1005 tag_def (tag|1),(name|3),(format|3)
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
deleted file mode 100644
index d346cd7..0000000
--- a/logd/fuzz/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-cc_defaults {
- name: "log_fuzzer_defaults",
- static_libs: [
- "libbase",
- "libcutils",
- "libselinux",
- "liblog",
- "liblogd",
- "libcutils",
- "libz",
- "libzstd",
- ],
- cflags: ["-Wextra"],
- host_supported: true,
-}
-
-cc_fuzz {
- name: "log_buffer_log_fuzzer",
- defaults: ["log_fuzzer_defaults"],
- srcs: [
- "log_buffer_log_fuzzer.cpp",
- ],
-}
-
-cc_fuzz {
- name: "serialized_log_buffer_fuzzer",
- defaults: ["log_fuzzer_defaults"],
- srcs: [
- "serialized_log_buffer_fuzzer.cpp",
- ],
- corpus: [
- "corpus/logentry_use_after_compress",
- ]
-}
diff --git a/logd/fuzz/corpus/logentry_use_after_compress b/logd/fuzz/corpus/logentry_use_after_compress
deleted file mode 100644
index 2081b13..0000000
--- a/logd/fuzz/corpus/logentry_use_after_compress
+++ /dev/null
Binary files differ
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
deleted file mode 100644
index 2fe9407..0000000
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2019 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 <string>
-
-#include <android-base/logging.h>
-
-#include "../ChattyLogBuffer.h"
-#include "../LogReaderList.h"
-#include "../LogReaderThread.h"
-#include "../LogStatistics.h"
-#include "../SerializedLogBuffer.h"
-
-// We don't want to waste a lot of entropy on messages
-#define MAX_MSG_LENGTH 5
-
-// Tag IDs usually start at 1000, we only want to try 1000 through 1009
-#define MIN_TAG_ID 1000
-#define TAG_MOD 10
-
-char* android::uidToName(uid_t) {
- return strdup("fake");
-}
-
-struct LogInput {
- public:
- log_id_t log_id;
- log_time realtime;
- uid_t uid;
- pid_t pid;
- pid_t tid;
- unsigned int log_mask;
-};
-
-int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer,
- LogStatistics* stats) {
- const uint8_t* data = *pdata;
- const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
- data += sizeof(LogInput);
- *data_left -= sizeof(LogInput);
-
- uint32_t tag = MIN_TAG_ID + data[0] % TAG_MOD;
- uint8_t msg_length = data[1] % MAX_MSG_LENGTH;
- if (msg_length < 2) {
- // Not enough data for message
- return 0;
- }
-
- data += 2 * sizeof(uint8_t);
- *data_left -= 2 * sizeof(uint8_t);
-
- if (*data_left < msg_length) {
- // Not enough data for tag and message
- *pdata = data;
- return 0;
- }
-
- // We need nullterm'd strings
- char msg[sizeof(uint32_t) + MAX_MSG_LENGTH + sizeof(char)];
- char* msg_only = msg + sizeof(uint32_t);
- memcpy(msg, &tag, sizeof(uint32_t));
- memcpy(msg_only, data, msg_length);
- msg_only[msg_length] = '\0';
- data += msg_length;
- *data_left -= msg_length;
-
- // Other elements not in enum.
- log_id_t log_id = static_cast<log_id_t>(unsigned(logInput->log_id) % (LOG_ID_MAX + 1));
- log_buffer->Log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
- sizeof(uint32_t) + msg_length + 1);
- stats->Format(logInput->uid, logInput->pid, logInput->log_mask);
- *pdata = data;
- return 1;
-}
-
-class NoopWriter : public LogWriter {
- public:
- NoopWriter() : LogWriter(0, true) {}
- bool Write(const logger_entry&, const char*) override { return true; }
-
- std::string name() const override { return "noop_writer"; }
-};
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- // We want a random tag length and a random remaining message length
- if (data == nullptr || size < sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- return 0;
- }
-
- android::base::SetMinimumLogSeverity(android::base::ERROR);
-
- LogReaderList reader_list;
- LogTags tags;
- PruneList prune_list;
- LogStatistics stats(true, true);
- std::unique_ptr<LogBuffer> log_buffer;
-#ifdef FUZZ_SERIALIZED
- log_buffer.reset(new SerializedLogBuffer(&reader_list, &tags, &stats));
-#else
- log_buffer.reset(new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats));
-#endif
- size_t data_left = size;
- const uint8_t** pdata = &data;
-
- prune_list.Init(nullptr);
- // We want to get pruning code to get called.
- log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
-
- while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- if (!write_log_messages(pdata, &data_left, log_buffer.get(), &stats)) {
- return 0;
- }
- }
-
- // Read out all of the logs.
- {
- auto lock = std::unique_lock{logd_lock};
- std::unique_ptr<LogWriter> test_writer(new NoopWriter());
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer.get(), &reader_list, std::move(test_writer), true, 0,
- kLogMaskAll, 0, {}, 1, {}));
- reader_list.reader_threads().emplace_back(std::move(log_reader));
- }
-
- // Wait until the reader has finished.
- while (true) {
- usleep(50);
- auto lock = std::unique_lock{logd_lock};
- if (reader_list.reader_threads().size() == 0) {
- break;
- }
- }
-
- log_id_for_each(i) { log_buffer->Clear(i, 0); }
- return 0;
-}
diff --git a/logd/fuzz/serialized_log_buffer_fuzzer.cpp b/logd/fuzz/serialized_log_buffer_fuzzer.cpp
deleted file mode 100644
index d4795b0..0000000
--- a/logd/fuzz/serialized_log_buffer_fuzzer.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define FUZZ_SERIALIZED
-
-#include "log_buffer_log_fuzzer.cpp"
diff --git a/logd/libaudit.cpp b/logd/libaudit.cpp
deleted file mode 100644
index ccea0a2..0000000
--- a/logd/libaudit.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012, Samsung Telecommunications of America
- * Copyright (C) 2014 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.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- *
- */
-
-#include "libaudit.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <limits>
-
-/**
- * Waits for an ack from the kernel
- * @param fd
- * The netlink socket fd
- * @return
- * This function returns 0 on success, else -errno.
- */
-static int get_ack(int fd) {
- struct audit_message rep = {};
- int rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
- if (rc < 0) {
- return rc;
- }
-
- if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
- audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
- rc = reinterpret_cast<struct nlmsgerr*>(rep.data)->error;
- if (rc) {
- return -rc;
- }
- }
-
- return 0;
-}
-
-/**
- *
- * @param fd
- * The netlink socket fd
- * @param type
- * The type of netlink message
- * @param data
- * The data to send
- * @param size
- * The length of the data in bytes
- * @return
- * This function returns a positive sequence number on success, else -errno.
- */
-static int audit_send(int fd, int type, const void* data, size_t size) {
- struct sockaddr_nl addr = {.nl_family = AF_NETLINK};
-
- /* Set up the netlink headers */
- struct audit_message req = {};
- req.nlh.nlmsg_type = static_cast<uint16_t>(type);
- req.nlh.nlmsg_len = NLMSG_SPACE(size);
- req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
- /*
- * Check for a valid fd, even though sendto would catch this, its easier
- * to always blindly increment the sequence number
- */
- if (fd < 0) {
- return -EBADF;
- }
-
- /* Ensure the message is not too big */
- if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
- return -EINVAL;
- }
-
- /* Only memcpy in the data if it was specified */
- if (size && data) {
- memcpy(NLMSG_DATA(&req.nlh), data, size);
- }
-
- /*
- * Only increment the sequence number on a guarantee
- * you will send it to the kernel.
- */
- static uint32_t sequence = 0;
- if (sequence == std::numeric_limits<uint32_t>::max()) {
- sequence = 1;
- } else {
- sequence++;
- }
- req.nlh.nlmsg_seq = sequence;
-
- ssize_t rc = TEMP_FAILURE_RETRY(
- sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr)));
-
- /* Not all the bytes were sent */
- if (rc < 0) {
- return -errno;
- } else if ((uint32_t)rc != req.nlh.nlmsg_len) {
- return -EPROTO;
- }
-
- /* We sent all the bytes, get the ack */
- rc = get_ack(fd);
-
- /* If the ack failed, return the error, else return the sequence number */
- rc = (rc == 0) ? (int)sequence : rc;
-
- return rc;
-}
-
-int audit_setup(int fd, pid_t pid) {
- /*
- * In order to set the auditd PID we send an audit message over the netlink
- * socket with the pid field of the status struct set to our current pid,
- * and the the mask set to AUDIT_STATUS_PID
- */
- struct audit_status status = {
- .mask = AUDIT_STATUS_PID,
- .pid = static_cast<uint32_t>(pid),
- };
-
- /* Let the kernel know this pid will be registering for audit events */
- int rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
- if (rc < 0) {
- return rc;
- }
-
- /*
- * In a request where we need to wait for a response, wait for the message
- * and discard it. This message confirms and sync's us with the kernel.
- * This daemon is now registered as the audit logger.
- *
- * TODO
- * If the daemon dies and restarts the message didn't come back,
- * so I went to non-blocking and it seemed to fix the bug.
- * Need to investigate further.
- */
- struct audit_message rep = {};
- audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
-
- return 0;
-}
-
-int audit_open() {
- return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
-}
-
-int audit_rate_limit(int fd, uint32_t limit) {
- struct audit_status status = {
- .mask = AUDIT_STATUS_RATE_LIMIT, .rate_limit = limit, /* audit entries per second */
- };
- return audit_send(fd, AUDIT_SET, &status, sizeof(status));
-}
-
-int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
- if (fd < 0) {
- return -EBADF;
- }
-
- int flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
- flags |= peek;
-
- /*
- * Get the data from the netlink socket but on error we need to be carefull,
- * the interface shows that EINTR can never be returned, other errors,
- * however, can be returned.
- */
- struct sockaddr_nl nladdr;
- socklen_t nladdrlen = sizeof(nladdr);
- ssize_t len = TEMP_FAILURE_RETRY(
- recvfrom(fd, rep, sizeof(*rep), flags, (struct sockaddr*)&nladdr, &nladdrlen));
-
- /*
- * EAGAIN should be re-tried until success or another error manifests.
- */
- if (len < 0) {
- if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
- /* If request is non blocking and errno is EAGAIN, just return 0 */
- return 0;
- }
- return -errno;
- }
-
- if (nladdrlen != sizeof(nladdr)) {
- return -EPROTO;
- }
-
- /* Make sure the netlink message was not spoof'd */
- if (nladdr.nl_pid) {
- return -EINVAL;
- }
-
- /* Check if the reply from the kernel was ok */
- if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
- return len == sizeof(*rep) ? -EFBIG : -EBADE;
- }
-
- return 0;
-}
-
-void audit_close(int fd) {
- close(fd);
-}
diff --git a/logd/libaudit.h b/logd/libaudit.h
deleted file mode 100644
index 27b0866..0000000
--- a/logd/libaudit.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012, Samsung Telecommunications of America
- * Copyright (C) 2014 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.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/cdefs.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <linux/audit.h>
-#include <linux/netlink.h>
-
-__BEGIN_DECLS
-
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
-
-typedef enum { GET_REPLY_BLOCKING = 0, GET_REPLY_NONBLOCKING } reply_t;
-
-/* type == AUDIT_SIGNAL_INFO */
-struct audit_sig_info {
- uid_t uid;
- pid_t pid;
- char ctx[0];
-};
-
-struct audit_message {
- struct nlmsghdr nlh;
- char data[MAX_AUDIT_MESSAGE_LENGTH];
-};
-
-/**
- * Opens a connection to the Audit netlink socket
- * @return
- * A valid fd on success or < 0 on error with errno set.
- * Returns the same errors as man 2 socket.
- */
-extern int audit_open(void);
-
-/**
- * Closes the fd returned from audit_open()
- * @param fd
- * The fd to close
- */
-extern void audit_close(int fd);
-
-/**
- *
- * @param fd
- * The fd returned by a call to audit_open()
- * @param rep
- * The response struct to store the response in.
- * @param block
- * Whether or not to block on IO
- * @param peek
- * Whether or not we are to remove the message from
- * the queue when we do a read on the netlink socket.
- * @return
- * This function returns 0 on success, else -errno.
- */
-extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
- int peek);
-
-/**
- * Sets a pid to receive audit netlink events from the kernel
- * @param fd
- * The fd returned by a call to audit_open()
- * @param pid
- * The pid whom to set as the receiver of audit messages
- * @return
- * This function returns 0 on success, -errno on error.
- */
-extern int audit_setup(int fd, pid_t pid);
-
-/**
- * Throttle kernel messages at the provided rate
- * @param fd
- * The fd returned by a call to audit_open()
- * @param rate
- * The rate, in messages per second, above which the kernel
- * should drop audit messages.
- * @return
- * This function returns 0 on success, -errno on error.
- */
-extern int audit_rate_limit(int fd, uint32_t limit);
-
-__END_DECLS
diff --git a/logd/logd.rc b/logd/logd.rc
deleted file mode 100644
index 530f342..0000000
--- a/logd/logd.rc
+++ /dev/null
@@ -1,35 +0,0 @@
-service logd /system/bin/logd
- socket logd stream 0666 logd logd
- socket logdr seqpacket 0666 logd logd
- socket logdw dgram+passcred 0222 logd logd
- file /proc/kmsg r
- file /dev/kmsg w
- user logd
- group logd system package_info readproc
- capabilities SYSLOG AUDIT_CONTROL
- priority 10
- writepid /dev/cpuset/system-background/tasks
-
-service logd-reinit /system/bin/logd --reinit
- oneshot
- disabled
- user logd
- group logd
- writepid /dev/cpuset/system-background/tasks
-
-# Limit SELinux denial generation to 5/second
-service logd-auditctl /system/bin/auditctl -r 5
- oneshot
- disabled
- user logd
- group logd
- capabilities AUDIT_CONTROL
-
-on fs
- write /dev/event-log-tags "# content owned by logd
-"
- chown logd logd /dev/event-log-tags
- chmod 0644 /dev/event-log-tags
-
-on property:sys.boot_completed=1
- start logd-auditctl
diff --git a/logd/logd_test.cpp b/logd/logd_test.cpp
deleted file mode 100644
index 828f580..0000000
--- a/logd/logd_test.cpp
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright (C) 2014 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 <ctype.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-#include <gtest/gtest.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#ifdef __ANDROID__
-#include <selinux/selinux.h>
-#endif
-
-#include "LogUtils.h" // For LOGD_SNDTIMEO.
-
-using android::base::unique_fd;
-
-#ifdef __ANDROID__
-static void send_to_control(char* buf, size_t len) {
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock >= 0) {
- if (write(sock, buf, strlen(buf) + 1) > 0) {
- ssize_t ret;
- while ((ret = read(sock, buf, len)) > 0) {
- if (((size_t)ret == len) || (len < PAGE_SIZE)) {
- break;
- }
- len -= ret;
- buf += ret;
-
- struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
-
- ret = poll(&p, 1, 20);
- if ((ret <= 0) || !(p.revents & POLLIN)) {
- break;
- }
- }
- }
- close(sock);
- }
-}
-
-/*
- * returns statistics
- */
-static void my_android_logger_get_statistics(char* buf, size_t len) {
- snprintf(buf, len, "getStatistics 0 1 2 3 4");
- send_to_control(buf, len);
-}
-
-static void alloc_statistics(char** buffer, size_t* length) {
- size_t len = 8192;
- char* buf;
-
- for (int retry = 32; (retry >= 0); delete[] buf, --retry) {
- buf = new char[len];
- my_android_logger_get_statistics(buf, len);
-
- buf[len - 1] = '\0';
- size_t ret = atol(buf) + 1;
- if (ret < 4) {
- delete[] buf;
- buf = nullptr;
- break;
- }
- bool check = ret <= len;
- len = ret;
- if (check) {
- break;
- }
- len += len / 8; // allow for some slop
- }
- *buffer = buf;
- *length = len;
-}
-
-static char* find_benchmark_spam(char* cp) {
- // liblog_benchmarks has been run designed to SPAM. The signature of
- // a noisiest UID statistics is:
- //
- // Chattiest UIDs in main log buffer: Size Pruned
- // UID PACKAGE BYTES LINES
- // 0 root 54164 147569
- //
- char* benchmark = nullptr;
- do {
- static const char signature[] = "\n0 root ";
-
- benchmark = strstr(cp, signature);
- if (!benchmark) {
- break;
- }
- cp = benchmark + sizeof(signature);
- while (isspace(*cp)) {
- ++cp;
- }
- benchmark = cp;
-#ifdef DEBUG
- char* end = strstr(benchmark, "\n");
- if (end == nullptr) {
- end = benchmark + strlen(benchmark);
- }
- fprintf(stderr, "parse for spam counter in \"%.*s\"\n",
- (int)(end - benchmark), benchmark);
-#endif
- // content
- while (isdigit(*cp)) {
- ++cp;
- }
- while (isspace(*cp)) {
- ++cp;
- }
- // optional +/- field?
- if ((*cp == '-') || (*cp == '+')) {
- while (isdigit(*++cp) || (*cp == '.') || (*cp == '%') ||
- (*cp == 'X')) {
- ;
- }
- while (isspace(*cp)) {
- ++cp;
- }
- }
- // number of entries pruned
- unsigned long value = 0;
- while (isdigit(*cp)) {
- value = value * 10ULL + *cp - '0';
- ++cp;
- }
- if (value > 10UL) {
- break;
- }
- benchmark = nullptr;
- } while (*cp);
- return benchmark;
-}
-#endif
-
-#ifdef LOGD_ENABLE_FLAKY_TESTS
-TEST(logd, statistics) {
-#ifdef __ANDROID__
- size_t len;
- char* buf;
-
- // Drop cache so that any access problems can be discovered.
- if (!android::base::WriteStringToFile("3\n", "/proc/sys/vm/drop_caches")) {
- GTEST_LOG_(INFO) << "Could not open trigger dropping inode cache";
- }
-
- alloc_statistics(&buf, &len);
-
- ASSERT_TRUE(nullptr != buf);
-
- // remove trailing FF
- char* cp = buf + len - 1;
- *cp = '\0';
- bool truncated = *--cp != '\f';
- if (!truncated) {
- *cp = '\0';
- }
-
- // squash out the byte count
- cp = buf;
- if (!truncated) {
- while (isdigit(*cp) || (*cp == '\n')) {
- ++cp;
- }
- }
-
- fprintf(stderr, "%s", cp);
-
- EXPECT_LT((size_t)64, strlen(cp));
-
- EXPECT_EQ(0, truncated);
-
- char* main_logs = strstr(cp, "\nChattiest UIDs in main ");
- EXPECT_TRUE(nullptr != main_logs);
-
- char* radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
- if (!radio_logs)
- GTEST_LOG_(INFO) << "Value of: nullptr != radio_logs\n"
- "Actual: false\n"
- "Expected: false\n";
-
- char* system_logs = strstr(cp, "\nChattiest UIDs in system ");
- EXPECT_TRUE(nullptr != system_logs);
-
- char* events_logs = strstr(cp, "\nChattiest UIDs in events ");
- EXPECT_TRUE(nullptr != events_logs);
-
- // Check if there is any " u0_a#### " as this means packagelistparser broken
- char* used_getpwuid = nullptr;
- int used_getpwuid_len;
- char* uid_name = cp;
- static const char getpwuid_prefix[] = " u0_a";
- while ((uid_name = strstr(uid_name, getpwuid_prefix)) != nullptr) {
- used_getpwuid = uid_name + 1;
- uid_name += strlen(getpwuid_prefix);
- while (isdigit(*uid_name)) ++uid_name;
- used_getpwuid_len = uid_name - used_getpwuid;
- if (isspace(*uid_name)) break;
- used_getpwuid = nullptr;
- }
- EXPECT_TRUE(nullptr == used_getpwuid);
- if (used_getpwuid) {
- fprintf(stderr, "libpackagelistparser failed to pick up %.*s\n",
- used_getpwuid_len, used_getpwuid);
- }
-
- delete[] buf;
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-#ifdef __ANDROID__
-static void caught_signal(int /* signum */) {
-}
-
-static void dump_log_msg(const char* prefix, log_msg* msg, int lid) {
- std::cout << std::flush;
- std::cerr << std::flush;
- fflush(stdout);
- fflush(stderr);
- EXPECT_GE(msg->entry.hdr_size, sizeof(logger_entry));
-
- fprintf(stderr, "%s: [%u] ", prefix, msg->len());
- fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
- fprintf(stderr, "pid=%u tid=%u %u.%09u ", msg->entry.pid, msg->entry.tid, msg->entry.sec,
- msg->entry.nsec);
- lid = msg->entry.lid;
-
- switch (lid) {
- case 0:
- fprintf(stderr, "lid=main ");
- break;
- case 1:
- fprintf(stderr, "lid=radio ");
- break;
- case 2:
- fprintf(stderr, "lid=events ");
- break;
- case 3:
- fprintf(stderr, "lid=system ");
- break;
- case 4:
- fprintf(stderr, "lid=crash ");
- break;
- case 5:
- fprintf(stderr, "lid=security ");
- break;
- case 6:
- fprintf(stderr, "lid=kernel ");
- break;
- default:
- if (lid >= 0) {
- fprintf(stderr, "lid=%d ", lid);
- }
- }
-
- unsigned int len = msg->entry.len;
- fprintf(stderr, "msg[%u]={", len);
- unsigned char* cp = reinterpret_cast<unsigned char*>(msg->msg());
- if (!cp) {
- static const unsigned char garbage[] = "<INVALID>";
- cp = const_cast<unsigned char*>(garbage);
- len = strlen(reinterpret_cast<const char*>(garbage));
- }
- while (len) {
- unsigned char* p = cp;
- while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
- ++p;
- }
- if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
- fprintf(stderr, "\"");
- while (*cp) {
- if (*cp != '\n') {
- fprintf(stderr, "%c", *cp);
- } else {
- fprintf(stderr, "\\n");
- }
- ++cp;
- --len;
- }
- fprintf(stderr, "\"");
- } else {
- fprintf(stderr, "%02x", *cp);
- }
- ++cp;
- if (--len) {
- fprintf(stderr, ", ");
- }
- }
- fprintf(stderr, "}\n");
- fflush(stderr);
-}
-#endif
-
-#ifdef __ANDROID__
-// BAD ROBOT
-// Benchmark threshold are generally considered bad form unless there is
-// is some human love applied to the continued maintenance and whether the
-// thresholds are tuned on a per-target basis. Here we check if the values
-// are more than double what is expected. Doubling will not prevent failure
-// on busy or low-end systems that could have a tendency to stretch values.
-//
-// The primary goal of this test is to simulate a spammy app (benchmark
-// being the worst) and check to make sure the logger can deal with it
-// appropriately by checking all the statistics are in an expected range.
-//
-TEST(logd, benchmark) {
- size_t len;
- char* buf;
-
- alloc_statistics(&buf, &len);
- bool benchmark_already_run = buf && find_benchmark_spam(buf);
- delete[] buf;
-
- if (benchmark_already_run) {
- fprintf(stderr,
- "WARNING: spam already present and too much history\n"
- " false OK for prune by worst UID check\n");
- }
-
- FILE* fp;
-
- // Introduce some extreme spam for the worst UID filter
- ASSERT_TRUE(
- nullptr !=
- (fp = popen("/data/nativetest/liblog-benchmarks/liblog-benchmarks"
- " BM_log_maximum_retry"
- " BM_log_maximum"
- " BM_clock_overhead"
- " BM_log_print_overhead"
- " BM_log_latency"
- " BM_log_delay",
- "r")));
-
- char buffer[5120];
-
- static const char* benchmarks[] = {
- "BM_log_maximum_retry ", "BM_log_maximum ", "BM_clock_overhead ",
- "BM_log_print_overhead ", "BM_log_latency ", "BM_log_delay "
- };
- static const unsigned int log_maximum_retry = 0;
- static const unsigned int log_maximum = 1;
- static const unsigned int clock_overhead = 2;
- static const unsigned int log_print_overhead = 3;
- static const unsigned int log_latency = 4;
- static const unsigned int log_delay = 5;
-
- unsigned long ns[arraysize(benchmarks)];
-
- memset(ns, 0, sizeof(ns));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- for (unsigned i = 0; i < arraysize(ns); ++i) {
- char* cp = strstr(buffer, benchmarks[i]);
- if (!cp) {
- continue;
- }
- sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
- fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
- }
- }
- int ret = pclose(fp);
-
- if (!WIFEXITED(ret) || (WEXITSTATUS(ret) == 127)) {
- fprintf(stderr,
- "WARNING: "
- "/data/nativetest/liblog-benchmarks/liblog-benchmarks missing\n"
- " can not perform test\n");
- return;
- }
-
- EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
- EXPECT_NE(0UL, ns[log_maximum_retry]); // failure to parse
-
- EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
- EXPECT_NE(0UL, ns[log_maximum]); // failure to parse
-
- EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
- EXPECT_NE(0UL, ns[clock_overhead]); // failure to parse
-
- EXPECT_GE(250000UL, ns[log_print_overhead]); // 126886 user
- EXPECT_NE(0UL, ns[log_print_overhead]); // failure to parse
-
- EXPECT_GE(10000000UL,
- ns[log_latency]); // 1453559 user space (background cgroup)
- EXPECT_NE(0UL, ns[log_latency]); // failure to parse
-
- EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
- EXPECT_NE(0UL, ns[log_delay]); // failure to parse
-
- alloc_statistics(&buf, &len);
-
- bool collected_statistics = !!buf;
- EXPECT_EQ(true, collected_statistics);
-
- ASSERT_TRUE(nullptr != buf);
-
- char* benchmark_statistics_found = find_benchmark_spam(buf);
- ASSERT_TRUE(benchmark_statistics_found != nullptr);
-
- // Check how effective the SPAM filter is, parse out Now size.
- // 0 root 54164 147569
- // ^-- benchmark_statistics_found
-
- unsigned long nowSpamSize = atol(benchmark_statistics_found);
-
- delete[] buf;
-
- ASSERT_NE(0UL, nowSpamSize);
-
- // Determine if we have the spam filter enabled
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
-
- ASSERT_TRUE(sock >= 0);
-
- static const char getPruneList[] = "getPruneList";
- if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
- char buffer[80];
- memset(buffer, 0, sizeof(buffer));
- read(sock, buffer, sizeof(buffer));
- char* cp = strchr(buffer, '\n');
- if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
- close(sock);
- fprintf(stderr,
- "WARNING: "
- "Logger has SPAM filtration turned off \"%s\"\n",
- buffer);
- return;
- }
- } else {
- int save_errno = errno;
- close(sock);
- FAIL() << "Can not send " << getPruneList << " to logger -- "
- << strerror(save_errno);
- }
-
- static const unsigned long expected_absolute_minimum_log_size = 65536UL;
- unsigned long totalSize = expected_absolute_minimum_log_size;
- static const char getSize[] = { 'g', 'e', 't', 'L', 'o', 'g',
- 'S', 'i', 'z', 'e', ' ', LOG_ID_MAIN + '0',
- '\0' };
- if (write(sock, getSize, sizeof(getSize)) > 0) {
- char buffer[80];
- memset(buffer, 0, sizeof(buffer));
- read(sock, buffer, sizeof(buffer));
- totalSize = atol(buffer);
- if (totalSize < expected_absolute_minimum_log_size) {
- fprintf(stderr,
- "WARNING: "
- "Logger had unexpected referenced size \"%s\"\n",
- buffer);
- totalSize = expected_absolute_minimum_log_size;
- }
- }
- close(sock);
-
- // logd allows excursions to 110% of total size
- totalSize = (totalSize * 11) / 10;
-
- // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
- ASSERT_GT(totalSize, nowSpamSize * 2);
-}
-#endif
-
-// b/26447386 confirm fixed
-void timeout_negative(const char* command) {
-#ifdef __ANDROID__
- log_msg msg_wrap, msg_timeout;
- bool content_wrap = false, content_timeout = false, written = false;
- unsigned int alarm_wrap = 0, alarm_timeout = 0;
- // A few tries to get it right just in case wrap kicks in due to
- // content providers being active during the test.
- int i = 3;
-
- while (--i) {
- int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- ASSERT_LT(0, fd);
-
- std::string ask(command);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(3);
-
- size_t len = ask.length() + 1;
- written = write(fd, ask.c_str(), len) == (ssize_t)len;
- if (!written) {
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
- close(fd);
- continue;
- }
-
- // alarm triggers at 50% of the --wrap time out
- content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
-
- alarm_wrap = alarm(5);
-
- // alarm triggers at 133% of the --wrap time out
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout =
- recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- }
-
- if (old_alarm > 0) {
- unsigned int time_spent = 3 - alarm_wrap;
- if (old_alarm > time_spent + 1) {
- old_alarm -= time_spent;
- } else {
- old_alarm = 2;
- }
- }
- alarm_timeout = alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- close(fd);
-
- if (content_wrap && alarm_wrap && content_timeout && alarm_timeout) {
- break;
- }
- }
-
- if (content_wrap) {
- dump_log_msg("wrap", &msg_wrap, -1);
- }
-
- if (content_timeout) {
- dump_log_msg("timeout", &msg_timeout, -1);
- }
-
- EXPECT_TRUE(written);
- EXPECT_TRUE(content_wrap);
- EXPECT_NE(0U, alarm_wrap);
- EXPECT_TRUE(content_timeout);
- EXPECT_NE(0U, alarm_timeout);
-#else
- command = nullptr;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, timeout_no_start) {
- timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6");
-}
-
-TEST(logd, timeout_start_epoch) {
- timeout_negative(
- "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-// b/26447386 refined behavior
-TEST(logd, timeout) {
-#ifdef __ANDROID__
- // b/33962045 This test interferes with other log reader tests that
- // follow because of file descriptor socket persistence in the same
- // process. So let's fork it to isolate it from giving us pain.
-
- pid_t pid = fork();
-
- if (pid) {
- siginfo_t info = {};
- ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
- ASSERT_EQ(0, info.si_status);
- return;
- }
-
- log_msg msg_wrap, msg_timeout;
- bool content_wrap = false, content_timeout = false, written = false;
- unsigned int alarm_wrap = 0, alarm_timeout = 0;
- // A few tries to get it right just in case wrap kicks in due to
- // content providers being active during the test.
- int i = 5;
- log_time start(CLOCK_REALTIME);
- start.tv_sec -= 30; // reach back a moderate period of time
-
- while (--i) {
- int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- int save_errno = errno;
- if (fd < 0) {
- fprintf(stderr, "failed to open /dev/socket/logdr %s\n",
- strerror(save_errno));
- _exit(fd);
- }
-
- std::string ask = android::base::StringPrintf(
- "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
- ".%09" PRIu32,
- start.tv_sec, start.tv_nsec);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(3);
-
- size_t len = ask.length() + 1;
- written = write(fd, ask.c_str(), len) == (ssize_t)len;
- if (!written) {
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
- close(fd);
- continue;
- }
-
- // alarm triggers at 50% of the --wrap time out
- content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
-
- alarm_wrap = alarm(5);
-
- // alarm triggers at 133% of the --wrap time out
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout =
- recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- }
-
- if (old_alarm > 0) {
- unsigned int time_spent = 3 - alarm_wrap;
- if (old_alarm > time_spent + 1) {
- old_alarm -= time_spent;
- } else {
- old_alarm = 2;
- }
- }
- alarm_timeout = alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- close(fd);
-
- if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
- break;
- }
-
- // modify start time in case content providers are relatively
- // active _or_ inactive during the test.
- if (content_timeout) {
- log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
- if (msg < start) {
- fprintf(stderr, "%u.%09u < %u.%09u\n", msg_timeout.entry.sec,
- msg_timeout.entry.nsec, (unsigned)start.tv_sec,
- (unsigned)start.tv_nsec);
- _exit(-1);
- }
- if (msg > start) {
- start = msg;
- start.tv_sec += 30;
- log_time now = log_time(CLOCK_REALTIME);
- if (start > now) {
- start = now;
- --start.tv_sec;
- }
- }
- } else {
- start.tv_sec -= 120; // inactive, reach further back!
- }
- }
-
- if (content_wrap) {
- dump_log_msg("wrap", &msg_wrap, -1);
- }
-
- if (content_timeout) {
- dump_log_msg("timeout", &msg_timeout, -1);
- }
-
- if (content_wrap || !content_timeout) {
- fprintf(stderr, "start=%" PRIu32 ".%09" PRIu32 "\n", start.tv_sec,
- start.tv_nsec);
- }
-
- EXPECT_TRUE(written);
- EXPECT_FALSE(content_wrap);
- EXPECT_EQ(0U, alarm_wrap);
- EXPECT_TRUE(content_timeout);
- EXPECT_NE(0U, alarm_timeout);
-
- _exit(!written + content_wrap + alarm_wrap + !content_timeout +
- !alarm_timeout);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-#ifdef LOGD_ENABLE_FLAKY_TESTS
-// b/27242723 confirmed fixed
-TEST(logd, SNDTIMEO) {
-#ifdef __ANDROID__
- static const unsigned sndtimeo =
- LOGD_SNDTIMEO; // <sigh> it has to be done!
- static const unsigned sleep_time = sndtimeo + 3;
- static const unsigned alarm_time = sleep_time + 5;
-
- int fd;
-
- ASSERT_TRUE(
- (fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET)) > 0);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(alarm_time);
-
- static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
- bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
- EXPECT_TRUE(reader_requested);
-
- log_msg msg;
- bool read_one = recv(fd, msg.buf, sizeof(msg), 0) > 0;
-
- EXPECT_TRUE(read_one);
- if (read_one) {
- dump_log_msg("user", &msg, -1);
- }
-
- fprintf(stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
- sleep(sleep_time);
-
- // flush will block if we did not trigger. if it did, last entry returns 0
- int recv_ret;
- do {
- recv_ret = recv(fd, msg.buf, sizeof(msg), 0);
- } while (recv_ret > 0);
- int save_errno = (recv_ret < 0) ? errno : 0;
-
- EXPECT_NE(0U, alarm(old_alarm));
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- EXPECT_EQ(0, recv_ret);
- if (recv_ret > 0) {
- dump_log_msg("user", &msg, -1);
- }
- EXPECT_EQ(0, save_errno);
-
- close(fd);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-TEST(logd, getEventTag_list) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "getEventTag name=*");
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 4096);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, getEventTag_42) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "getEventTag id=42");
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != nullptr);
- EXPECT_TRUE(strstr(buffer, "answer") != nullptr);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, getEventTag_newentry) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- log_time now(CLOCK_MONOTONIC);
- char name[64];
- snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
- name);
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(new|1)") != nullptr);
- EXPECT_TRUE(strstr(buffer, name) != nullptr);
-// ToDo: also look for this in /data/misc/logd/event-log-tags and
-// /dev/event-log-tags.
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, no_epipe) {
-#ifdef __ANDROID__
- // Actually generating SIGPIPE in logd is racy, since we need to close the socket quicker than
- // logd finishes writing the data to it, so we try 10 times, which should be enough to trigger
- // SIGPIPE if logd isn't ignoring SIGPIPE
- for (int i = 0; i < 10; ++i) {
- unique_fd sock1(
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- ASSERT_GT(sock1, 0);
- unique_fd sock2(
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- ASSERT_GT(sock2, 0);
-
- std::string message = "getStatistics 0 1 2 3 4 5 6 7";
-
- ASSERT_GT(write(sock1, message.c_str(), message.length()), 0);
- sock1.reset();
- ASSERT_GT(write(sock2, message.c_str(), message.length()), 0);
-
- struct pollfd p = {.fd = sock2, .events = POLLIN, .revents = 0};
-
- int ret = poll(&p, 1, 20);
- EXPECT_EQ(ret, 1);
- EXPECT_TRUE(p.revents & POLLIN);
- EXPECT_FALSE(p.revents & POLL_ERR);
- }
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/logd/logtagd.rc b/logd/logtagd.rc
deleted file mode 100644
index 248a78c..0000000
--- a/logd/logtagd.rc
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# logtagd event log tag service (debug only)
-#
-on post-fs-data
- mkdir /data/misc/logd 0750 logd log
- write /data/misc/logd/event-log-tags ""
- chown logd log /data/misc/logd/event-log-tags
- chmod 0600 /data/misc/logd/event-log-tags
- restorecon /data/misc/logd/event-log-tags
diff --git a/logd/main.cpp b/logd/main.cpp
deleted file mode 100644
index c92c5b7..0000000
--- a/logd/main.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/capability.h>
-#include <poll.h>
-#include <sched.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/capability.h>
-#include <sys/klog.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
-#include <log/event_tag_map.h>
-#include <packagelistparser/packagelistparser.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
-#include <utils/threads.h>
-
-#include "ChattyLogBuffer.h"
-#include "CommandListener.h"
-#include "LogAudit.h"
-#include "LogBuffer.h"
-#include "LogKlog.h"
-#include "LogListener.h"
-#include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogUtils.h"
-#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, \
- '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'
-
-// The service is designed to be run by init, it does not respond well to starting up manually. Init
-// has a 'sigstop' feature that sends SIGSTOP to a service immediately before calling exec(). This
-// allows debuggers, etc to be attached to logd at the very beginning, while still having init
-// handle the user, groups, capabilities, files, etc setup.
-static void DropPrivs(bool klogd, bool auditd) {
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- PLOG(FATAL) << "failed to set background scheduling policy";
- }
-
- sched_param param = {};
- if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
- PLOG(FATAL) << "failed to set batch scheduler";
- }
-
- 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);
- if (cap_clear(caps.get()) < 0) {
- PLOG(FATAL) << "cap_clear() failed";
- }
- if (klogd) {
- cap_value_t cap_syslog = CAP_SYSLOG;
- if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_syslog, CAP_SET) < 0 ||
- cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_syslog, CAP_SET) < 0) {
- PLOG(FATAL) << "Failed to set CAP_SYSLOG";
- }
- }
- if (auditd) {
- cap_value_t cap_audit_control = CAP_AUDIT_CONTROL;
- if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_audit_control, CAP_SET) < 0 ||
- cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_audit_control, CAP_SET) < 0) {
- PLOG(FATAL) << "Failed to set CAP_AUDIT_CONTROL";
- }
- }
- if (cap_set_proc(caps.get()) < 0) {
- PLOG(FATAL) << "cap_set_proc() failed";
- }
-}
-
-// 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;
- char* name;
- } userdata = {
- .uid = u,
- .name = nullptr,
- };
-
- packagelist_parse(
- [](pkg_info* info, void* callback_parameter) {
- auto userdata = reinterpret_cast<Userdata*>(callback_parameter);
- bool result = true;
- if (info->uid == userdata->uid) {
- userdata->name = strdup(info->name);
- // false to stop processing
- result = false;
- }
- packagelist_free(info);
- return result;
- },
- &userdata);
-
- return userdata.name;
-}
-
-static void readDmesg(LogAudit* al, LogKlog* kl) {
- if (!al && !kl) {
- return;
- }
-
- int rc = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
- if (rc <= 0) {
- return;
- }
-
- // Margin for additional input race or trailing nul
- ssize_t len = rc + 1024;
- std::unique_ptr<char[]> buf(new char[len]);
-
- rc = klogctl(KLOG_READ_ALL, buf.get(), len);
- if (rc <= 0) {
- return;
- }
-
- if (rc < len) {
- len = rc + 1;
- }
- buf[--len] = '\0';
-
- ssize_t sublen;
- for (char *ptr = nullptr, *tok = buf.get();
- (rc >= 0) && !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
- tok = nullptr) {
- if ((sublen <= 0) || !*tok) continue;
- if (al) {
- rc = al->log(tok, sublen);
- }
- if (kl) {
- rc = kl->log(tok, sublen);
- }
- }
-}
-
-static int issueReinit() {
- int sock = TEMP_FAILURE_RETRY(socket_local_client(
- "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- if (sock < 0) return -errno;
-
- static const char reinitStr[] = "reinit";
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
- if (ret < 0) return -errno;
-
- struct pollfd p;
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
- if (ret < 0) return -errno;
- if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
-
- static const char success[] = "success";
- char buffer[sizeof(success) - 1];
- memset(buffer, 0, sizeof(buffer));
- ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (ret < 0) return -errno;
-
- return strncmp(buffer, success, sizeof(success) - 1) != 0;
-}
-
-// Foreground waits for exit of the main persistent threads
-// that are started here. The threads are created to manage
-// UNIX domain client sockets for writing, reading and
-// controlling the user space logger, and for any additional
-// 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,
- // so here explicitly set TZ to UTC, which overrides the property.
- setenv("TZ", "UTC", 1);
- // issue reinit command. KISS argument parsing.
- if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
- return issueReinit();
- }
-
- android::base::InitLogging(
- argv, [](android::base::LogId log_id, android::base::LogSeverity severity,
- const char* tag, const char* file, unsigned int line, const char* message) {
- if (tag && strcmp(tag, "logd") != 0) {
- auto prefixed_message = android::base::StringPrintf("%s: %s", tag, message);
- android::base::KernelLogger(log_id, severity, "logd", file, line,
- prefixed_message.c_str());
- } else {
- android::base::KernelLogger(log_id, severity, "logd", file, line, message);
- }
- });
-
- static const char dev_kmsg[] = "/dev/kmsg";
- int fdDmesg = android_get_control_file(dev_kmsg);
- if (fdDmesg < 0) {
- fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
- }
-
- int fdPmesg = -1;
- 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) {
- fdPmesg = TEMP_FAILURE_RETRY(
- open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
- }
- if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg;
- }
-
- bool auditd = GetBoolProperty("ro.logd.auditd", true);
- DropPrivs(klogd, auditd);
-
- // A cache of event log tags
- LogTags log_tags;
-
- // Pruning configuration.
- PruneList prune_list;
-
- std::string buffer_type = GetProperty("logd.buffer_type", "serialized");
-
- // Partial (required for chatty) or full logging statistics.
- 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.
- LogReaderList reader_list;
-
- // LogBuffer is the object which is responsible for holding all log entries.
- LogBuffer* log_buffer = nullptr;
- if (buffer_type == "chatty") {
- log_buffer = new ChattyLogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics);
- } else if (buffer_type == "serialized") {
- log_buffer = new SerializedLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else if (buffer_type == "simple") {
- log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else {
- LOG(FATAL) << "buffer_type must be one of 'chatty', 'serialized', or 'simple'";
- }
-
- // LogReader listens on /dev/socket/logdr. When a client
- // connects, log entries in the LogBuffer are written to the client.
- LogReader* reader = new LogReader(log_buffer, &reader_list);
- if (reader->startListener()) {
- return EXIT_FAILURE;
- }
-
- // LogListener listens on /dev/socket/logdw for client
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogListener* swl = new LogListener(log_buffer);
- if (!swl->StartListener()) {
- return EXIT_FAILURE;
- }
-
- // Command listener listens on /dev/socket/logd for incoming logd
- // administrative commands.
- CommandListener* cl = new CommandListener(log_buffer, &log_tags, &prune_list, &log_statistics);
- if (cl->startListener()) {
- return EXIT_FAILURE;
- }
-
- // LogAudit listens on NETLINK_AUDIT socket for selinux
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogAudit* al = nullptr;
- if (auditd) {
- int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1;
- al = new LogAudit(log_buffer, dmesg_fd, &log_statistics);
- }
-
- LogKlog* kl = nullptr;
- if (klogd) {
- kl = new LogKlog(log_buffer, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
- }
-
- readDmesg(al, kl);
-
- // failure is an option ... messages are in dmesg (required by standard)
- if (kl && kl->startListener()) {
- delete kl;
- }
-
- if (al && al->startListener()) {
- delete al;
- }
-
- TEMP_FAILURE_RETRY(pause());
-
- return EXIT_SUCCESS;
-}
diff --git a/logwrapper b/logwrapper
new file mode 120000
index 0000000..a65ffdf
--- /dev/null
+++ b/logwrapper
@@ -0,0 +1 @@
+../logging/logwrapper
\ No newline at end of file
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
deleted file mode 100644
index 8851a47..0000000
--- a/logwrapper/Android.bp
+++ /dev/null
@@ -1,70 +0,0 @@
-cc_defaults {
- name: "logwrapper_defaults",
- cflags: [
- "-Werror",
- ],
-}
-
-// ========================================================
-// Static and shared library
-// ========================================================
-
-cc_library {
- name: "liblogwrap",
- defaults: ["logwrapper_defaults"],
- recovery_available: true,
- srcs: ["logwrap.cpp"],
- shared_libs: [
- "libcutils",
- "liblog",
- ],
- header_libs: ["libbase_headers"],
- export_include_dirs: ["include"],
- local_include_dirs: ["include"],
-}
-
-// ========================================================
-// Executable
-// ========================================================
-
-cc_defaults {
- name: "logwrapper_common",
- defaults: ["logwrapper_defaults"],
- local_include_dirs: ["include"],
- srcs: [
- "logwrap.cpp",
- "logwrapper.cpp",
- ],
- header_libs: ["libbase_headers"],
- shared_libs: ["libcutils", "liblog"],
-}
-
-cc_binary {
- name: "logwrapper",
- defaults: ["logwrapper_common"],
-}
-
-cc_binary {
- name: "logwrapper_vendor",
- defaults: ["logwrapper_common"],
- stem: "logwrapper",
- vendor: true,
-}
-
-// ========================================================
-// Benchmark
-// ========================================================
-
-cc_benchmark {
- name: "logwrap_fork_execvp_benchmark",
- defaults: ["logwrapper_defaults"],
- srcs: [
- "logwrap_fork_execvp_benchmark.cpp",
- ],
- shared_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "liblogwrap",
- ],
-}
diff --git a/logwrapper/NOTICE b/logwrapper/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/logwrapper/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/logwrapper/OWNERS b/logwrapper/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/logwrapper/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
deleted file mode 100644
index cb40ee2..0000000
--- a/logwrapper/include/logwrap/logwrap.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* system/core/include/logwrap/logwrap.h
- *
- * Copyright 2013, 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
-
-/*
- * Run a command while logging its stdout and stderr
- *
- * Arguments:
- * argc: the number of elements in argv
- * argv: an array of strings containing the command to be executed and its
- * arguments as separate strings. argv does not need to be
- * NULL-terminated
- * status: the equivalent child status as populated by wait(status). This
- * value is only valid when logwrap successfully completes. If NULL
- * the return value of the child will be the function's return value.
- * forward_signals: set to true if you want to forward SIGINT, SIGQUIT, and
- * SIGHUP to the child process, while it is running. You likely do
- * not need to use this; it is primarily for the logwrapper
- * executable itself.
- * log_target: Specify where to log the output of the child, either LOG_NONE,
- * LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
- * log), or LOG_FILE (and you need to specify a pathname in the
- * file_path argument, otherwise pass NULL). These are bit fields,
- * and can be OR'ed together to log to multiple places.
- * abbreviated: If true, capture up to the first 100 lines and last 4K of
- * output from the child. The abbreviated output is not dumped to
- * the specified log until the child has exited.
- * file_path: if log_target has the LOG_FILE bit set, then this parameter
- * must be set to the pathname of the file to log to.
- *
- * Return value:
- * 0 when logwrap successfully run the child process and captured its status
- * -1 when an internal error occurred
- * -ECHILD if status is NULL and the child didn't exit properly
- * the return value of the child if it exited properly and status is NULL
- *
- */
-
-/* Values for the log_target parameter logwrap_fork_execvp() */
-#define LOG_NONE 0
-#define LOG_ALOG 1
-#define LOG_KLOG 2
-#define LOG_FILE 4
-
-int logwrap_fork_execvp(int argc, const char* const* argv, int* status, bool forward_signals,
- int log_target, bool abbreviated, const char* file_path);
diff --git a/logwrapper/logwrap.cpp b/logwrapper/logwrap.cpp
deleted file mode 100644
index 5a518bc..0000000
--- a/logwrapper/logwrap.cpp
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * Copyright (C) 2008 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 <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <poll.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <android-base/macros.h>
-#include <cutils/klog.h>
-#include <log/log.h>
-#include <logwrap/logwrap.h>
-
-static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
-// Protected by fd_mutex. These signals must be blocked while modifying as well.
-static pid_t child_pid;
-static struct sigaction old_int;
-static struct sigaction old_quit;
-static struct sigaction old_hup;
-
-#define ERROR(fmt, args...) \
- do { \
- fprintf(stderr, fmt, ##args); \
- ALOG(LOG_ERROR, "logwrapper", fmt, ##args); \
- } while (0)
-
-#define FATAL_CHILD(fmt, args...) \
- do { \
- ERROR(fmt, ##args); \
- _exit(-1); \
- } while (0)
-
-#define MAX_KLOG_TAG 16
-
-/* This is a simple buffer that holds up to the first beginning_buf->buf_size
- * bytes of output from a command.
- */
-#define BEGINNING_BUF_SIZE 0x1000
-struct beginning_buf {
- char* buf;
- size_t alloc_len;
- /* buf_size is the usable space, which is one less than the allocated size */
- size_t buf_size;
- size_t used_len;
-};
-
-/* This is a circular buf that holds up to the last ending_buf->buf_size bytes
- * of output from a command after the first beginning_buf->buf_size bytes
- * (which are held in beginning_buf above).
- */
-#define ENDING_BUF_SIZE 0x1000
-struct ending_buf {
- char* buf;
- ssize_t alloc_len;
- /* buf_size is the usable space, which is one less than the allocated size */
- ssize_t buf_size;
- ssize_t used_len;
- /* read and write offsets into the circular buffer */
- int read;
- int write;
-};
-
-/* A structure to hold all the abbreviated buf data */
-struct abbr_buf {
- struct beginning_buf b_buf;
- struct ending_buf e_buf;
- int beginning_buf_full;
-};
-
-/* Collect all the various bits of info needed for logging in one place. */
-struct log_info {
- int log_target;
- char klog_fmt[MAX_KLOG_TAG * 2];
- const char* btag;
- bool abbreviated;
- FILE* fp;
- struct abbr_buf a_buf;
-};
-
-/* Forware declaration */
-static void add_line_to_abbr_buf(struct abbr_buf* a_buf, char* linebuf, int linelen);
-
-/* Return 0 on success, and 1 when full */
-static int add_line_to_linear_buf(struct beginning_buf* b_buf, char* line, ssize_t line_len) {
- int full = 0;
-
- if ((line_len + b_buf->used_len) > b_buf->buf_size) {
- full = 1;
- } else {
- /* Add to the end of the buf */
- memcpy(b_buf->buf + b_buf->used_len, line, line_len);
- b_buf->used_len += line_len;
- }
-
- return full;
-}
-
-static void add_line_to_circular_buf(struct ending_buf* e_buf, char* line, ssize_t line_len) {
- ssize_t free_len;
- ssize_t needed_space;
- int cnt;
-
- if (e_buf->buf == nullptr) {
- return;
- }
-
- if (line_len > e_buf->buf_size) {
- return;
- }
-
- free_len = e_buf->buf_size - e_buf->used_len;
-
- if (line_len > free_len) {
- /* remove oldest entries at read, and move read to make
- * room for the new string */
- needed_space = line_len - free_len;
- e_buf->read = (e_buf->read + needed_space) % e_buf->buf_size;
- e_buf->used_len -= needed_space;
- }
-
- /* Copy the line into the circular buffer, dealing with possible
- * wraparound.
- */
- cnt = std::min(line_len, e_buf->buf_size - e_buf->write);
- memcpy(e_buf->buf + e_buf->write, line, cnt);
- if (cnt < line_len) {
- memcpy(e_buf->buf, line + cnt, line_len - cnt);
- }
- e_buf->used_len += line_len;
- e_buf->write = (e_buf->write + line_len) % e_buf->buf_size;
-}
-
-/* Log directly to the specified log */
-static void do_log_line(struct log_info* log_info, const char* line) {
- if (log_info->log_target & LOG_KLOG) {
- klog_write(6, log_info->klog_fmt, line);
- }
- if (log_info->log_target & LOG_ALOG) {
- ALOG(LOG_INFO, log_info->btag, "%s", line);
- }
- if (log_info->log_target & LOG_FILE) {
- fprintf(log_info->fp, "%s\n", line);
- }
-}
-
-/* Log to either the abbreviated buf, or directly to the specified log
- * via do_log_line() above.
- */
-static void log_line(struct log_info* log_info, char* line, int len) {
- if (log_info->abbreviated) {
- add_line_to_abbr_buf(&log_info->a_buf, line, len);
- } else {
- do_log_line(log_info, line);
- }
-}
-
-/*
- * The kernel will take a maximum of 1024 bytes in any single write to
- * the kernel logging device file, so find and print each line one at
- * a time. The allocated size for buf should be at least 1 byte larger
- * than buf_size (the usable size of the buffer) to make sure there is
- * room to temporarily stuff a null byte to terminate a line for logging.
- */
-static void print_buf_lines(struct log_info* log_info, char* buf, int buf_size) {
- char* line_start;
- char c;
- int i;
-
- line_start = buf;
- for (i = 0; i < buf_size; i++) {
- if (*(buf + i) == '\n') {
- /* Found a line ending, print the line and compute new line_start */
- /* Save the next char and replace with \0 */
- c = *(buf + i + 1);
- *(buf + i + 1) = '\0';
- do_log_line(log_info, line_start);
- /* Restore the saved char */
- *(buf + i + 1) = c;
- line_start = buf + i + 1;
- } else if (*(buf + i) == '\0') {
- /* The end of the buffer, print the last bit */
- do_log_line(log_info, line_start);
- break;
- }
- }
- /* If the buffer was completely full, and didn't end with a newline, just
- * ignore the partial last line.
- */
-}
-
-static void init_abbr_buf(struct abbr_buf* a_buf) {
- char* new_buf;
-
- memset(a_buf, 0, sizeof(struct abbr_buf));
- new_buf = static_cast<char*>(malloc(BEGINNING_BUF_SIZE));
- if (new_buf) {
- a_buf->b_buf.buf = new_buf;
- a_buf->b_buf.alloc_len = BEGINNING_BUF_SIZE;
- a_buf->b_buf.buf_size = BEGINNING_BUF_SIZE - 1;
- }
- new_buf = static_cast<char*>(malloc(ENDING_BUF_SIZE));
- if (new_buf) {
- a_buf->e_buf.buf = new_buf;
- a_buf->e_buf.alloc_len = ENDING_BUF_SIZE;
- a_buf->e_buf.buf_size = ENDING_BUF_SIZE - 1;
- }
-}
-
-static void free_abbr_buf(struct abbr_buf* a_buf) {
- free(a_buf->b_buf.buf);
- free(a_buf->e_buf.buf);
-}
-
-static void add_line_to_abbr_buf(struct abbr_buf* a_buf, char* linebuf, int linelen) {
- if (!a_buf->beginning_buf_full) {
- a_buf->beginning_buf_full = add_line_to_linear_buf(&a_buf->b_buf, linebuf, linelen);
- }
- if (a_buf->beginning_buf_full) {
- add_line_to_circular_buf(&a_buf->e_buf, linebuf, linelen);
- }
-}
-
-static void print_abbr_buf(struct log_info* log_info) {
- struct abbr_buf* a_buf = &log_info->a_buf;
-
- /* Add the abbreviated output to the kernel log */
- if (a_buf->b_buf.alloc_len) {
- print_buf_lines(log_info, a_buf->b_buf.buf, a_buf->b_buf.used_len);
- }
-
- /* Print an ellipsis to indicate that the buffer has wrapped or
- * is full, and some data was not logged.
- */
- if (a_buf->e_buf.used_len == a_buf->e_buf.buf_size) {
- do_log_line(log_info, "...\n");
- }
-
- if (a_buf->e_buf.used_len == 0) {
- return;
- }
-
- /* Simplest way to print the circular buffer is allocate a second buf
- * of the same size, and memcpy it so it's a simple linear buffer,
- * and then cal print_buf_lines on it */
- if (a_buf->e_buf.read < a_buf->e_buf.write) {
- /* no wrap around, just print it */
- print_buf_lines(log_info, a_buf->e_buf.buf + a_buf->e_buf.read, a_buf->e_buf.used_len);
- } else {
- /* The circular buffer will always have at least 1 byte unused,
- * so by allocating alloc_len here we will have at least
- * 1 byte of space available as required by print_buf_lines().
- */
- char* nbuf = static_cast<char*>(malloc(a_buf->e_buf.alloc_len));
- if (!nbuf) {
- return;
- }
- int first_chunk_len = a_buf->e_buf.buf_size - a_buf->e_buf.read;
- memcpy(nbuf, a_buf->e_buf.buf + a_buf->e_buf.read, first_chunk_len);
- /* copy second chunk */
- memcpy(nbuf + first_chunk_len, a_buf->e_buf.buf, a_buf->e_buf.write);
- print_buf_lines(log_info, nbuf, first_chunk_len + a_buf->e_buf.write);
- free(nbuf);
- }
-}
-
-static void signal_handler(int signal_num);
-
-static void block_signals(sigset_t* oldset) {
- sigset_t blockset;
-
- sigemptyset(&blockset);
- sigaddset(&blockset, SIGINT);
- sigaddset(&blockset, SIGQUIT);
- sigaddset(&blockset, SIGHUP);
- pthread_sigmask(SIG_BLOCK, &blockset, oldset);
-}
-
-static void unblock_signals(sigset_t* oldset) {
- pthread_sigmask(SIG_SETMASK, oldset, nullptr);
-}
-
-static void setup_signal_handlers(pid_t pid) {
- struct sigaction handler = {.sa_handler = signal_handler};
-
- child_pid = pid;
- sigaction(SIGINT, &handler, &old_int);
- sigaction(SIGQUIT, &handler, &old_quit);
- sigaction(SIGHUP, &handler, &old_hup);
-}
-
-static void restore_signal_handlers() {
- sigaction(SIGINT, &old_int, nullptr);
- sigaction(SIGQUIT, &old_quit, nullptr);
- sigaction(SIGHUP, &old_hup, nullptr);
- child_pid = 0;
-}
-
-static void signal_handler(int signal_num) {
- if (child_pid == 0 || kill(child_pid, signal_num) != 0) {
- restore_signal_handlers();
- raise(signal_num);
- }
-}
-
-static int parent(const char* tag, int parent_read, pid_t pid, int* chld_sts, int log_target,
- bool abbreviated, const char* file_path, bool forward_signals) {
- int status = 0;
- char buffer[4096];
- struct pollfd poll_fds[] = {
- {
- .fd = parent_read,
- .events = POLLIN,
- },
- };
- int rc = 0;
- int fd;
-
- struct log_info log_info;
-
- int a = 0; // start index of unprocessed data
- int b = 0; // end index of unprocessed data
- int sz;
- bool found_child = false;
- // There is a very small chance that opening child_ptty in the child will fail, but in this case
- // POLLHUP will not be generated below. Therefore, we use a 1 second timeout for poll() until
- // we receive a message from child_ptty. If this times out, we call waitpid() with WNOHANG to
- // check the status of the child process and exit appropriately if it has terminated.
- bool received_messages = false;
- char tmpbuf[256];
-
- log_info.btag = basename(tag);
- if (!log_info.btag) {
- log_info.btag = tag;
- }
-
- if (abbreviated && (log_target == LOG_NONE)) {
- abbreviated = 0;
- }
- if (abbreviated) {
- init_abbr_buf(&log_info.a_buf);
- }
-
- if (log_target & LOG_KLOG) {
- snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt), "<6>%.*s: %%s\n", MAX_KLOG_TAG,
- log_info.btag);
- }
-
- if ((log_target & LOG_FILE) && !file_path) {
- /* No file_path specified, clear the LOG_FILE bit */
- log_target &= ~LOG_FILE;
- }
-
- if (log_target & LOG_FILE) {
- fd = open(file_path, O_WRONLY | O_CREAT | O_CLOEXEC, 0664);
- if (fd < 0) {
- ERROR("Cannot log to file %s\n", file_path);
- log_target &= ~LOG_FILE;
- } else {
- lseek(fd, 0, SEEK_END);
- log_info.fp = fdopen(fd, "a");
- }
- }
-
- log_info.log_target = log_target;
- log_info.abbreviated = abbreviated;
-
- while (!found_child) {
- int timeout = received_messages ? -1 : 1000;
- if (TEMP_FAILURE_RETRY(poll(poll_fds, arraysize(poll_fds), timeout)) < 0) {
- ERROR("poll failed\n");
- rc = -1;
- goto err_poll;
- }
-
- if (poll_fds[0].revents & POLLIN) {
- received_messages = true;
- sz = TEMP_FAILURE_RETRY(read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
-
- sz += b;
- // Log one line at a time
- for (b = 0; b < sz; b++) {
- if (buffer[b] == '\r') {
- if (abbreviated) {
- /* The abbreviated logging code uses newline as
- * the line separator. Lucikly, the pty layer
- * helpfully cooks the output of the command
- * being run and inserts a CR before NL. So
- * I just change it to NL here when doing
- * abbreviated logging.
- */
- buffer[b] = '\n';
- } else {
- buffer[b] = '\0';
- }
- } else if (buffer[b] == '\n') {
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- a = b + 1;
- }
- }
-
- if (a == 0 && b == sizeof(buffer) - 1) {
- // buffer is full, flush
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- b = 0;
- } else if (a != b) {
- // Keep left-overs
- b -= a;
- memmove(buffer, &buffer[a], b);
- a = 0;
- } else {
- a = 0;
- b = 0;
- }
- }
-
- if (!received_messages || (poll_fds[0].revents & POLLHUP)) {
- int ret;
- sigset_t oldset;
-
- if (forward_signals) {
- // Our signal handlers forward these signals to 'child_pid', but waitpid() may reap
- // the child, so we must block these signals until we either 1) conclude that the
- // child is still running or 2) determine the child has been reaped and we have
- // reset the signals to their original disposition.
- block_signals(&oldset);
- }
-
- int flags = (poll_fds[0].revents & POLLHUP) ? 0 : WNOHANG;
- ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, flags));
- if (ret < 0) {
- rc = errno;
- ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
- goto err_waitpid;
- }
- if (ret > 0) {
- found_child = true;
- }
-
- if (forward_signals) {
- if (found_child) {
- restore_signal_handlers();
- }
- unblock_signals(&oldset);
- }
- }
- }
-
- if (chld_sts != nullptr) {
- *chld_sts = status;
- } else {
- if (WIFEXITED(status))
- rc = WEXITSTATUS(status);
- else
- rc = -ECHILD;
- }
-
- // Flush remaining data
- if (a != b) {
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- }
-
- /* All the output has been processed, time to dump the abbreviated output */
- if (abbreviated) {
- print_abbr_buf(&log_info);
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s terminated by exit(%d)\n", log_info.btag,
- WEXITSTATUS(status));
- do_log_line(&log_info, tmpbuf);
- }
- } else {
- if (WIFSIGNALED(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s terminated by signal %d\n", log_info.btag,
- WTERMSIG(status));
- do_log_line(&log_info, tmpbuf);
- } else if (WIFSTOPPED(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s stopped by signal %d\n", log_info.btag,
- WSTOPSIG(status));
- do_log_line(&log_info, tmpbuf);
- }
- }
-
-err_waitpid:
-err_poll:
- if (log_target & LOG_FILE) {
- fclose(log_info.fp); /* Also closes underlying fd */
- }
- if (abbreviated) {
- free_abbr_buf(&log_info.a_buf);
- }
- return rc;
-}
-
-static void child(int argc, const char* const* argv) {
- // create null terminated argv_child array
- char* argv_child[argc + 1];
- memcpy(argv_child, argv, argc * sizeof(char*));
- argv_child[argc] = nullptr;
-
- if (execvp(argv_child[0], argv_child)) {
- FATAL_CHILD("executing %s failed: %s\n", argv_child[0], strerror(errno));
- }
-}
-
-int logwrap_fork_execvp(int argc, const char* const* argv, int* status, bool forward_signals,
- int log_target, bool abbreviated, const char* file_path) {
- pid_t pid;
- int parent_ptty;
- sigset_t oldset;
- int rc = 0;
-
- rc = pthread_mutex_lock(&fd_mutex);
- if (rc) {
- ERROR("failed to lock signal_fd mutex\n");
- goto err_lock;
- }
-
- /* Use ptty instead of socketpair so that STDOUT is not buffered */
- parent_ptty = TEMP_FAILURE_RETRY(posix_openpt(O_RDWR | O_CLOEXEC));
- if (parent_ptty < 0) {
- ERROR("Cannot create parent ptty\n");
- rc = -1;
- goto err_open;
- }
-
- char child_devname[64];
- if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
- ptsname_r(parent_ptty, child_devname, sizeof(child_devname)) != 0) {
- ERROR("Problem with /dev/ptmx\n");
- rc = -1;
- goto err_ptty;
- }
-
- if (forward_signals) {
- // Block these signals until we have the child pid and our signal handlers set up.
- block_signals(&oldset);
- }
-
- pid = fork();
- if (pid < 0) {
- ERROR("Failed to fork\n");
- rc = -1;
- goto err_fork;
- } else if (pid == 0) {
- pthread_mutex_unlock(&fd_mutex);
- if (forward_signals) {
- unblock_signals(&oldset);
- }
-
- setsid();
-
- int child_ptty = TEMP_FAILURE_RETRY(open(child_devname, O_RDWR | O_CLOEXEC));
- if (child_ptty < 0) {
- FATAL_CHILD("Cannot open child_ptty: %s\n", strerror(errno));
- }
- close(parent_ptty);
-
- dup2(child_ptty, 1);
- dup2(child_ptty, 2);
- close(child_ptty);
-
- child(argc, argv);
- } else {
- if (forward_signals) {
- setup_signal_handlers(pid);
- unblock_signals(&oldset);
- }
-
- rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated, file_path,
- forward_signals);
-
- if (forward_signals) {
- restore_signal_handlers();
- }
- }
-
-err_fork:
- if (forward_signals) {
- unblock_signals(&oldset);
- }
-err_ptty:
- close(parent_ptty);
-err_open:
- pthread_mutex_unlock(&fd_mutex);
-err_lock:
- return rc;
-}
diff --git a/logwrapper/logwrap_fork_execvp_benchmark.cpp b/logwrapper/logwrap_fork_execvp_benchmark.cpp
deleted file mode 100644
index b2d0c71..0000000
--- a/logwrapper/logwrap_fork_execvp_benchmark.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 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 "logwrap/logwrap.h"
-
-#include <android-base/logging.h>
-#include <benchmark/benchmark.h>
-
-static void BM_android_fork_execvp_ext(benchmark::State& state) {
- const char* argv[] = {"/system/bin/echo", "hello", "world"};
- const int argc = 3;
- while (state.KeepRunning()) {
- int rc = logwrap_fork_execvp(argc, argv, nullptr, false, LOG_NONE, false, nullptr);
- CHECK_EQ(0, rc);
- }
-}
-BENCHMARK(BM_android_fork_execvp_ext);
-
-BENCHMARK_MAIN();
diff --git a/logwrapper/logwrapper.cpp b/logwrapper/logwrapper.cpp
deleted file mode 100644
index 7118d12..0000000
--- a/logwrapper/logwrapper.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2008 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <cutils/klog.h>
-#include <log/log.h>
-#include <logwrap/logwrap.h>
-
-void fatal(const char* msg) {
- fprintf(stderr, "%s", msg);
- ALOG(LOG_ERROR, "logwrapper", "%s", msg);
- exit(-1);
-}
-
-void usage() {
- fatal("Usage: logwrapper [-a] [-d] [-k] BINARY [ARGS ...]\n"
- "\n"
- "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
- "the Android logging system. Tag is set to BINARY, priority is\n"
- "always LOG_INFO.\n"
- "\n"
- "-a: Causes logwrapper to do abbreviated logging.\n"
- " This logs up to the first 4K and last 4K of the command\n"
- " being run, and logs the output when the command exits\n"
- "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
- " fault address is set to the status of wait()\n"
- "-k: Causes logwrapper to log to the kernel log instead of\n"
- " the Android system log\n");
-}
-
-int main(int argc, char* argv[]) {
- int seg_fault_on_exit = 0;
- int log_target = LOG_ALOG;
- bool abbreviated = false;
- int ch;
- int status = 0xAAAA;
- int rc;
-
- while ((ch = getopt(argc, argv, "adk")) != -1) {
- switch (ch) {
- case 'a':
- abbreviated = true;
- break;
- case 'd':
- seg_fault_on_exit = 1;
- break;
- case 'k':
- log_target = LOG_KLOG;
- klog_set_level(6);
- break;
- case '?':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc < 1) {
- usage();
- }
-
- rc = logwrap_fork_execvp(argc, &argv[0], &status, true, log_target, abbreviated, nullptr);
- if (!rc) {
- if (WIFEXITED(status))
- rc = WEXITSTATUS(status);
- else
- rc = -ECHILD;
- }
-
- if (seg_fault_on_exit) {
- uintptr_t fault_address = (uintptr_t)status;
- *(int*)fault_address = 0; // causes SIGSEGV with fault_address = status
- }
-
- return rc;
-}