Remove liblog, logcat, logd, logwrapper

These subdirectories have moved to platform/system/logging.

BUG: 168791309
Test: Local build + TH
Change-Id: Iaee2ff59d4450f3e59dc9ea8b0e257b2de53e478
This commit is contained in:
Baligh Uddin 2020-10-08 23:17:52 +00:00
parent 83e9bc346a
commit d2c21a10d3
167 changed files with 0 additions and 31845 deletions

View File

@ -1 +0,0 @@
../.clang-format-2

View File

@ -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"],
}

View File

@ -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

View File

@ -1 +0,0 @@
tomcherry@google.com

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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();
}

View File

@ -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
* `&lt;assert.h&gt;` 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
/** @} */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
../include/android

View File

@ -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

View File

@ -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 */

View File

@ -1 +0,0 @@
../../include/log/log_id.h

View File

@ -1 +0,0 @@
../../include/log/log_main.h

View File

@ -1 +0,0 @@
../../include/log/log_properties.h

View File

@ -1 +0,0 @@
../../include/log/log_radio.h

View File

@ -1 +0,0 @@
../../include/log/log_read.h

View File

@ -1 +0,0 @@
../../include/log/log_safetynet.h

View File

@ -1 +0,0 @@
../../include/log/log_system.h

View File

@ -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 */

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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,
}

View File

@ -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>

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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

View File

@ -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",
],
}

View File

@ -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

View File

@ -1 +0,0 @@
tomcherry@google.com

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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[@]}"

View File

@ -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

View File

@ -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

View File

@ -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",
],
}

View File

@ -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

View File

@ -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"

View File

@ -1 +0,0 @@
../.clang-format-4

View File

@ -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",
],
}

View File

@ -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>

View File

@ -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();
}

View File

@ -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);
};

View File

@ -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"));

View File

@ -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;
}

View File

@ -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
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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_;
};

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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_;
};

View File

@ -1,458 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LogBufferTest.h"
#include <unistd.h>
#include <limits>
#include <memory>
#include <regex>
#include <vector>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "LogBuffer.h"
#include "LogReaderThread.h"
#include "LogWriter.h"
using android::base::Join;
using android::base::Split;
using android::base::StringPrintf;
char* android::uidToName(uid_t) {
return nullptr;
}
static std::vector<std::string> CompareLoggerEntries(const logger_entry& expected,
const logger_entry& result, bool ignore_len) {
std::vector<std::string> errors;
if (!ignore_len && expected.len != result.len) {
errors.emplace_back(
StringPrintf("len: expected %" PRIu16 " vs %" PRIu16, expected.len, result.len));
}
if (expected.hdr_size != result.hdr_size) {
errors.emplace_back(StringPrintf("hdr_size: %" PRIu16 " vs %" PRIu16, expected.hdr_size,
result.hdr_size));
}
if (expected.pid != result.pid) {
errors.emplace_back(
StringPrintf("pid: expected %" PRIi32 " vs %" PRIi32, expected.pid, result.pid));
}
if (expected.tid != result.tid) {
errors.emplace_back(
StringPrintf("tid: expected %" PRIu32 " vs %" PRIu32, expected.tid, result.tid));
}
if (expected.sec != result.sec) {
errors.emplace_back(
StringPrintf("sec: expected %" PRIu32 " vs %" PRIu32, expected.sec, result.sec));
}
if (expected.nsec != result.nsec) {
errors.emplace_back(
StringPrintf("nsec: expected %" PRIu32 " vs %" PRIu32, expected.nsec, result.nsec));
}
if (expected.lid != result.lid) {
errors.emplace_back(
StringPrintf("lid: expected %" PRIu32 " vs %" PRIu32, expected.lid, result.lid));
}
if (expected.uid != result.uid) {
errors.emplace_back(
StringPrintf("uid: expected %" PRIu32 " vs %" PRIu32, expected.uid, result.uid));
}
return errors;
}
static std::string MakePrintable(std::string in) {
if (in.size() > 80) {
in = in.substr(0, 80) + "...";
}
std::string result;
for (const char c : in) {
if (isprint(c)) {
result.push_back(c);
} else {
result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
}
}
return result;
}
static std::string CompareMessages(const std::string& expected, const std::string& result) {
if (expected == result) {
return {};
}
size_t diff_index = 0;
for (; diff_index < std::min(expected.size(), result.size()); ++diff_index) {
if (expected[diff_index] != result[diff_index]) {
break;
}
}
if (diff_index < 80) {
auto expected_short = MakePrintable(expected);
auto result_short = MakePrintable(result);
return StringPrintf("msg: expected '%s' vs '%s'", expected_short.c_str(),
result_short.c_str());
}
auto expected_short = MakePrintable(expected.substr(diff_index));
auto result_short = MakePrintable(result.substr(diff_index));
return StringPrintf("msg: index %zu: expected '%s' vs '%s'", diff_index, expected_short.c_str(),
result_short.c_str());
}
static std::string CompareRegexMessages(const std::string& expected, const std::string& result) {
auto expected_pieces = Split(expected, std::string("\0", 1));
auto result_pieces = Split(result, std::string("\0", 1));
if (expected_pieces.size() != 3 || result_pieces.size() != 3) {
return StringPrintf(
"msg: should have 3 null delimited strings found %d in expected, %d in result: "
"'%s' vs '%s'",
static_cast<int>(expected_pieces.size()), static_cast<int>(result_pieces.size()),
MakePrintable(expected).c_str(), MakePrintable(result).c_str());
}
if (expected_pieces[0] != result_pieces[0]) {
return StringPrintf("msg: tag/priority mismatch expected '%s' vs '%s'",
MakePrintable(expected_pieces[0]).c_str(),
MakePrintable(result_pieces[0]).c_str());
}
std::regex expected_tag_regex(expected_pieces[1]);
if (!std::regex_search(result_pieces[1], expected_tag_regex)) {
return StringPrintf("msg: message regex mismatch expected '%s' vs '%s'",
MakePrintable(expected_pieces[1]).c_str(),
MakePrintable(result_pieces[1]).c_str());
}
if (expected_pieces[2] != result_pieces[2]) {
return StringPrintf("msg: nothing expected after final null character '%s' vs '%s'",
MakePrintable(expected_pieces[2]).c_str(),
MakePrintable(result_pieces[2]).c_str());
}
return {};
}
void CompareLogMessages(const std::vector<LogMessage>& expected,
const std::vector<LogMessage>& result) {
EXPECT_EQ(expected.size(), result.size());
size_t end = std::min(expected.size(), result.size());
size_t num_errors = 0;
for (size_t i = 0; i < end; ++i) {
auto errors =
CompareLoggerEntries(expected[i].entry, result[i].entry, expected[i].regex_compare);
auto msg_error = expected[i].regex_compare
? CompareRegexMessages(expected[i].message, result[i].message)
: CompareMessages(expected[i].message, result[i].message);
if (!msg_error.empty()) {
errors.emplace_back(msg_error);
}
if (!errors.empty()) {
GTEST_LOG_(ERROR) << "Mismatch log message " << i << "\n" << Join(errors, "\n");
++num_errors;
}
}
EXPECT_EQ(0U, num_errors);
}
void FixupMessages(std::vector<LogMessage>* messages) {
for (auto& [entry, message, _] : *messages) {
entry.hdr_size = sizeof(logger_entry);
entry.len = message.size();
}
}
TEST_P(LogBufferTest, smoke) {
std::vector<LogMessage> log_messages = {
{{
.pid = 1,
.tid = 1,
.sec = 1234,
.nsec = 323001,
.lid = LOG_ID_MAIN,
.uid = 0,
},
"smoke test"},
};
FixupMessages(&log_messages);
LogMessages(log_messages);
std::vector<LogMessage> read_log_messages;
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
std::unique_ptr<FlushToState> flush_to_state =
log_buffer_->CreateFlushToState(1, kLogMaskAll);
EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
EXPECT_EQ(2ULL, flush_to_state->start());
}
CompareLogMessages(log_messages, read_log_messages);
}
TEST_P(LogBufferTest, smoke_with_reader_thread) {
std::vector<LogMessage> log_messages = {
{{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
"first"},
{{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
"second"},
{{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_KERNEL, .uid = 0},
"third"},
{{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20004, .lid = LOG_ID_MAIN, .uid = 0},
"fourth"},
{{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20005, .lid = LOG_ID_RADIO, .uid = 0},
"fifth"},
{{.pid = 2, .tid = 2, .sec = 10000, .nsec = 20006, .lid = LOG_ID_RADIO, .uid = 0},
"sixth"},
{{.pid = 3, .tid = 2, .sec = 10000, .nsec = 20007, .lid = LOG_ID_RADIO, .uid = 0},
"seventh"},
{{.pid = 4, .tid = 2, .sec = 10000, .nsec = 20008, .lid = LOG_ID_MAIN, .uid = 0},
"eighth"},
{{.pid = 5, .tid = 2, .sec = 10000, .nsec = 20009, .lid = LOG_ID_CRASH, .uid = 0},
"nineth"},
{{.pid = 6, .tid = 2, .sec = 10000, .nsec = 20011, .lid = LOG_ID_MAIN, .uid = 0},
"tenth"},
};
FixupMessages(&log_messages);
LogMessages(log_messages);
std::vector<LogMessage> read_log_messages;
bool released = false;
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
std::unique_ptr<LogReaderThread> log_reader(
new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
0, kLogMaskAll, 0, {}, 1, {}));
reader_list_.reader_threads().emplace_back(std::move(log_reader));
}
while (!released) {
usleep(5000);
}
{
auto lock = std::lock_guard{logd_lock};
EXPECT_EQ(0U, reader_list_.reader_threads().size());
}
CompareLogMessages(log_messages, read_log_messages);
}
// Generate random messages, set the 'sec' parameter explicit though, to be able to track the
// expected order of messages.
LogMessage GenerateRandomLogMessage(uint32_t sec) {
auto rand_uint32 = [](int max) -> uint32_t { return rand() % max; };
logger_entry entry = {
.hdr_size = sizeof(logger_entry),
.pid = rand() % 5000,
.tid = rand_uint32(5000),
.sec = sec,
.nsec = rand_uint32(NS_PER_SEC),
.lid = rand_uint32(LOG_ID_STATS),
.uid = rand_uint32(100000),
};
// See comment in ChattyLogBuffer::Log() for why this is disallowed.
if (entry.nsec % 1000 == 0) {
++entry.nsec;
}
if (entry.lid == LOG_ID_EVENTS) {
entry.lid = LOG_ID_KERNEL;
}
std::string message;
char priority = ANDROID_LOG_INFO + rand() % 2;
message.push_back(priority);
int tag_length = 2 + rand() % 10;
for (int i = 0; i < tag_length; ++i) {
message.push_back('a' + rand() % 26);
}
message.push_back('\0');
int msg_length = 2 + rand() % 1000;
for (int i = 0; i < msg_length; ++i) {
message.push_back('a' + rand() % 26);
}
message.push_back('\0');
entry.len = message.size();
return {entry, message};
}
TEST_P(LogBufferTest, random_messages) {
srand(1);
std::vector<LogMessage> log_messages;
for (size_t i = 0; i < 1000; ++i) {
log_messages.emplace_back(GenerateRandomLogMessage(i));
}
LogMessages(log_messages);
std::vector<LogMessage> read_log_messages;
bool released = false;
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
std::unique_ptr<LogReaderThread> log_reader(
new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
0, kLogMaskAll, 0, {}, 1, {}));
reader_list_.reader_threads().emplace_back(std::move(log_reader));
}
while (!released) {
usleep(5000);
}
{
auto lock = std::lock_guard{logd_lock};
EXPECT_EQ(0U, reader_list_.reader_threads().size());
}
CompareLogMessages(log_messages, read_log_messages);
}
TEST_P(LogBufferTest, read_last_sequence) {
std::vector<LogMessage> log_messages = {
{{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
"first"},
{{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
"second"},
{{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
"third"},
};
FixupMessages(&log_messages);
LogMessages(log_messages);
std::vector<LogMessage> read_log_messages;
bool released = false;
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
std::unique_ptr<LogReaderThread> log_reader(
new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
0, kLogMaskAll, 0, {}, 3, {}));
reader_list_.reader_threads().emplace_back(std::move(log_reader));
}
while (!released) {
usleep(5000);
}
{
auto lock = std::lock_guard{logd_lock};
EXPECT_EQ(0U, reader_list_.reader_threads().size());
}
std::vector<LogMessage> expected_log_messages = {log_messages.back()};
CompareLogMessages(expected_log_messages, read_log_messages);
}
TEST_P(LogBufferTest, clear_logs) {
// Log 3 initial logs.
std::vector<LogMessage> log_messages = {
{{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
"first"},
{{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
"second"},
{{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
"third"},
};
FixupMessages(&log_messages);
LogMessages(log_messages);
std::vector<LogMessage> read_log_messages;
bool released = false;
// Connect a blocking reader.
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
std::unique_ptr<LogReaderThread> log_reader(
new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false,
0, kLogMaskAll, 0, {}, 1, {}));
reader_list_.reader_threads().emplace_back(std::move(log_reader));
}
// Wait up to 250ms for the reader to read the first 3 logs.
constexpr int kMaxRetryCount = 50;
int count = 0;
for (; count < kMaxRetryCount; ++count) {
usleep(5000);
auto lock = std::lock_guard{logd_lock};
if (reader_list_.reader_threads().back()->start() == 4) {
break;
}
}
ASSERT_LT(count, kMaxRetryCount);
// Clear the log buffer.
log_buffer_->Clear(LOG_ID_MAIN, 0);
// Log 3 more logs.
std::vector<LogMessage> after_clear_messages = {
{{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
"4th"},
{{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
"5th"},
{{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
"6th"},
};
FixupMessages(&after_clear_messages);
LogMessages(after_clear_messages);
// Wait up to 250ms for the reader to read the 3 additional logs.
for (count = 0; count < kMaxRetryCount; ++count) {
usleep(5000);
auto lock = std::lock_guard{logd_lock};
if (reader_list_.reader_threads().back()->start() == 7) {
break;
}
}
ASSERT_LT(count, kMaxRetryCount);
// Release the reader, wait for it to get the signal then check that it has been deleted.
{
auto lock = std::lock_guard{logd_lock};
reader_list_.reader_threads().back()->Release();
}
while (!released) {
usleep(5000);
}
{
auto lock = std::lock_guard{logd_lock};
EXPECT_EQ(0U, reader_list_.reader_threads().size());
}
// Check that we have read all 6 messages.
std::vector<LogMessage> expected_log_messages = log_messages;
expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(),
after_clear_messages.end());
CompareLogMessages(expected_log_messages, read_log_messages);
// Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer.
std::vector<LogMessage> read_log_messages_after_clear;
{
auto lock = std::lock_guard{logd_lock};
std::unique_ptr<LogWriter> test_writer(
new TestWriter(&read_log_messages_after_clear, nullptr));
std::unique_ptr<FlushToState> flush_to_state =
log_buffer_->CreateFlushToState(1, kLogMaskAll);
EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
EXPECT_EQ(7ULL, flush_to_state->start());
}
CompareLogMessages(after_clear_messages, read_log_messages_after_clear);
}
INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest,
testing::Values("chatty", "serialized", "simple"));

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "ChattyLogBuffer.h"
#include "LogReaderList.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "PruneList.h"
#include "SerializedLogBuffer.h"
#include "SimpleLogBuffer.h"
struct LogMessage {
logger_entry entry;
std::string message;
bool regex_compare = false; // Only set for expected messages, when true 'message' should be
// interpretted as a regex.
};
// Compares the ordered list of expected and result, causing a test failure with appropriate
// information on failure.
void CompareLogMessages(const std::vector<LogMessage>& expected,
const std::vector<LogMessage>& result);
// Sets hdr_size and len parameters appropriately.
void FixupMessages(std::vector<LogMessage>* messages);
class TestWriter : public LogWriter {
public:
TestWriter(std::vector<LogMessage>* msgs, bool* released)
: LogWriter(0, true), msgs_(msgs), released_(released) {}
bool Write(const logger_entry& entry, const char* message) override {
msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false});
return true;
}
void Release() {
if (released_) *released_ = true;
}
std::string name() const override { return "test_writer"; }
private:
std::vector<LogMessage>* msgs_;
bool* released_;
};
class LogBufferTest : public testing::TestWithParam<std::string> {
protected:
void SetUp() override {
if (GetParam() == "chatty") {
log_buffer_.reset(new ChattyLogBuffer(&reader_list_, &tags_, &prune_, &stats_));
} else if (GetParam() == "serialized") {
log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_));
} else if (GetParam() == "simple") {
log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_));
} else {
FAIL() << "Unknown buffer type selected for test";
}
log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); }
}
void LogMessages(const std::vector<LogMessage>& messages) {
for (auto& [entry, message, _] : messages) {
log_buffer_->Log(static_cast<log_id_t>(entry.lid), log_time(entry.sec, entry.nsec),
entry.uid, entry.pid, entry.tid, message.c_str(), message.size());
}
}
LogReaderList reader_list_;
LogTags tags_;
PruneList prune_;
LogStatistics stats_{false, true};
std::unique_ptr<LogBuffer> log_buffer_;
};

View File

@ -1,772 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LogKlog.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/uio.h>
#include <syslog.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "LogBuffer.h"
#define KMSG_PRIORITY(PRI) \
'<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
// List of the _only_ needles we supply here to android::strnstr
static const char suspendStr[] = "PM: suspend entry ";
static const char resumeStr[] = "PM: suspend exit ";
static const char suspendedStr[] = "Suspended for ";
static const char healthdStr[] = "healthd";
static const char batteryStr[] = ": battery ";
static const char auditStr[] = " audit(";
static const char klogdStr[] = "logd.klogd: ";
// Parsing is hard
// called if we see a '<', s is the next character, returns pointer after '>'
static char* is_prio(char* s, ssize_t len) {
if ((len <= 0) || !isdigit(*s++)) return nullptr;
--len;
static const size_t max_prio_len = (len < 4) ? len : 4;
size_t priolen = 0;
char c;
while (((c = *s++)) && (++priolen <= max_prio_len)) {
if (!isdigit(c)) return ((c == '>') && (*s == '[')) ? s : nullptr;
}
return nullptr;
}
// called if we see a '[', s is the next character, returns pointer after ']'
static char* is_timestamp(char* s, ssize_t len) {
while ((len > 0) && (*s == ' ')) {
++s;
--len;
}
if ((len <= 0) || !isdigit(*s++)) return nullptr;
--len;
bool first_period = true;
char c;
while ((len > 0) && ((c = *s++))) {
--len;
if ((c == '.') && first_period) {
first_period = false;
} else if (!isdigit(c)) {
return ((c == ']') && !first_period && (*s == ' ')) ? s : nullptr;
}
}
return nullptr;
}
// Like strtok_r with "\r\n" except that we look for log signatures (regex)
// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
// *[0-9]+[.][0-9]+[]] \)
// and split if we see a second one without a newline.
// We allow nuls in content, monitoring the overall length and sub-length of
// the discovered tokens.
#define SIGNATURE_MASK 0xF0
// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
#define LESS_THAN_SIG SIGNATURE_MASK
#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
// space is one more than <digit> of 9
#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
char* android::log_strntok_r(char* s, ssize_t& len, char*& last,
ssize_t& sublen) {
sublen = 0;
if (len <= 0) return nullptr;
if (!s) {
if (!(s = last)) return nullptr;
// fixup for log signature split <,
// LESS_THAN_SIG + <digit>
if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
*s = (*s & ~SIGNATURE_MASK) + '0';
*--s = '<';
++len;
}
// fixup for log signature split [,
// OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
*s = (*s == OPEN_BRACKET_SPACE) ? ' ' : (*s & ~SIGNATURE_MASK) + '0';
*--s = '[';
++len;
}
}
while ((len > 0) && ((*s == '\r') || (*s == '\n'))) {
++s;
--len;
}
if (len <= 0) return last = nullptr;
char *peek, *tok = s;
for (;;) {
if (len <= 0) {
last = nullptr;
return tok;
}
char c = *s++;
--len;
ssize_t adjust;
switch (c) {
case '\r':
case '\n':
s[-1] = '\0';
last = s;
return tok;
case '<':
peek = is_prio(s, len);
if (!peek) break;
if (s != (tok + 1)) { // not first?
s[-1] = '\0';
*s &= ~SIGNATURE_MASK;
*s |= LESS_THAN_SIG; // signature for '<'
last = s;
return tok;
}
adjust = peek - s;
if (adjust > len) {
adjust = len;
}
sublen += adjust;
len -= adjust;
s = peek;
if ((*s == '[') && ((peek = is_timestamp(s + 1, len - 1)))) {
adjust = peek - s;
if (adjust > len) {
adjust = len;
}
sublen += adjust;
len -= adjust;
s = peek;
}
break;
case '[':
peek = is_timestamp(s, len);
if (!peek) break;
if (s != (tok + 1)) { // not first?
s[-1] = '\0';
if (*s == ' ') {
*s = OPEN_BRACKET_SPACE;
} else {
*s &= ~SIGNATURE_MASK;
*s |= OPEN_BRACKET_SIG; // signature for '['
}
last = s;
return tok;
}
adjust = peek - s;
if (adjust > len) {
adjust = len;
}
sublen += adjust;
len -= adjust;
s = peek;
break;
}
++sublen;
}
// NOTREACHED
}
log_time LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTONIC))
? log_time(log_time::EPOCH)
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
: SocketListener(fdRead, false),
logbuf(buf),
signature(CLOCK_MONOTONIC),
initialized(false),
enableLogging(true),
auditd(auditd),
stats_(stats) {
static const char klogd_message[] = "%s%s%" PRIu64 "\n";
char buffer[strlen(priority_message) + strlen(klogdStr) +
strlen(klogd_message) + 20];
snprintf(buffer, sizeof(buffer), klogd_message, priority_message, klogdStr,
signature.nsec());
write(fdWrite, buffer, strlen(buffer));
}
bool LogKlog::onDataAvailable(SocketClient* cli) {
if (!initialized) {
prctl(PR_SET_NAME, "logd.klogd");
initialized = true;
enableLogging = false;
}
char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
ssize_t len = 0;
for (;;) {
ssize_t retval = 0;
if (len < (ssize_t)(sizeof(buffer) - 1)) {
retval =
read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
}
if ((retval == 0) && (len <= 0)) {
break;
}
if (retval < 0) {
return false;
}
len += retval;
bool full = len == (sizeof(buffer) - 1);
char* ep = buffer + len;
*ep = '\0';
ssize_t sublen;
for (char *ptr = nullptr, *tok = buffer;
!!(tok = android::log_strntok_r(tok, len, ptr, sublen));
tok = nullptr) {
if (((tok + sublen) >= ep) && (retval != 0) && full) {
if (sublen > 0) memmove(buffer, tok, sublen);
len = sublen;
break;
}
if ((sublen > 0) && *tok) {
log(tok, sublen);
}
}
}
return true;
}
void LogKlog::calculateCorrection(const log_time& monotonic,
const char* real_string, ssize_t len) {
static const char real_format[] = "%Y-%m-%d %H:%M:%S.%09q UTC";
if (len < (ssize_t)(strlen(real_format) + 5)) return;
log_time real(log_time::EPOCH);
const char* ep = real.strptime(real_string, real_format);
if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
return;
}
// kernel report UTC, log_time::strptime is localtime from calendar.
// Bionic and liblog strptime does not support %z or %Z to pick up
// timezone so we are calculating our own correction.
time_t now = real.tv_sec;
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_isdst = -1;
localtime_r(&now, &tm);
if ((tm.tm_gmtoff < 0) && ((-tm.tm_gmtoff) > (long)real.tv_sec)) {
real = log_time(log_time::EPOCH);
} else {
real.tv_sec += tm.tm_gmtoff;
}
if (monotonic > real) {
correction = log_time(log_time::EPOCH);
} else {
correction = real - monotonic;
}
}
log_time LogKlog::sniffTime(const char*& buf, ssize_t len, bool reverse) {
log_time now(log_time::EPOCH);
if (len <= 0) return now;
const char* cp = nullptr;
if ((len > 10) && (*buf == '[')) {
cp = now.strptime(buf, "[ %s.%q]"); // can index beyond buffer bounds
if (cp && (cp > &buf[len - 1])) cp = nullptr;
}
if (cp) {
len -= cp - buf;
if ((len > 0) && isspace(*cp)) {
++cp;
--len;
}
buf = cp;
const char* b;
if (((b = android::strnstr(cp, len, suspendStr))) &&
(((b += strlen(suspendStr)) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
} else if (((b = android::strnstr(cp, len, resumeStr))) &&
(((b += strlen(resumeStr)) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
} else if (((b = android::strnstr(cp, len, healthdStr))) &&
(((b += strlen(healthdStr)) - cp) < len) &&
((b = android::strnstr(b, len -= b - cp, batteryStr))) &&
(((b += strlen(batteryStr)) - cp) < len)) {
// NB: healthd is roughly 150us late, so we use it instead to
// trigger a check for ntp-induced or hardware clock drift.
log_time real(CLOCK_REALTIME);
log_time mono(CLOCK_MONOTONIC);
correction = (real < mono) ? log_time(log_time::EPOCH) : (real - mono);
} else if (((b = android::strnstr(cp, len, suspendedStr))) &&
(((b += strlen(suspendStr)) - cp) < len)) {
len -= b - cp;
log_time real(log_time::EPOCH);
char* endp;
real.tv_sec = strtol(b, &endp, 10);
if ((*endp == '.') && ((endp - b) < len)) {
unsigned long multiplier = NS_PER_SEC;
real.tv_nsec = 0;
len -= endp - b;
while (--len && isdigit(*++endp) && (multiplier /= 10)) {
real.tv_nsec += (*endp - '0') * multiplier;
}
if (reverse) {
if (real > correction) {
correction = log_time(log_time::EPOCH);
} else {
correction -= real;
}
} else {
correction += real;
}
}
}
convertMonotonicToReal(now);
} else {
now = log_time(CLOCK_REALTIME);
}
return now;
}
pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) {
if (len <= 0) return 0;
const char* cp = buf;
// sscanf does a strlen, let's check if the string is not nul terminated.
// pseudo out-of-bounds access since we always have an extra char on buffer.
if (((ssize_t)strnlen(cp, len) == len) && cp[len]) {
return 0;
}
// HTC kernels with modified printk "c0 1648 "
if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
(isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
bool gotDigit = false;
int i;
for (i = 4; i < 9; ++i) {
if (isdigit(cp[i])) {
gotDigit = true;
} else if (gotDigit || (cp[i] != ' ')) {
break;
}
}
if ((i == 9) && (cp[i] == ' ')) {
int pid = 0;
char placeholder;
if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) {
buf = cp + 10; // skip-it-all
return pid;
}
}
}
while (len) {
// Mediatek kernels with modified printk
if (*cp == '[') {
int pid = 0;
char placeholder;
if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) {
return pid;
}
break; // Only the first one
}
++cp;
--len;
}
return 0;
}
// kernel log prefix, convert to a kernel log priority number
static int parseKernelPrio(const char*& buf, ssize_t len) {
int pri = LOG_USER | LOG_INFO;
const char* cp = buf;
if ((len > 0) && (*cp == '<')) {
pri = 0;
while (--len && isdigit(*++cp)) {
pri = (pri * 10) + *cp - '0';
}
if ((len > 0) && (*cp == '>')) {
++cp;
} else {
cp = buf;
pri = LOG_USER | LOG_INFO;
}
buf = cp;
}
return pri;
}
// Convert kernel log priority number into an Android Logger priority number
static int convertKernelPrioToAndroidPrio(int pri) {
switch (pri & LOG_PRIMASK) {
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT:
return ANDROID_LOG_FATAL;
case LOG_ERR:
return ANDROID_LOG_ERROR;
case LOG_WARNING:
return ANDROID_LOG_WARN;
default:
case LOG_NOTICE:
case LOG_INFO:
break;
case LOG_DEBUG:
return ANDROID_LOG_DEBUG;
}
return ANDROID_LOG_INFO;
}
static const char* strnrchr(const char* s, ssize_t len, char c) {
const char* save = nullptr;
for (; len > 0; ++s, len--) {
if (*s == c) {
save = s;
}
}
return save;
}
//
// log a message into the kernel log buffer
//
// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
// them to appear correct in the logcat output:
//
// LOG_KERN (0):
// <PRI>[<TIME>] <tag> ":" <message>
// <PRI>[<TIME>] <tag> <tag> ":" <message>
// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
// <PRI>[<TIME>] "[INFO]"<tag> : <message>
// <PRI>[<TIME>] "------------[ cut here ]------------" (?)
// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---" (?)
// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
// <PRI+TAG>[<TIME>] (see sys/syslog.h)
// Observe:
// Minimum tag length = 3 NB: drops things like r5:c00bbadf, but allow PM:
// Maximum tag words = 2
// Maximum tag length = 16 NB: we are thinking of how ugly logcat can get.
// Not a Tag if there is no message content.
// leading additional spaces means no tag, inherit last tag.
// Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
// Drop:
// empty messages
// messages with ' audit(' in them if auditd is running
// logd.klogd:
// return -1 if message logd.klogd: <signature>
//
int LogKlog::log(const char* buf, ssize_t len) {
if (auditd && android::strnstr(buf, len, auditStr)) {
return 0;
}
const char* p = buf;
int pri = parseKernelPrio(p, len);
log_time now = sniffTime(p, len - (p - buf), false);
// sniff for start marker
const char* start = android::strnstr(p, len - (p - buf), klogdStr);
if (start) {
uint64_t sig = strtoll(start + strlen(klogdStr), nullptr, 10);
if (sig == signature.nsec()) {
if (initialized) {
enableLogging = true;
} else {
enableLogging = false;
}
return -1;
}
return 0;
}
if (!enableLogging) {
return 0;
}
// Parse pid, tid and uid
const pid_t pid = sniffPid(p, len - (p - buf));
const pid_t tid = pid;
uid_t uid = AID_ROOT;
if (pid) {
uid = stats_->PidToUid(pid);
}
// Parse (rules at top) to pull out a tag from the incoming kernel message.
// Some may view the following as an ugly heuristic, the desire is to
// beautify the kernel logs into an Android Logging format; the goal is
// admirable but costly.
while ((p < &buf[len]) && (isspace(*p) || !*p)) {
++p;
}
if (p >= &buf[len]) { // timestamp, no content
return 0;
}
start = p;
const char* tag = "";
const char* etag = tag;
ssize_t taglen = len - (p - buf);
const char* bt = p;
static const char infoBrace[] = "[INFO]";
static const ssize_t infoBraceLen = strlen(infoBrace);
if ((taglen >= infoBraceLen) &&
!fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
bt = p + infoBraceLen;
taglen -= infoBraceLen;
}
const char* et;
for (et = bt; (taglen > 0) && *et && (*et != ':') && !isspace(*et);
++et, --taglen) {
// skip ':' within [ ... ]
if (*et == '[') {
while ((taglen > 0) && *et && *et != ']') {
++et;
--taglen;
}
if (taglen <= 0) {
break;
}
}
}
const char* cp;
for (cp = et; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
}
// Validate tag
ssize_t size = et - bt;
if ((taglen > 0) && (size > 0)) {
if (*cp == ':') {
// ToDo: handle case insensitive colon separated logging stutter:
// <tag> : <tag>: ...
// One Word
tag = bt;
etag = et;
p = cp + 1;
} else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
// clean up any tag stutter
if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
// <PRI>[<TIME>] <tag> <tag> : message
// <PRI>[<TIME>] <tag> <tag>: message
// <PRI>[<TIME>] <tag> '<tag>.<num>' : message
// <PRI>[<TIME>] <tag> '<tag><num>' : message
// <PRI>[<TIME>] <tag> '<tag><stuff>' : message
const char* b = cp;
cp += size;
taglen -= size;
while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
}
const char* e;
for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
}
if ((taglen > 0) && (*cp == ':')) {
tag = b;
etag = e;
p = cp + 1;
}
} else {
// what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
static const char host[] = "_host";
static const ssize_t hostlen = strlen(host);
if ((size > hostlen) &&
!fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
!fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
const char* b = cp;
cp += size - hostlen;
taglen -= size - hostlen;
if (*cp == '.') {
while ((--taglen > 0) && !isspace(*++cp) &&
(*cp != ':')) {
}
const char* e;
for (e = cp; (taglen > 0) && isspace(*cp);
++cp, --taglen) {
}
if ((taglen > 0) && (*cp == ':')) {
tag = b;
etag = e;
p = cp + 1;
}
}
} else {
goto twoWord;
}
}
} else {
// <PRI>[<TIME>] <tag> <stuff>' : message
twoWord:
while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
}
const char* e;
for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
}
// Two words
if ((taglen > 0) && (*cp == ':')) {
tag = bt;
etag = e;
p = cp + 1;
}
}
} // else no tag
static const char cpu[] = "CPU";
static const ssize_t cpuLen = strlen(cpu);
static const char warning[] = "WARNING";
static const ssize_t warningLen = strlen(warning);
static const char error[] = "ERROR";
static const ssize_t errorLen = strlen(error);
static const char info[] = "INFO";
static const ssize_t infoLen = strlen(info);
size = etag - tag;
if ((size <= 1) ||
// register names like x9
((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
// register names like x18 but not driver names like en0
((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
// ignore
((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
p = start;
etag = tag = "";
}
// Suppress additional stutter in tag:
// eg: [143:healthd]healthd -> [143:healthd]
taglen = etag - tag;
// Mediatek-special printk induced stutter
const char* mp = strnrchr(tag, taglen, ']');
if (mp && (++mp < etag)) {
ssize_t s = etag - mp;
if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
taglen = mp - tag;
}
}
// Deal with sloppy and simplistic harmless p = cp + 1 etc above.
if (len < (p - buf)) {
p = &buf[len];
}
// skip leading space
while ((p < &buf[len]) && (isspace(*p) || !*p)) {
++p;
}
// truncate trailing space or nuls
ssize_t b = len - (p - buf);
while ((b > 0) && (isspace(p[b - 1]) || !p[b - 1])) {
--b;
}
// trick ... allow tag with empty content to be logged. log() drops empty
if ((b <= 0) && (taglen > 0)) {
p = " ";
b = 1;
}
// This shouldn't happen, but clamp the size if it does.
if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
b = LOGGER_ENTRY_MAX_PAYLOAD;
}
if (taglen > LOGGER_ENTRY_MAX_PAYLOAD) {
taglen = LOGGER_ENTRY_MAX_PAYLOAD;
}
// calculate buffer copy requirements
ssize_t n = 1 + taglen + 1 + b + 1;
// Extra checks for likely impossible cases.
if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) {
return -EINVAL;
}
// Careful.
// We are using the stack to house the log buffer for speed reasons.
// If we malloc'd this buffer, we could get away without n's USHRT_MAX
// test above, but we would then required a max(n, USHRT_MAX) as
// truncating length argument to logbuf->log() below. Gain is protection
// against stack corruption and speedup, loss is truncated long-line content.
char newstr[n];
char* np = newstr;
// Convert priority into single-byte Android logger priority
*np = convertKernelPrioToAndroidPrio(pri);
++np;
// Copy parsed tag following priority
memcpy(np, tag, taglen);
np += taglen;
*np = '\0';
++np;
// Copy main message to the remainder
memcpy(np, p, b);
np[b] = '\0';
{
// Watch out for singular race conditions with timezone causing near
// integer quarter-hour jumps in the time and compensate accordingly.
// Entries will be temporal within near_seconds * 2. b/21868540
static uint32_t vote_time[3];
vote_time[2] = vote_time[1];
vote_time[1] = vote_time[0];
vote_time[0] = now.tv_sec;
if (vote_time[1] && vote_time[2]) {
static const unsigned near_seconds = 10;
static const unsigned timezones_seconds = 900;
int diff0 = (vote_time[0] - vote_time[1]) / near_seconds;
unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
if ((abs1 <= 1) && // last two were in agreement on timezone
((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
timezones_seconds;
now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
}
}
}
// Log message
int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
return rc;
}

Some files were not shown because too many files have changed in this diff Show More