Merge changes from topic "bug_168791309"
* changes: Add symlinks to satisfy include paths. Remove liblog, logcat, logd, logwrapper
This commit is contained in:
commit
8d96bfa9bd
171 changed files with 4 additions and 31845 deletions
1
liblog
Symbolic link
1
liblog
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../logging/liblog
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../.clang-format-2
|
|
||||||
|
|
@ -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"],
|
|
||||||
}
|
|
||||||
190
liblog/NOTICE
190
liblog/NOTICE
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
tomcherry@google.com
|
|
||||||
161
liblog/README.md
161
liblog/README.md
|
|
@ -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.
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../include/android
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_id.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_main.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_properties.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_radio.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_read.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_safetynet.h
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../include/log/log_system.h
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
1748
liblog/logprint.cpp
1748
liblog/logprint.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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,
|
|
||||||
}
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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());
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
27
liblog/uio.h
27
liblog/uio.h
|
|
@ -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
|
|
||||||
1
logcat
Symbolic link
1
logcat
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../logging/logcat
|
||||||
|
|
@ -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",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
190
logcat/NOTICE
190
logcat/NOTICE
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
tomcherry@google.com
|
|
||||||
|
|
@ -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.
|
|
||||||
1212
logcat/logcat.cpp
1212
logcat/logcat.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -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[@]}"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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"
|
|
||||||
1
logd
Symbolic link
1
logd
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../logging/logd
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../.clang-format-4
|
|
||||||
212
logd/Android.bp
212
logd/Android.bp
|
|
@ -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",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
};
|
|
||||||
|
|
@ -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"));
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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_;
|
|
||||||
};
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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_;
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue