Merge changes from topic "snapshot_fuzz"
* changes:
libsnapshot_fuzzer: Add tests
libsnapshot_fuzzer: add initial corpus
libsnapshot_fuzzer: Attempt to cleanup env before and after
libsnapshot_fuzzer: add new test directive to switch slot
libsnapshot_fuzzer: mount data image
libsnapshot_fuzzer: also create snapshots dir
libsnapshot_fuzzer: Add ZERO to operation types
diff --git a/adb/adb.cpp b/adb/adb.cpp
index dcec0ba..08986b7 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -109,7 +109,9 @@
{
D("adb: online");
t->online = 1;
+#if ADB_HOST
t->SetConnectionEstablished(true);
+#endif
}
void handle_offline(atransport *t)
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 43a9252..124e2d8 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -73,6 +73,7 @@
typedef std::list<std::unique_ptr<alistener>> ListenerList;
static ListenerList& listener_list GUARDED_BY(listener_list_mutex) = *new ListenerList();
+#if ADB_HOST
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
if (ev & FDE_READ) {
unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
@@ -88,6 +89,7 @@
}
}
}
+#endif
static void listener_event_func(int _fd, unsigned ev, void* _l)
{
@@ -164,7 +166,7 @@
}
}
-void enable_daemon_sockets() EXCLUDES(listener_list_mutex) {
+void enable_server_sockets() EXCLUDES(listener_list_mutex) {
std::lock_guard<std::mutex> lock(listener_list_mutex);
for (auto& l : listener_list) {
if (l->connect_to == "*smartsocket*") {
@@ -173,6 +175,7 @@
}
}
+#if ADB_HOST
void close_smartsockets() EXCLUDES(listener_list_mutex) {
std::lock_guard<std::mutex> lock(listener_list_mutex);
auto pred = [](const std::unique_ptr<alistener>& listener) {
@@ -180,6 +183,7 @@
};
listener_list.remove_if(pred);
}
+#endif
InstallStatus install_listener(const std::string& local_name, const char* connect_to,
atransport* transport, int flags, int* resolved_tcp_port,
@@ -188,7 +192,7 @@
for (auto& l : listener_list) {
if (local_name == l->local_name) {
// Can't repurpose a smartsocket.
- if(l->connect_to[0] == '*') {
+ if (l->connect_to[0] == '*') {
*error = "cannot repurpose smartsocket";
return INSTALL_STATUS_INTERNAL_ERROR;
}
@@ -227,7 +231,11 @@
close_on_exec(listener->fd);
if (listener->connect_to == "*smartsocket*") {
+#if ADB_HOST
listener->fde = fdevent_create(listener->fd, ss_listener_event_func, listener.get());
+#else
+ LOG(FATAL) << "attempted to connect to *smartsocket* in daemon";
+#endif
} else {
listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get());
}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 354dcc5..0aa774a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef __ADB_LISTENERS_H
-#define __ADB_LISTENERS_H
+#pragma once
#include "adb.h"
@@ -44,7 +43,7 @@
InstallStatus remove_listener(const char* local_name, atransport* transport);
void remove_all_listeners(void);
-void enable_daemon_sockets();
+#if ADB_HOST
+void enable_server_sockets();
void close_smartsockets();
-
-#endif /* __ADB_LISTENERS_H */
+#endif
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index c579dde..210241c 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -90,7 +90,7 @@
int adb_trace_mask;
std::string get_trace_setting() {
-#if ADB_HOST
+#if ADB_HOST || !defined(__ANDROID__)
const char* setting = getenv("ADB_TRACE");
if (setting == nullptr) {
setting = "";
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index f0a287d..efb6c2f 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1712,14 +1712,21 @@
}
printf("List of devices attached\n");
return adb_query_command(query);
- }
- else if (!strcmp(argv[0], "connect")) {
+ } else if (!strcmp(argv[0], "transport-id")) {
+ TransportId transport_id;
+ std::string error;
+ unique_fd fd(adb_connect(&transport_id, "host:features", &error, true));
+ if (fd == -1) {
+ error_exit("%s", error.c_str());
+ }
+ printf("%" PRIu64 "\n", transport_id);
+ return 0;
+ } else if (!strcmp(argv[0], "connect")) {
if (argc != 2) error_exit("usage: adb connect HOST[:PORT]");
std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
return adb_query_command(query);
- }
- else if (!strcmp(argv[0], "disconnect")) {
+ } else if (!strcmp(argv[0], "disconnect")) {
if (argc > 2) error_exit("usage: adb disconnect [HOST[:PORT]]");
std::string query = android::base::StringPrintf("host:disconnect:%s",
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 05e210f..a19bd6d 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -206,7 +206,7 @@
// We don't accept() client connections until this point: this way, clients
// can't see wonky state early in startup even if they're connecting directly
// to the server instead of going through the adb program.
- fdevent_run_on_main_thread([] { enable_daemon_sockets(); });
+ fdevent_run_on_main_thread([] { enable_server_sockets(); });
});
notify_thread.detach();
diff --git a/adb/coverage/gen_coverage.sh b/adb/coverage/gen_coverage.sh
index cced62a..43d45f0 100755
--- a/adb/coverage/gen_coverage.sh
+++ b/adb/coverage/gen_coverage.sh
@@ -17,10 +17,10 @@
# Check that we can connect to it.
adb disconnect
-adb tcpip $REMOTE_PORT
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+TRANSPORT_ID=$(adb transport-id)
+adb tcpip $REMOTE_PORT
+adb -t $TRANSPORT_ID wait-for-disconnect
adb connect $REMOTE
@@ -32,13 +32,16 @@
fi
# Back to USB, and make sure adbd is root.
+adb -s $REMOTE usb
adb disconnect $REMOTE
+adb wait-for-device root
adb root
-adb wait-for-device usb
+adb wait-for-device
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+TRANSPORT_ID=$(adb transport-id)
+adb usb
+adb -t $TRANSPORT_ID wait-for-disconnect
adb wait-for-device
@@ -61,10 +64,9 @@
adb shell setprop persist.adb.trace_mask 1
### Run test_device.py over USB.
+TRANSPORT_ID=$(adb transport-id)
adb shell killall adbd
-
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+adb -t $TRANSPORT_ID wait-for-disconnect
adb wait-for-device shell rm -rf "/data/misc/trace/*" /data/local/tmp/adb_coverage/
"$OUTPUT_DIR"/../test_device.py
@@ -80,13 +82,16 @@
sleep 5
# Restart adbd in tcp mode.
+TRANSPORT_ID=$(adb transport-id)
adb tcpip $REMOTE_PORT
-sleep 5
+adb -t $TRANSPORT_ID wait-for-disconnect
+
adb connect $REMOTE
adb -s $REMOTE wait-for-device
-# Run test_device.py again.
-ANDROID_SERIAL=$REMOTE "$OUTPUT_DIR"/../test_device.py
+# Instead of running test_device.py again, which takes forever, do some I/O back and forth instead.
+dd if=/dev/zero bs=1024 count=10240 | adb -s $REMOTE raw sink:10485760
+adb -s $REMOTE raw source:10485760 | dd of=/dev/null bs=1024 count=10240
# Dump traces again.
adb disconnect $REMOTE
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 55b7783..db8f07b 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -173,12 +173,6 @@
LOG(FATAL) << "Could not set SELinux context";
}
}
- std::string error;
- std::string local_name =
- android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
- LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
- }
}
}
#endif
diff --git a/adb/fastdeploy/proto/ApkEntry.proto b/adb/fastdeploy/proto/ApkEntry.proto
index d84c5a5..ed5056e 100644
--- a/adb/fastdeploy/proto/ApkEntry.proto
+++ b/adb/fastdeploy/proto/ApkEntry.proto
@@ -5,7 +5,6 @@
option java_package = "com.android.fastdeploy";
option java_outer_classname = "ApkEntryProto";
option java_multiple_files = true;
-option optimize_for = LITE_RUNTIME;
message APKDump {
string name = 1;
diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h
index 9fc3b2c..bb3af74 100644
--- a/adb/fdevent/fdevent.h
+++ b/adb/fdevent/fdevent.h
@@ -79,8 +79,8 @@
unique_fd Destroy(fdevent* fde);
protected:
- virtual void Register(fdevent*) {}
- virtual void Unregister(fdevent*) {}
+ virtual void Register(fdevent*) = 0;
+ virtual void Unregister(fdevent*) = 0;
public:
// Change which events should cause notifications.
diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp
index ac86c08..21c1ba0 100644
--- a/adb/fdevent/fdevent_poll.cpp
+++ b/adb/fdevent/fdevent_poll.cpp
@@ -211,3 +211,7 @@
PLOG(FATAL) << "failed to write to fdevent interrupt fd";
}
}
+
+void fdevent_context_poll::Register(fdevent*) {}
+
+void fdevent_context_poll::Unregister(fdevent*) {}
diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h
index 98abab2..8803e3e 100644
--- a/adb/fdevent/fdevent_poll.h
+++ b/adb/fdevent/fdevent_poll.h
@@ -48,6 +48,9 @@
fdevent_context_poll();
virtual ~fdevent_context_poll();
+ virtual void Register(fdevent* fde) final;
+ virtual void Unregister(fdevent* fde) final;
+
virtual void Set(fdevent* fde, unsigned events) final;
virtual void Loop() final;
diff --git a/adb/libs/adbconnection/include/adbconnection/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h
index 86d3259..d226699 100644
--- a/adb/libs/adbconnection/include/adbconnection/process_info.h
+++ b/adb/libs/adbconnection/include/adbconnection/process_info.h
@@ -21,7 +21,7 @@
#include <string>
struct ProcessInfo {
- const static size_t kMaxArchNameLength = 16;
+ static constexpr size_t kMaxArchNameLength = 16;
uint64_t pid;
bool debuggable;
diff --git a/adb/socket.h b/adb/socket.h
index 4276851..0623204 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -108,7 +108,10 @@
asocket *create_remote_socket(unsigned id, atransport *t);
void connect_to_remote(asocket* s, std::string_view destination);
+
+#if ADB_HOST
void connect_to_smartsocket(asocket *s);
+#endif
// Internal functions that are only made available here for testing purposes.
namespace internal {
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index d17036c..b7b25fa 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -103,12 +103,6 @@
if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) {
return false;
}
-
- if (port_value == -1) {
- *error = "missing port in specification: ";
- *error += spec;
- return false;
- }
}
if (hostname) {
diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp
index e9d5270..e83c34c 100644
--- a/adb/socket_spec_test.cpp
+++ b/adb/socket_spec_test.cpp
@@ -24,6 +24,13 @@
#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
+TEST(socket_spec, parse_tcp_socket_spec_failure) {
+ std::string hostname, error, serial;
+ int port;
+ EXPECT_FALSE(parse_tcp_socket_spec("sneakernet:5037", &hostname, &port, &serial, &error));
+ EXPECT_TRUE(error.find("sneakernet") != std::string::npos);
+}
+
TEST(socket_spec, parse_tcp_socket_spec_just_port) {
std::string hostname, error, serial;
int port;
@@ -134,6 +141,19 @@
EXPECT_NE(client_fd.get(), -1);
}
+TEST(socket_spec, socket_spec_connect_failure) {
+ std::string error, serial;
+ int port;
+ unique_fd client_fd;
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "acceptfd:", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:x", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5:x", &port, &serial, &error));
+ EXPECT_FALSE(socket_spec_connect(&client_fd, "sneakernet:", &port, &serial, &error));
+}
+
TEST(socket_spec, socket_spec_listen_connect_localfilesystem) {
std::string error, serial;
int port;
@@ -152,3 +172,16 @@
EXPECT_NE(client_fd.get(), -1);
}
}
+
+TEST(socket_spec, is_socket_spec) {
+ EXPECT_TRUE(is_socket_spec("tcp:blah"));
+ EXPECT_TRUE(is_socket_spec("acceptfd:blah"));
+ EXPECT_TRUE(is_socket_spec("local:blah"));
+ EXPECT_TRUE(is_socket_spec("localreserved:blah"));
+}
+
+TEST(socket_spec, is_local_socket_spec) {
+ EXPECT_TRUE(is_local_socket_spec("local:blah"));
+ EXPECT_TRUE(is_local_socket_spec("tcp:localhost"));
+ EXPECT_FALSE(is_local_socket_spec("tcp:www.google.com"));
+}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 423af67..13a4737 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -520,6 +520,7 @@
send_packet(p, s->transport);
}
+#if ADB_HOST
/* this is used by magic sockets to rig local sockets to
send the go-ahead message when they connect */
static void local_socket_ready_notify(asocket* s) {
@@ -584,8 +585,6 @@
return n;
}
-#if ADB_HOST
-
namespace internal {
// Parses a host service string of the following format:
@@ -714,15 +713,11 @@
} // namespace internal
-#endif // ADB_HOST
-
static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
-#if ADB_HOST
std::string_view service;
std::string_view serial;
TransportId transport_id = 0;
TransportType type = kTransportAny;
-#endif
D("SS(%d): enqueue %zu", s->id, data.size());
@@ -755,7 +750,6 @@
D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
-#if ADB_HOST
service = std::string_view(s->smart_socket_data).substr(4);
// TODO: These should be handled in handle_host_request.
@@ -841,16 +835,6 @@
s2->ready(s2);
return 0;
}
-#else /* !ADB_HOST */
- if (s->transport == nullptr) {
- std::string error_msg = "unknown failure";
- s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg);
- if (s->transport == nullptr) {
- SendFail(s->peer->fd, error_msg);
- goto fail;
- }
- }
-#endif
if (!s->transport) {
SendFail(s->peer->fd, "device offline (no transport)");
@@ -922,6 +906,7 @@
ss->peer = s;
s->ready(s);
}
+#endif
size_t asocket::get_max_payload() const {
size_t max_payload = MAX_PAYLOAD;
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 25ed366..1667011 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -928,6 +928,7 @@
remove_transport(t);
}
+#if ADB_HOST
static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
bool sanitize_qual) {
if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */
@@ -1083,10 +1084,13 @@
}
cv_.notify_one();
}
+#endif
atransport::~atransport() {
+#if ADB_HOST
// If the connection callback had not been run before, run it now.
SetConnectionEstablished(false);
+#endif
}
int atransport::Write(apacket* p) {
@@ -1240,6 +1244,7 @@
disconnects_.clear();
}
+#if ADB_HOST
bool atransport::MatchesTarget(const std::string& target) const {
if (!serial.empty()) {
if (target == serial) {
@@ -1283,8 +1288,6 @@
return reconnect_(this);
}
-#if ADB_HOST
-
// We use newline as our delimiter, make sure to never output it.
static std::string sanitize(std::string str, bool alphanumeric) {
auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
@@ -1366,7 +1369,7 @@
void close_usb_devices(bool reset) {
close_usb_devices([](const atransport*) { return true; }, reset);
}
-#endif // ADB_HOST
+#endif
bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
atransport::ReconnectCallback reconnect, bool use_tls, int* error) {
@@ -1406,7 +1409,9 @@
lock.unlock();
+#if ADB_HOST
auto waitable = t->connection_waitable();
+#endif
register_transport(t);
if (local == 1) {
@@ -1414,6 +1419,7 @@
return true;
}
+#if ADB_HOST
if (!waitable->WaitForConnection(std::chrono::seconds(10))) {
if (error) *error = ETIMEDOUT;
return false;
@@ -1423,6 +1429,7 @@
if (error) *error = EPERM;
return false;
}
+#endif
return true;
}
@@ -1453,14 +1460,9 @@
t->Kick();
}
}
-#if ADB_HOST
reconnect_handler.CheckForKicked();
-#endif
}
-#endif
-
-#if ADB_HOST
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
@@ -1482,9 +1484,7 @@
register_transport(t);
}
-#endif
-#if ADB_HOST
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index e93c31c..2ac21cf 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -262,9 +262,12 @@
: id(NextTransportId()),
kicked_(false),
connection_state_(state),
- connection_waitable_(std::make_shared<ConnectionWaitable>()),
connection_(nullptr),
reconnect_(std::move(reconnect)) {
+#if ADB_HOST
+ connection_waitable_ = std::make_shared<ConnectionWaitable>();
+#endif
+
// Initialize protocol to min version for compatibility with older versions.
// Version will be updated post-connect.
protocol_version = A_VERSION_MIN;
@@ -350,6 +353,7 @@
void RemoveDisconnect(adisconnect* disconnect);
void RunDisconnects();
+#if ADB_HOST
// Returns true if |target| matches this transport. A matching |target| can be any of:
// * <serial>
// * <devpath>
@@ -374,6 +378,7 @@
// Attempts to reconnect with the underlying Connection.
ReconnectResult Reconnect();
+#endif
private:
std::atomic<bool> kicked_;
@@ -392,9 +397,11 @@
std::deque<std::shared_ptr<RSA>> keys_;
#endif
+#if ADB_HOST
// A sharable object that can be used to wait for the atransport's
// connection to be established.
std::shared_ptr<ConnectionWaitable> connection_waitable_;
+#endif
// The underlying connection object.
std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
@@ -434,10 +441,17 @@
void init_transport_registration(void);
void init_mdns_transport_discovery(void);
std::string list_transports(bool long_listing);
+
+#if ADB_HOST
atransport* find_transport(const char* serial);
+
void kick_all_tcp_devices();
+#endif
+
void kick_all_transports();
+
void kick_all_tcp_tls_transports();
+
#if !ADB_HOST
void kick_all_transports_by_auth_key(std::string_view auth_key);
#endif
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index a9ada4a..8579ff4 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -127,6 +127,7 @@
ASSERT_EQ(std::string("baz"), t.device);
}
+#if ADB_HOST
TEST_F(TransportTest, test_matches_target) {
std::string serial = "foo";
std::string devpath = "/path/to/bar";
@@ -183,3 +184,4 @@
EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100"));
}
}
+#endif
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index d67b522..31c2d5d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -169,6 +169,7 @@
"libdebuggerd/backtrace.cpp",
"libdebuggerd/gwp_asan.cpp",
"libdebuggerd/open_files_list.cpp",
+ "libdebuggerd/scudo.cpp",
"libdebuggerd/tombstone.cpp",
"libdebuggerd/utility.cpp",
],
@@ -176,8 +177,13 @@
local_include_dirs: ["libdebuggerd/include"],
export_include_dirs: ["libdebuggerd/include"],
- // Needed for private/bionic_fdsan.h
- include_dirs: ["bionic/libc"],
+ include_dirs: [
+ // Needed for private/bionic_fdsan.h
+ "bionic/libc",
+
+ // Needed for scudo/interface.h
+ "external/scudo/standalone/include",
+ ],
header_libs: [
"bionic_libc_platform_headers",
"gwp_asan_headers",
@@ -192,7 +198,10 @@
"liblog",
],
- whole_static_libs: ["gwp_asan_crash_handler"],
+ whole_static_libs: [
+ "gwp_asan_crash_handler",
+ "libscudo",
+ ],
target: {
recovery: {
@@ -206,6 +215,9 @@
debuggable: {
cflags: ["-DROOT_POSSIBLE"],
},
+ experimental_mte: {
+ cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+ },
},
}
@@ -256,6 +268,10 @@
"gwp_asan_headers",
],
+ include_dirs: [
+ "external/scudo/standalone/include",
+ ],
+
local_include_dirs: [
"libdebuggerd",
],
@@ -271,6 +287,12 @@
},
test_suites: ["device-tests"],
+
+ product_variables: {
+ experimental_mte: {
+ cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+ },
+ },
}
cc_benchmark {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 0cd2350..d7cb972 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -289,6 +289,8 @@
process_info->fdsan_table_address = crash_info->data.d.fdsan_table_address;
process_info->gwp_asan_state = crash_info->data.d.gwp_asan_state;
process_info->gwp_asan_metadata = crash_info->data.d.gwp_asan_metadata;
+ process_info->scudo_stack_depot = crash_info->data.d.scudo_stack_depot;
+ process_info->scudo_region_info = crash_info->data.d.scudo_region_info;
FALLTHROUGH_INTENDED;
case 1:
case 2:
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 054f836..9d7658e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -31,6 +31,9 @@
#include <android/fdsan.h>
#include <android/set_abort_message.h>
+#include <bionic/malloc.h>
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
#include <bionic/reserved_signals.h>
#include <android-base/cmsg.h>
@@ -331,6 +334,184 @@
R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
}
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+static void SetTagCheckingLevelSync() {
+ int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (tagged_addr_ctrl < 0) {
+ abort();
+ }
+
+ tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | PR_MTE_TCF_SYNC;
+ if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) != 0) {
+ abort();
+ }
+
+ HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+ if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level))) {
+ abort();
+ }
+}
+#endif
+
+TEST_F(CrasherTest, mte_uaf) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([]() {
+ SetTagCheckingLevelSync();
+ volatile int* p = (volatile int*)malloc(16);
+ free((void *)p);
+ p[0] = 42;
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
+ ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a 16-byte allocation.*
+
+allocated by thread .*
+ #00 pc)");
+ ASSERT_MATCH(result, R"(deallocated by thread .*
+ #00 pc)");
+#else
+ GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_overflow) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([]() {
+ SetTagCheckingLevelSync();
+ volatile int* p = (volatile int*)malloc(16);
+ p[4] = 42;
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
+ ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation.*
+
+allocated by thread .*
+ #00 pc)");
+#else
+ GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_underflow) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([]() {
+ SetTagCheckingLevelSync();
+ volatile int* p = (volatile int*)malloc(16);
+ p[-1] = 42;
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
+ ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a 16-byte allocation.*
+
+allocated by thread .*
+ #00 pc)");
+#else
+ GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_multiple_causes) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([]() {
+ SetTagCheckingLevelSync();
+
+ // Make two allocations with the same tag and close to one another. Check for both properties
+ // with a bounds check -- this relies on the fact that only if the allocations have the same tag
+ // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
+ // (some non-zero value << 56) apart.
+ //
+ // The out-of-bounds access will be considered either an overflow of one or an underflow of the
+ // other.
+ std::set<uintptr_t> allocs;
+ for (int i = 0; i != 4096; ++i) {
+ uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
+ auto it = allocs.insert(alloc).first;
+ if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
+ *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
+ }
+ if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
+ *reinterpret_cast<int*>(alloc + 16) = 42;
+ }
+ }
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
+ ASSERT_MATCH(
+ result,
+ R"(Note: multiple potential causes for this crash were detected, listing them in decreasing order of probability.)");
+
+ // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
+ // overflows), so we can't match explicitly for an underflow message.
+ ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
+#else
+ GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
TEST_F(CrasherTest, LD_PRELOAD) {
int intercept_result;
unique_fd output_fd;
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 6650294..254ed4f 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -40,6 +40,8 @@
void* fdsan_table;
const gwp_asan::AllocatorState* gwp_asan_state;
const gwp_asan::AllocationMetadata* gwp_asan_metadata;
+ const char* scudo_stack_depot;
+ const char* scudo_region_info;
};
// These callbacks are called in a signal handler, and thus must be async signal safe.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
new file mode 100644
index 0000000..4d00ece
--- /dev/null
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
@@ -0,0 +1,42 @@
+/*
+ * 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 "types.h"
+#include "utility.h"
+
+#include <memory.h>
+
+#include "scudo/interface.h"
+
+class ScudoCrashData {
+ public:
+ ScudoCrashData() = delete;
+ ~ScudoCrashData() = default;
+ ScudoCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info);
+
+ bool CrashIsMine() const;
+
+ void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
+
+ private:
+ scudo_error_info error_info_ = {};
+ uintptr_t untagged_fault_addr_;
+
+ void DumpReport(const scudo_error_report* report, log_t* log,
+ unwindstack::Unwinder* unwinder) const;
+};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 35c3fd6..04c4b5c 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -41,6 +41,8 @@
uintptr_t fdsan_table_address = 0;
uintptr_t gwp_asan_state = 0;
uintptr_t gwp_asan_metadata = 0;
+ uintptr_t scudo_stack_depot = 0;
+ uintptr_t scudo_region_info = 0;
bool has_fault_address = false;
uintptr_t fault_address = 0;
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
new file mode 100644
index 0000000..f8bfe07
--- /dev/null
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "libdebuggerd/scudo.h"
+#include "libdebuggerd/gwp_asan.h"
+
+#include "unwindstack/Memory.h"
+#include "unwindstack/Unwinder.h"
+
+#include <bionic/macros.h>
+
+std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr,
+ size_t size) {
+ auto buf = std::make_unique<char[]>(size);
+ if (!process_memory->ReadFully(addr, buf.get(), size)) {
+ return std::unique_ptr<char[]>();
+ }
+ return buf;
+}
+
+static const uintptr_t kTagGranuleSize = 16;
+
+ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
+ const ProcessInfo& process_info) {
+ if (!process_info.has_fault_address) {
+ return;
+ }
+
+ auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot,
+ __scudo_get_stack_depot_size());
+ auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
+ __scudo_get_region_info_size());
+
+ untagged_fault_addr_ = untag_address(process_info.fault_address);
+ uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
+
+ uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
+ if (memory_begin > fault_page) {
+ return;
+ }
+
+ uintptr_t memory_end = fault_page + PAGE_SIZE * 16;
+ if (memory_end < fault_page) {
+ return;
+ }
+
+ auto memory = std::make_unique<char[]>(memory_end - memory_begin);
+ for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) {
+ process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE);
+ }
+
+ auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize);
+ for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) {
+ memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
+ }
+
+ __scudo_get_error_info(&error_info_, process_info.fault_address, stack_depot.get(),
+ region_info.get(), memory.get(), memory_tags.get(), memory_begin,
+ memory_end - memory_begin);
+}
+
+bool ScudoCrashData::CrashIsMine() const {
+ return error_info_.reports[0].error_type != UNKNOWN;
+}
+
+void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
+ if (error_info_.reports[1].error_type != UNKNOWN) {
+ _LOG(log, logtype::HEADER,
+ "\nNote: multiple potential causes for this crash were detected, listing them in "
+ "decreasing order of probability.\n");
+ }
+
+ size_t report_num = 0;
+ while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
+ error_info_.reports[report_num].error_type != UNKNOWN) {
+ DumpReport(&error_info_.reports[report_num++], log, unwinder);
+ }
+}
+
+void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
+ unwindstack::Unwinder* unwinder) const {
+ const char *error_type_str;
+ switch (report->error_type) {
+ case USE_AFTER_FREE:
+ error_type_str = "Use After Free";
+ break;
+ case BUFFER_OVERFLOW:
+ error_type_str = "Buffer Overflow";
+ break;
+ case BUFFER_UNDERFLOW:
+ error_type_str = "Buffer Underflow";
+ break;
+ default:
+ error_type_str = "Unknown";
+ break;
+ }
+
+ uintptr_t diff;
+ const char* location_str;
+
+ if (untagged_fault_addr_ < report->allocation_address) {
+ // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
+ location_str = "left of";
+ diff = report->allocation_address - untagged_fault_addr_;
+ } else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
+ // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
+ location_str = "into";
+ diff = untagged_fault_addr_ - report->allocation_address;
+ } else {
+ // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
+ location_str = "right of";
+ diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
+ }
+
+ // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
+ const char* byte_suffix = "s";
+ if (diff == 1) {
+ byte_suffix = "";
+ }
+ _LOG(log, logtype::HEADER,
+ "\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
+ error_type_str, diff, byte_suffix, location_str, report->allocation_size,
+ report->allocation_address);
+
+ if (report->allocation_trace[0]) {
+ _LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < 64 && report->allocation_trace[i]; ++i) {
+ unwindstack::FrameData frame_data =
+ unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+ }
+
+ if (report->deallocation_trace[0]) {
+ _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < 64 && report->deallocation_trace[i]; ++i) {
+ unwindstack::FrameData frame_data =
+ unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+ }
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d6b2e25..ab65dd1 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -56,6 +56,7 @@
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/gwp_asan.h"
#include "libdebuggerd/open_files_list.h"
+#include "libdebuggerd/scudo.h"
#include "libdebuggerd/utility.h"
#include "gwp_asan/common.h"
@@ -389,14 +390,17 @@
}
std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
+ std::unique_ptr<ScudoCrashData> scudo_crash_data;
if (primary_thread) {
gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
process_info, thread_info);
+ scudo_crash_data =
+ std::make_unique<ScudoCrashData>(unwinder->GetProcessMemory().get(), process_info);
}
if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
gwp_asan_crash_data->DumpCause(log);
- } else if (thread_info.siginfo) {
+ } else if (thread_info.siginfo && !(primary_thread && scudo_crash_data->CrashIsMine())) {
dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
thread_info.registers.get());
}
@@ -427,6 +431,8 @@
gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
}
+ scudo_crash_data->DumpCause(log, unwinder);
+
unwindstack::Maps* maps = unwinder->GetMaps();
dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
thread_info.registers.get());
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 3bf28b6..c8a3431 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,6 +35,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
#include <bionic/reserved_signals.h>
#include <debuggerd/handler.h>
#include <log/log.h>
@@ -374,6 +375,12 @@
return "SEGV_ADIDERR";
case SEGV_ADIPERR:
return "SEGV_ADIPERR";
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+ case SEGV_MTEAERR:
+ return "SEGV_MTEAERR";
+ case SEGV_MTESERR:
+ return "SEGV_MTESERR";
+#endif
}
static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
break;
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index e85660c..53a76ea 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -95,6 +95,8 @@
uintptr_t fdsan_table_address;
uintptr_t gwp_asan_state;
uintptr_t gwp_asan_metadata;
+ uintptr_t scudo_stack_depot;
+ uintptr_t scudo_region_info;
};
struct __attribute__((__packed__)) CrashInfo {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3a2deb7..6b49fc7 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -149,6 +149,7 @@
],
header_libs: [
+ "avb_headers",
"libsnapshot_headers",
]
}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index fd6ff8e..1bf4c9c 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -31,6 +31,7 @@
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
+#include <libavb/libavb.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <libsnapshot/snapshot.h>
@@ -122,6 +123,27 @@
}
}
+static void CopyAVBFooter(std::vector<char>* data, const uint64_t block_device_size) {
+ if (data->size() < AVB_FOOTER_SIZE) {
+ return;
+ }
+ std::string footer;
+ uint64_t footer_offset = data->size() - AVB_FOOTER_SIZE;
+ for (int idx = 0; idx < AVB_FOOTER_MAGIC_LEN; idx++) {
+ footer.push_back(data->at(footer_offset + idx));
+ }
+ if (0 != footer.compare(AVB_FOOTER_MAGIC)) {
+ return;
+ }
+
+ // copy AVB footer from end of data to end of block device
+ uint64_t original_data_size = data->size();
+ data->resize(block_device_size, 0);
+ for (int idx = 0; idx < AVB_FOOTER_SIZE; idx++) {
+ data->at(block_device_size - 1 - idx) = data->at(original_data_size - 1 - idx);
+ }
+}
+
int Flash(FastbootDevice* device, const std::string& partition_name) {
PartitionHandle handle;
if (!OpenPartition(device, partition_name, &handle)) {
@@ -131,8 +153,14 @@
std::vector<char> data = std::move(device->download_data());
if (data.size() == 0) {
return -EINVAL;
- } else if (data.size() > get_block_device_size(handle.fd())) {
+ }
+ uint64_t block_device_size = get_block_device_size(handle.fd());
+ if (data.size() > block_device_size) {
return -EOVERFLOW;
+ } else if (data.size() < block_device_size &&
+ (partition_name == "boot" || partition_name == "boot_a" ||
+ partition_name == "boot_b")) {
+ CopyAVBFooter(&data, block_device_size);
}
WipeOverlayfsForPartition(device, partition_name);
int result = FlashBlockDevice(handle.fd(), data);
diff --git a/init/init.cpp b/init/init.cpp
index 3f8f628..631db8e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -537,7 +537,9 @@
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
-static void set_usb_controller() {
+static void SetUsbController() {
+ static auto controller_set = false;
+ if (controller_set) return;
std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
if (!dir) return;
@@ -546,6 +548,7 @@
if (dp->d_name[0] == '.') continue;
SetProperty("sys.usb.controller", dp->d_name);
+ controller_set = true;
break;
}
}
@@ -800,7 +803,7 @@
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
MountHandler mount_handler(&epoll);
- set_usb_controller();
+ SetUsbController();
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
Action::set_function_map(&function_map);
@@ -910,6 +913,7 @@
}
if (!IsShuttingDown()) {
HandleControlMessages();
+ SetUsbController();
}
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e89f74a..ffd58a3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -66,8 +66,6 @@
#include "sigchld_handler.h"
#include "util.h"
-#define PROC_SYSRQ "/proc/sysrq-trigger"
-
using namespace std::literals;
using android::base::boot_clock;
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 485188b..76460a5 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -29,6 +29,7 @@
#include <cutils/android_reboot.h>
#include "capabilities.h"
+#include "reboot_utils.h"
namespace android {
namespace init {
@@ -138,6 +139,9 @@
LOG(ERROR) << backtrace->FormatFrameData(i);
}
if (init_fatal_panic) {
+ LOG(ERROR) << __FUNCTION__ << ": Trigger crash";
+ android::base::WriteStringToFile("c", PROC_SYSRQ);
+ LOG(ERROR) << __FUNCTION__ << ": Sys-Rq failed to crash the system; fallback to exit().";
_exit(signal_number);
}
RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 878ad96..05bb9ae 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -18,6 +18,8 @@
#include <string>
+#define PROC_SYSRQ "/proc/sysrq-trigger"
+
namespace android {
namespace init {
diff --git a/liblog/README.md b/liblog/README.md
index f64f376..74a2cd7 100644
--- a/liblog/README.md
+++ b/liblog/README.md
@@ -60,8 +60,6 @@
LOG_EVENT_INT(tag, value)
LOG_EVENT_LONG(tag, value)
- clockid_t android_log_clockid()
-
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)
@@ -119,7 +117,7 @@
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
+`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
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index 820b7cb..d7e9b7d 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -133,12 +133,6 @@
(void)__android_log_bswrite(_tag, _value);
#endif
-#ifdef __linux__
-
-clockid_t android_log_clockid(void);
-
-#endif /* __linux__ */
-
/* --------------------------------------------------------------------- */
/*
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 24b88d2..23d76f4 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -112,7 +112,6 @@
/* Multiple log_id_t opens */
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
-#define android_logger_close android_logger_free
/* Single log_id_t open */
struct logger_list* android_logger_list_open(log_id_t id, int mode,
unsigned int tail, pid_t pid);
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 3a75fa3..22c7eca 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -192,7 +192,7 @@
return -EINVAL;
}
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index 9e8d277..238431f 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -216,11 +216,7 @@
p_ret->year_output = false;
p_ret->zone_output = false;
p_ret->epoch_output = false;
-#ifdef __ANDROID__
- p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
-#else
p_ret->monotonic_output = false;
-#endif
p_ret->uid_output = false;
p_ret->descriptive_output = false;
descriptive_output = false;
@@ -1465,13 +1461,10 @@
nsec = entry->tv_nsec;
#if __ANDROID__
if (p_format->monotonic_output) {
- /* prevent convertMonotonic from being called if logd is monotonic */
- if (android_log_clockid() != CLOCK_MONOTONIC) {
- struct timespec time;
- convertMonotonic(&time, entry);
- now = time.tv_sec;
- nsec = time.tv_nsec;
- }
+ struct timespec time;
+ convertMonotonic(&time, entry);
+ now = time.tv_sec;
+ nsec = time.tv_nsec;
}
#endif
if (now < 0) {
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 0751e2c..8e676bd 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -188,7 +188,7 @@
return -EINVAL;
}
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
cp = strdup(filename);
if (!cp) {
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 37670ec..f5e060c 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -365,29 +365,6 @@
return c;
}
-static unsigned char evaluate_persist_ro(const struct cache2_char* self) {
- unsigned char c = self->cache_persist.c;
-
- if (c) {
- return c;
- }
-
- return self->cache_ro.c;
-}
-
-/*
- * Timestamp state generally remains constant, but can change at any time
- * to handle developer requirements.
- */
-clockid_t android_log_clockid() {
- static struct cache2_char clockid = {PTHREAD_MUTEX_INITIALIZER, 0,
- "persist.logd.timestamp", {{NULL, 0xFFFFFFFF}, '\0'},
- "ro.logd.timestamp", {{NULL, 0xFFFFFFFF}, '\0'},
- evaluate_persist_ro};
-
- return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
-}
-
/*
* Security state generally remains constant, but the DO must be able
* to turn off logging should it become spammy after an attack is detected.
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index f4734b9..a4e4def 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -184,7 +184,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
android_pmsg_log_header_t pmsg_header;
pmsg_header.magic = LOGGER_MAGIC;
@@ -260,7 +260,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
struct packet {
android_pmsg_log_header_t pmsg_header;
@@ -335,7 +335,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
struct packet {
android_pmsg_log_header_t pmsg_header;
@@ -410,7 +410,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
struct packet {
android_pmsg_log_header_t pmsg_header;
@@ -483,7 +483,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
struct packet {
android_pmsg_log_header_t pmsg_header;
@@ -792,16 +792,6 @@
BENCHMARK(BM_is_loggable);
/*
- * Measure the time it takes for android_log_clockid.
- */
-static void BM_clockid(benchmark::State& state) {
- while (state.KeepRunning()) {
- android_log_clockid();
- }
-}
-BENCHMARK(BM_clockid);
-
-/*
* Measure the time it takes for __android_log_security.
*/
static void BM_security(benchmark::State& state) {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d3d8e91..bbc985a 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -329,8 +329,6 @@
#ifdef __ANDROID__
pid_t pid = getpid();
- log_time ts(android_log_clockid());
-
size_t num_lines = 1, size = 0, length = 0, total = 0;
const char* cp = message;
while (*cp) {
@@ -432,7 +430,6 @@
pid_t pid = getpid();
static const char tag[] = "TEST__android_log_buf_write";
- log_time ts(android_log_clockid());
auto write_function = [&] {
EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO, tag, message));
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 9ecdd4f..64de00e 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -37,25 +37,22 @@
#include "dhcpmsg.h"
-int fatal();
+int fatal(const char*);
-int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
-{
- int s;
- struct sockaddr_ll bindaddr;
+int open_raw_socket(const char* ifname __unused, uint8_t hwaddr[ETH_ALEN], int if_index) {
+ int s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (s < 0) return fatal("socket(PF_PACKET)");
- if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
- return fatal("socket(PF_PACKET)");
- }
-
- memset(&bindaddr, 0, sizeof(bindaddr));
- bindaddr.sll_family = AF_PACKET;
- bindaddr.sll_protocol = htons(ETH_P_IP);
- bindaddr.sll_halen = ETH_ALEN;
+ struct sockaddr_ll bindaddr = {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htons(ETH_P_IP),
+ .sll_ifindex = if_index,
+ .sll_halen = ETH_ALEN,
+ };
memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
- bindaddr.sll_ifindex = if_index;
if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
+ close(s);
return fatal("Cannot bind raw socket to interface");
}
diff --git a/libnetutils/packet.h b/libnetutils/packet.h
index aade392..66186fc 100644
--- a/libnetutils/packet.h
+++ b/libnetutils/packet.h
@@ -17,7 +17,9 @@
#ifndef _WIFI_PACKET_H_
#define _WIFI_PACKET_H_
-int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
+#include <linux/if_ether.h>
+
+int open_raw_socket(const char* ifname, uint8_t hwaddr[ETH_ALEN], int if_index);
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
int receive_packet(int s, struct dhcp_msg *msg);
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index 766ea0f..ccc6f62 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -89,15 +89,15 @@
"test_vendor.cpp",
],
static_libs: [
+ "libbase",
"libgmock",
+ "liblog",
+ "libjsoncpp",
"libjsonpbverify",
"libjsonpbparse",
"libprocessgroup_proto",
],
shared_libs: [
- "libbase",
- "liblog",
- "libjsoncpp",
"libprotobuf-cpp-full",
],
test_suites: [
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index ff886fd..db61669 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -8,6 +8,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
export_include_dirs: ["include"],
target: {
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 627f0d4..3b98bab 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -43,6 +43,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "apex_inherit",
}
cc_test {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 5efe03f..9c1621b 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -180,6 +180,7 @@
struct ifa_cacheinfo *cacheinfo = nullptr;
char addrstr[INET6_ADDRSTRLEN] = "";
char ifname[IFNAMSIZ] = "";
+ uint32_t flags;
if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
return false;
@@ -194,6 +195,9 @@
// For log messages.
const char *msgtype = rtMessageName(type);
+ // First 8 bits of flags. In practice will always be overridden when parsing IFA_FLAGS below.
+ flags = ifaddr->ifa_flags;
+
struct rtattr *rta;
int len = IFA_PAYLOAD(nh);
for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
@@ -242,6 +246,9 @@
}
cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
+
+ } else if (rta->rta_type == IFA_FLAGS) {
+ flags = *(uint32_t*)RTA_DATA(rta);
}
}
@@ -256,7 +263,7 @@
mSubsystem = strdup("net");
asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
asprintf(&mParams[1], "INTERFACE=%s", ifname);
- asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+ asprintf(&mParams[2], "FLAGS=%u", flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f3d3f27..601904a 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -411,6 +411,7 @@
srcs: [
"benchmarks/unwind_benchmarks.cpp",
"benchmarks/ElfBenchmark.cpp",
+ "benchmarks/MapsBenchmark.cpp",
"benchmarks/SymbolBenchmark.cpp",
"benchmarks/Utils.cpp",
],
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index c108a2a..a46bd7a 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -23,7 +23,9 @@
#include <benchmark/benchmark.h>
#include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
#include "Utils.h"
@@ -75,3 +77,66 @@
BenchmarkElfCreate(state, GetCompressedElfFile());
}
BENCHMARK(BM_elf_create_compressed);
+
+static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
+ unwindstack::MapInfo** build_id_map_info) {
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ return;
+ }
+
+ // Find the libc.so share library and use that for benchmark purposes.
+ *build_id_map_info = nullptr;
+ for (auto& map_info : maps) {
+ if (map_info->offset == 0 && map_info->GetBuildID() != "") {
+ *build_id_map_info = map_info.get();
+ break;
+ }
+ }
+
+ if (*build_id_map_info == nullptr) {
+ state.SkipWithError("Failed to find a map with a BuildID.");
+ }
+}
+
+static void BM_elf_get_build_id_from_object(benchmark::State& state) {
+ unwindstack::LocalMaps maps;
+ unwindstack::MapInfo* build_id_map_info;
+ InitializeBuildId(state, maps, &build_id_map_info);
+
+ unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
+ unwindstack::Regs::CurrentArch());
+ if (!elf->valid()) {
+ state.SkipWithError("Cannot get valid elf from map.");
+ }
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ uintptr_t id = build_id_map_info->build_id;
+ if (id != 0) {
+ delete reinterpret_cast<std::string*>(id);
+ build_id_map_info->build_id = 0;
+ }
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+ }
+}
+BENCHMARK(BM_elf_get_build_id_from_object);
+
+static void BM_elf_get_build_id_from_file(benchmark::State& state) {
+ unwindstack::LocalMaps maps;
+ unwindstack::MapInfo* build_id_map_info;
+ InitializeBuildId(state, maps, &build_id_map_info);
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ uintptr_t id = build_id_map_info->build_id;
+ if (id != 0) {
+ delete reinterpret_cast<std::string*>(id);
+ build_id_map_info->build_id = 0;
+ }
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+ }
+}
+BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
new file mode 100644
index 0000000..be106a3
--- /dev/null
+++ b/libunwindstack/benchmarks/MapsBenchmark.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 <err.h>
+#include <stdint.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+
+class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
+ public:
+ BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
+ virtual ~BenchmarkLocalUpdatableMaps() = default;
+
+ const std::string GetMapsFile() const override { return maps_file_; }
+
+ void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+
+ private:
+ std::string maps_file_;
+};
+
+constexpr size_t kNumMaps = 10000;
+
+static void CreateInitialMap(const char* filename) {
+ std::string maps;
+ for (size_t i = 0; i < kNumMaps; i += 2) {
+ maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
+ (i + 1) * 1000, i);
+ }
+ if (!android::base::WriteStringToFile(maps, filename)) {
+ errx(1, "WriteStringToFile failed");
+ }
+}
+
+static void CreateReparseMap(const char* filename) {
+ std::string maps;
+ for (size_t i = 0; i < kNumMaps; i++) {
+ maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 2000,
+ (i + 1) * 2000, 2 * i);
+ }
+ if (!android::base::WriteStringToFile(maps, filename)) {
+ errx(1, "WriteStringToFile failed");
+ }
+}
+
+void BM_local_updatable_maps_reparse(benchmark::State& state) {
+ TemporaryFile initial_map;
+ CreateInitialMap(initial_map.path);
+
+ TemporaryFile reparse_map;
+ CreateReparseMap(reparse_map.path);
+
+ for (auto _ : state) {
+ BenchmarkLocalUpdatableMaps maps;
+ maps.BenchmarkSetMapsFile(initial_map.path);
+ if (!maps.Reparse()) {
+ errx(1, "Internal Error: reparse of initial maps filed.");
+ }
+ if (maps.Total() != (kNumMaps / 2)) {
+ errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+ kNumMaps / 2);
+ }
+ maps.BenchmarkSetMapsFile(reparse_map.path);
+ if (!maps.Reparse()) {
+ errx(1, "Internal Error: reparse of second set of maps filed.");
+ }
+ if (maps.Total() != kNumMaps) {
+ errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+ kNumMaps);
+ }
+ }
+}
+BENCHMARK(BM_local_updatable_maps_reparse);
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
index de9137a..0bee6ef 100644
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -22,7 +22,6 @@
#include <android-base/strings.h>
-#include <unwindstack/Elf.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -83,63 +82,4 @@
}
BENCHMARK(BM_cached_unwind);
-static void Initialize(benchmark::State& state, unwindstack::Maps& maps,
- unwindstack::MapInfo** build_id_map_info) {
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- return;
- }
-
- // Find the libc.so share library and use that for benchmark purposes.
- *build_id_map_info = nullptr;
- for (auto& map_info : maps) {
- if (map_info->offset == 0 && map_info->GetBuildID() != "") {
- *build_id_map_info = map_info.get();
- break;
- }
- }
-
- if (*build_id_map_info == nullptr) {
- state.SkipWithError("Failed to find a map with a BuildID.");
- }
-}
-
-static void BM_get_build_id_from_elf(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- Initialize(state, maps, &build_id_map_info);
-
- unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
- unwindstack::Regs::CurrentArch());
- if (!elf->valid()) {
- state.SkipWithError("Cannot get valid elf from map.");
- }
-
- for (auto _ : state) {
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_get_build_id_from_elf);
-
-static void BM_get_build_id_from_file(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- Initialize(state, maps, &build_id_map_info);
-
- for (auto _ : state) {
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_get_build_id_from_file);
-
BENCHMARK_MAIN();
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3ab619b..2dbfb70 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,6 +22,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
header_libs: [
"liblog_headers",
@@ -162,6 +163,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "apex_inherit",
}
cc_library {
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 1202c15..1d899ab 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -195,7 +195,7 @@
int prot = PROT_READ;
if (!readOnly) prot |= PROT_WRITE;
- void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+ void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
if (ptr == MAP_FAILED) {
if (errno == EINVAL && length == 0) {
ptr = nullptr;
diff --git a/libutils/FileMap_test.cpp b/libutils/FileMap_test.cpp
index 576d89b..9f7ce85 100644
--- a/libutils/FileMap_test.cpp
+++ b/libutils/FileMap_test.cpp
@@ -32,3 +32,23 @@
ASSERT_EQ(0u, m.getDataLength());
ASSERT_EQ(4096, m.getDataOffset());
}
+
+TEST(FileMap, large_offset) {
+ // Make sure that an offset > INT32_MAX will not fail the create
+ // function. See http://b/155662887.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ off64_t offset = INT32_MAX + 1024LL;
+
+ // Make the temporary file large enough to pass the mmap.
+ ASSERT_EQ(offset, lseek64(tf.fd, offset, SEEK_SET));
+ char value = 0;
+ ASSERT_EQ(1, write(tf.fd, &value, 1));
+
+ android::FileMap m;
+ ASSERT_TRUE(m.create("test", tf.fd, offset, 0, true));
+ ASSERT_STREQ("test", m.getFileName());
+ ASSERT_EQ(0u, m.getDataLength());
+ ASSERT_EQ(offset, m.getDataOffset());
+}
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index dee577e..6002567 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -19,12 +19,20 @@
#include <unistd.h>
+#if !defined(__MINGW32__)
+#include <sys/mman.h>
+#endif
+
#if defined(__APPLE__)
/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
-
+static_assert(sizeof(off_t) >= 8, "This code requires that Mac OS have at least a 64-bit off_t.");
typedef off_t off64_t;
+static inline void* mmap64(void* addr, size_t length, int prot, int flags, int fd, off64_t offset) {
+ return mmap(addr, length, prot, flags, fd, offset);
+}
+
static inline off64_t lseek64(int fd, off64_t offset, int whence) {
return lseek(fd, offset, whence);
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 8185f01..13023f2 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -459,7 +459,7 @@
closedir);
if (!dir.get()) return retval;
- log_time now(android_log_clockid());
+ log_time now(CLOCK_REALTIME);
size_t len = strlen(file);
log_time modulo(0, NS_PER_SEC);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index b32b437..3a55c4e 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -174,11 +174,6 @@
}
TEST(logcat, year) {
- if (android_log_clockid() == CLOCK_MONOTONIC) {
- fprintf(stderr, "Skipping test, logd is monotonic time\n");
- return;
- }
-
int count;
int tries = 3; // in case run too soon after system start or buffer clear
@@ -249,11 +244,6 @@
}
TEST(logcat, tz) {
- if (android_log_clockid() == CLOCK_MONOTONIC) {
- fprintf(stderr, "Skipping test, logd is monotonic time\n");
- return;
- }
-
int tries = 4; // in case run too soon after system start or buffer clear
int count;
diff --git a/logd/Android.bp b/logd/Android.bp
index b6d30cd..ee86566 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -33,11 +33,12 @@
srcs: [
"LogCommand.cpp",
+ "ChattyLogBuffer.cpp",
"CommandListener.cpp",
"LogListener.cpp",
"LogReader.cpp",
+ "LogReaderList.cpp",
"LogReaderThread.cpp",
- "LogBuffer.cpp",
"LogBufferElement.cpp",
"LogStatistics.cpp",
"LogWhiteBlackList.cpp",
@@ -52,7 +53,14 @@
export_include_dirs: ["."],
- cflags: ["-Werror"] + event_flag,
+ cflags: [
+ "-Wextra",
+ "-Wthread-safety",
+ ] + event_flag,
+
+ lto: {
+ thin: true
+ }
}
cc_binary {
@@ -75,7 +83,13 @@
"libcap",
],
- cflags: ["-Werror"],
+ cflags: [
+ "-Wextra",
+ ],
+
+ lto: {
+ thin: true
+ }
}
cc_binary {
@@ -90,10 +104,8 @@
shared_libs: ["libbase"],
cflags: [
- "-Wall",
+ "-Wconversion",
"-Wextra",
- "-Werror",
- "-Wconversion"
],
}
diff --git a/logd/LogBuffer.cpp b/logd/ChattyLogBuffer.cpp
similarity index 73%
rename from logd/LogBuffer.cpp
rename to logd/ChattyLogBuffer.cpp
index a7323e8..fa5bcee 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/ChattyLogBuffer.cpp
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// for manual checking of stale entries during LogBuffer::erase()
+// 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>
@@ -32,7 +34,6 @@
#include <cutils/properties.h>
#include <private/android_logger.h>
-#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
#include "LogUtils.h"
@@ -44,72 +45,22 @@
// Default
#define log_buffer_size(id) mMaxSize[id]
-void LogBuffer::init() {
+void ChattyLogBuffer::Init() {
log_id_for_each(i) {
- if (setSize(i, __android_logger_get_buffer_size(i))) {
- setSize(i, LOG_BUFFER_MIN_SIZE);
+ if (SetSize(i, __android_logger_get_buffer_size(i))) {
+ SetSize(i, LOG_BUFFER_MIN_SIZE);
}
}
- bool lastMonotonic = monotonic;
- monotonic = android_log_clockid() == CLOCK_MONOTONIC;
- if (lastMonotonic != monotonic) {
- //
- // Fixup all timestamps, may not be 100% accurate, but better than
- // throwing what we have away when we get 'surprised' by a change.
- // In-place element fixup so no need to check reader-lock. Entries
- // should already be in timestamp order, but we could end up with a
- // few out-of-order entries if new monotonics come in before we
- // are notified of the reinit change in status. A Typical example would
- // be:
- // --------- beginning of system
- // 10.494082 184 201 D Cryptfs : Just triggered post_fs_data
- // --------- beginning of kernel
- // 0.000000 0 0 I : Initializing cgroup subsys
- // as the act of mounting /data would trigger persist.logd.timestamp to
- // be corrected. 1/30 corner case YMMV.
- //
- rdlock();
- LogBufferElementCollection::iterator it = mLogElements.begin();
- while ((it != mLogElements.end())) {
- LogBufferElement* e = *it;
- if (monotonic) {
- if (!android::isMonotonic(e->mRealTime)) {
- LogKlog::convertRealToMonotonic(e->mRealTime);
- if ((e->mRealTime.tv_nsec % 1000) == 0) {
- e->mRealTime.tv_nsec++;
- }
- }
- } else {
- if (android::isMonotonic(e->mRealTime)) {
- LogKlog::convertMonotonicToReal(e->mRealTime);
- if ((e->mRealTime.tv_nsec % 1000) == 0) {
- e->mRealTime.tv_nsec++;
- }
- }
- }
- ++it;
- }
- unlock();
- }
-
// Release any sleeping reader threads to dump their current content.
- LogReaderThread::wrlock();
-
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- entry->triggerReader_Locked();
- times++;
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ reader_thread->triggerReader_Locked();
}
-
- LogReaderThread::unlock();
}
-LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune)
- : monotonic(android_log_clockid() == CLOCK_MONOTONIC),
- mTimes(*times),
- tags_(tags),
- prune_(prune) {
+ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
+ LogStatistics* stats)
+ : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) {
pthread_rwlock_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
@@ -117,17 +68,17 @@
droppedElements[i] = nullptr;
}
- init();
+ Init();
}
-LogBuffer::~LogBuffer() {
+ChattyLogBuffer::~ChattyLogBuffer() {
log_id_for_each(i) {
delete lastLoggedElements[i];
delete droppedElements[i];
}
}
-LogBufferElementCollection::iterator LogBuffer::GetOldest(log_id_t log_id) {
+LogBufferElementCollection::iterator ChattyLogBuffer::GetOldest(log_id_t log_id) {
auto it = mLogElements.begin();
if (oldest_[log_id]) {
it = *oldest_[log_id];
@@ -143,8 +94,7 @@
enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
-static enum match_type identical(LogBufferElement* elem,
- LogBufferElement* last) {
+static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) {
// is it mostly identical?
// if (!elem) return DIFFERENT;
ssize_t lenl = elem->getMsgLen();
@@ -158,8 +108,7 @@
if (elem->getTid() != last->getTid()) return DIFFERENT;
// last is more than a minute old, stop squashing identical messages
- if (elem->getRealTime().nsec() >
- (last->getRealTime().nsec() + 60 * NS_PER_SEC))
+ if (elem->getRealTime().nsec() > (last->getRealTime().nsec() + 60 * NS_PER_SEC))
return DIFFERENT;
// Identical message
@@ -168,21 +117,17 @@
if (lenl == lenr) {
if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
// liblog tagged messages (content gets summed)
- if ((elem->getLogId() == 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)) {
+ if (elem->getLogId() == 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 (last->isBinary() &&
- (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))) {
+ if (last->isBinary() && 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);
@@ -198,15 +143,14 @@
if (!avcr) return DIFFERENT;
lenr -= avcr - msgr;
if (lenl != lenr) return DIFFERENT;
- if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc),
- lenl - strlen(avc))) {
+ if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) {
return DIFFERENT;
}
return SAME;
}
-int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
- pid_t tid, const char* msg, uint16_t len) {
+int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+ const char* msg, uint16_t len) {
if (log_id >= LOG_ID_MAX) {
return -EINVAL;
}
@@ -242,9 +186,7 @@
}
if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
// Log traffic received to total
- wrlock();
- stats.addTotal(elem);
- unlock();
+ stats_->AddTotal(elem);
delete elem;
return -EACCES;
}
@@ -330,8 +272,7 @@
if (dropped) {
// Sum up liblog tag messages?
if ((count == 0) /* at Pass 1 */ && (match == SAME_LIBLOG)) {
- android_log_event_int_t* event =
- reinterpret_cast<android_log_event_int_t*>(
+ android_log_event_int_t* event = reinterpret_cast<android_log_event_int_t*>(
const_cast<char*>(currentLast->getMsg()));
//
// To unit test, differentiate with something like:
@@ -342,7 +283,7 @@
uint32_t swab = event->payload.data;
unsigned long long total = htole32(swab);
event = reinterpret_cast<android_log_event_int_t*>(
- const_cast<char*>(elem->getMsg()));
+ const_cast<char*>(elem->getMsg()));
swab = event->payload.data;
lastLoggedElements[LOG_ID_EVENTS] = elem;
@@ -353,7 +294,7 @@
unlock();
return len;
}
- stats.addTotal(currentLast);
+ stats_->AddTotal(currentLast);
delete currentLast;
swab = total;
event->payload.data = htole32(swab);
@@ -369,7 +310,7 @@
}
}
if (count) {
- stats.addTotal(currentLast);
+ stats_->AddTotal(currentLast);
currentLast->setDropped(count);
}
droppedElements[log_id] = currentLast;
@@ -397,39 +338,24 @@
return len;
}
-// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
-void LogBuffer::log(LogBufferElement* elem) {
+// assumes ChattyLogBuffer::wrlock() held, owns elem, look after garbage collection
+void ChattyLogBuffer::log(LogBufferElement* elem) {
mLogElements.push_back(elem);
- stats.add(elem);
+ stats_->Add(elem);
maybePrune(elem->getLogId());
+ reader_list_->NotifyNewLog(1 << elem->getLogId());
}
-// Prune at most 10% of the log entries or maxPrune, whichever is less.
-//
-// LogBuffer::wrlock() must be held when this function is called.
-void LogBuffer::maybePrune(log_id_t id) {
- size_t sizes = stats.sizes(id);
- unsigned long maxSize = log_buffer_size(id);
- if (sizes > maxSize) {
- size_t sizeOver = sizes - ((maxSize * 9) / 10);
- size_t elements = stats.realElements(id);
- size_t minElements = elements / 100;
- if (minElements < minPrune) {
- minElements = minPrune;
- }
- unsigned long pruneRows = elements * sizeOver / sizes;
- if (pruneRows < minElements) {
- pruneRows = minElements;
- }
- if (pruneRows > maxPrune) {
- pruneRows = maxPrune;
- }
- prune(id, pruneRows);
+// ChattyLogBuffer::wrlock() must be held when this function is called.
+void ChattyLogBuffer::maybePrune(log_id_t id) {
+ unsigned long prune_rows;
+ if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) {
+ prune(id, prune_rows);
}
}
-LogBufferElementCollection::iterator LogBuffer::erase(
- LogBufferElementCollection::iterator it, bool coalesce) {
+LogBufferElementCollection::iterator ChattyLogBuffer::erase(LogBufferElementCollection::iterator it,
+ bool coalesce) {
LogBufferElement* element = *it;
log_id_t id = element->getLogId();
@@ -437,9 +363,8 @@
// 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->getUid();
+ int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag()
+ : element->getUid();
LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
if ((found != mLastWorst[id].end()) && (it == found->second)) {
mLastWorst[id].erase(found);
@@ -450,10 +375,8 @@
// element->getUid() 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->getPid());
- if ((found != mLastWorstPidOfSystem[id].end()) &&
- (it == found->second)) {
+ LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element->getPid());
+ if (found != mLastWorstPidOfSystem[id].end() && it == found->second) {
mLastWorstPidOfSystem[id].erase(found);
}
}
@@ -463,9 +386,8 @@
log_id_for_each(i) { doSetLast |= setLast[i] = oldest_[i] && it == *oldest_[i]; }
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
LogBufferElementCollection::iterator bad = it;
- int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
- ? element->getTag()
- : element->getUid();
+ int key =
+ (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() : element->getUid();
#endif
it = mLogElements.erase(it);
if (doSetLast) {
@@ -484,22 +406,20 @@
log_id_for_each(i) {
for (auto b : mLastWorst[i]) {
if (bad == b.second) {
- android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i,
- b.first, key);
+ android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i, b.first, key);
}
}
for (auto b : mLastWorstPidOfSystem[i]) {
if (bad == b.second) {
- android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i,
- b.first);
+ android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i, b.first);
}
}
}
#endif
if (coalesce) {
- stats.erase(element);
+ stats_->Erase(element);
} else {
- stats.subtract(element);
+ stats_->Subtract(element);
}
delete element;
@@ -519,26 +439,20 @@
uint64_t value;
} __packed;
- public:
- LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid)
- : uid(uid), pid(pid), tid(tid) {
- }
- explicit LogBufferElementKey(uint64_t key) : value(key) {
- }
+ public:
+ LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) : uid(uid), pid(pid), tid(tid) {}
+ explicit LogBufferElementKey(uint64_t key) : value(key) {}
- uint64_t getKey() {
- return value;
- }
+ uint64_t getKey() { return value; }
};
class LogBufferElementLast {
typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
LogBufferElementMap map;
- public:
+ public:
bool coalesce(LogBufferElement* element, uint16_t dropped) {
- LogBufferElementKey key(element->getUid(), element->getPid(),
- element->getTid());
+ LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid());
LogBufferElementMap::iterator it = map.find(key.getKey());
if (it != map.end()) {
LogBufferElement* found = it->second;
@@ -554,14 +468,11 @@
}
void add(LogBufferElement* element) {
- LogBufferElementKey key(element->getUid(), element->getPid(),
- element->getTid());
+ LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid());
map[key.getKey()] = element;
}
- inline void clear() {
- map.clear();
- }
+ void clear() { map.clear(); }
void clear(LogBufferElement* element) {
uint64_t current = element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
@@ -579,21 +490,20 @@
// If the selected reader is blocking our pruning progress, decide on
// what kind of mitigation is necessary to unblock the situation.
-void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) {
- if (stats.sizes(id) > (2 * log_buffer_size(id))) { // +100%
+void ChattyLogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) {
+ if (stats_->Sizes(id) > (2 * log_buffer_size(id))) { // +100%
// A misbehaving or slow reader has its connection
// dropped if we hit too much memory pressure.
- android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n",
+ android::prdebug("Kicking blocked reader, pid %d, from ChattyLogBuffer::kickMe()\n",
me->client()->getPid());
me->release_Locked();
- } else if (me->timeout().tv_sec || me->timeout().tv_nsec) {
- // Allow a blocked WRAP timeout reader to
- // trigger and start reporting the log data.
+ } else if (me->deadline().time_since_epoch().count() != 0) {
+ // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
me->triggerReader_Locked();
} else {
// tell slow reader to skip entries to catch up
android::prdebug(
- "Skipping %lu entries from slow reader, pid %d, from LogBuffer::kickMe()\n",
+ "Skipping %lu entries from slow reader, pid %d, from ChattyLogBuffer::kickMe()\n",
pruneRows, me->client()->getPid());
me->triggerSkip_Locked(id, pruneRows);
}
@@ -644,25 +554,25 @@
// The third thread is optional, and only gets hit if there was a whitelist
// and more needs to be pruned against the backstop of the region lock.
//
-// LogBuffer::wrlock() must be held when this function is called.
+// ChattyLogBuffer::wrlock() must be held when this function is called.
//
-bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
+bool ChattyLogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogReaderThread* oldest = nullptr;
bool busy = false;
bool clearAll = pruneRows == ULONG_MAX;
- LogReaderThread::rdlock();
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
// Region locked?
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- if (entry->IsWatching(id) && (!oldest || oldest->start() > entry->start() ||
- (oldest->start() == entry->start() &&
- (entry->timeout().tv_sec || entry->timeout().tv_nsec)))) {
- oldest = entry;
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ if (!reader_thread->IsWatching(id)) {
+ continue;
}
- times++;
+ 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;
@@ -674,8 +584,7 @@
while (it != mLogElements.end()) {
LogBufferElement* element = *it;
- if ((element->getLogId() != id) ||
- (element->getUid() != caller_uid)) {
+ if (element->getLogId() != id || element->getUid() != caller_uid) {
++it;
continue;
}
@@ -691,7 +600,6 @@
break;
}
}
- LogReaderThread::unlock();
return busy;
}
@@ -708,19 +616,14 @@
// Calculate threshold as 12.5% of available storage
size_t threshold = log_buffer_size(id) / 8;
- if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
- stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
- .findWorst(worst, worst_sizes, second_worst_sizes,
- threshold);
+ 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.sort(AID_ROOT, (pid_t)0, 2, id)
- .findWorst(worst, worst_sizes, second_worst_sizes,
- threshold);
+ stats_->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
- if ((worst == AID_SYSTEM) && prune_->worstPidOfSystemEnabled()) {
- stats.sortPids(worst, (pid_t)0, 2, id)
- .findWorst(worstPid, worst_sizes, second_worst_sizes);
+ if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
+ stats_->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
}
}
}
@@ -740,10 +643,8 @@
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 != mLogElements.end())) {
+ LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
+ if (found != mLastWorst[id].end() && found->second != mLogElements.end()) {
leading = false;
it = found->second;
}
@@ -751,10 +652,9 @@
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 != mLogElements.end())) {
+ LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid);
+ if (found != mLastWorstPidOfSystem[id].end() &&
+ found->second != mLogElements.end()) {
leading = false;
it = found->second;
}
@@ -763,7 +663,7 @@
if (leading) {
it = GetOldest(id);
}
- static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 };
+ static const timespec too_old = {EXPIRE_HOUR_THRESHOLD * 60 * 60, 0};
LogBufferElementCollection::iterator lastt;
lastt = mLogElements.end();
--lastt;
@@ -796,9 +696,8 @@
continue;
}
- int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
- ? element->getTag()
- : element->getUid();
+ int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag()
+ : element->getUid();
if (hasBlacklist && prune_->naughty(element)) {
last.clear(element);
@@ -829,10 +728,9 @@
if (dropped) {
last.add(element);
- if (worstPid &&
- ((!gc && (element->getPid() == worstPid)) ||
- (mLastWorstPidOfSystem[id].find(element->getPid()) ==
- mLastWorstPidOfSystem[id].end()))) {
+ if (worstPid && ((!gc && element->getPid() == worstPid) ||
+ mLastWorstPidOfSystem[id].find(element->getPid()) ==
+ mLastWorstPidOfSystem[id].end())) {
// element->getUid() 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.
@@ -846,8 +744,7 @@
continue;
}
- if ((key != worst) ||
- (worstPid && (element->getPid() != worstPid))) {
+ if (key != worst || (worstPid && element->getPid() != worstPid)) {
leading = false;
last.clear(element);
++it;
@@ -869,22 +766,20 @@
if (leading) {
it = erase(it);
} else {
- stats.drop(element);
+ stats_->Drop(element);
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()))) {
+ if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) ==
+ mLastWorstPidOfSystem[id].end())) {
// element->getUid() 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())) {
+ if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) {
mLastWorst[id][worst] = it;
}
++it;
@@ -952,13 +847,11 @@
}
}
- LogReaderThread::unlock();
-
return (pruneRows > 0) && busy;
}
// clear all rows of type "id" from the buffer.
-bool LogBuffer::clear(log_id_t id, uid_t uid) {
+bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) {
bool busy = true;
// If it takes more than 4 tries (seconds) to clear, then kill reader(s)
for (int retry = 4;;) {
@@ -975,20 +868,15 @@
// readers and let the clear run (below) deal with determining
// if we are still blocked and return an error code to caller.
if (busy) {
- LogReaderThread::wrlock();
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- // Killer punch
- if (entry->IsWatching(id)) {
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ if (reader_thread->IsWatching(id)) {
android::prdebug(
- "Kicking blocked reader, pid %d, from LogBuffer::clear()\n",
- entry->client()->getPid());
- entry->release_Locked();
+ "Kicking blocked reader, pid %d, from ChattyLogBuffer::clear()\n",
+ reader_thread->client()->getPid());
+ reader_thread->release_Locked();
}
- times++;
}
- LogReaderThread::unlock();
}
}
wrlock();
@@ -1002,16 +890,8 @@
return busy;
}
-// get the used space associated with "id".
-unsigned long LogBuffer::getSizeUsed(log_id_t id) {
- rdlock();
- size_t retval = stats.sizes(id);
- unlock();
- return retval;
-}
-
// set the total space allocated to "id"
-int LogBuffer::setSize(log_id_t id, unsigned long size) {
+int ChattyLogBuffer::SetSize(log_id_t id, unsigned long size) {
// Reasonable limits ...
if (!__android_logger_valid_buffer_size(size)) {
return -1;
@@ -1023,16 +903,16 @@
}
// get the total space allocated to "id"
-unsigned long LogBuffer::getSize(log_id_t id) {
+unsigned long ChattyLogBuffer::GetSize(log_id_t id) {
rdlock();
size_t retval = log_buffer_size(id);
unlock();
return retval;
}
-uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged,
- bool security,
- const std::function<int(const LogBufferElement* element)>& filter) {
+uint64_t ChattyLogBuffer::FlushTo(
+ SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged, bool security,
+ const std::function<FlushToResult(const LogBufferElement* element)>& filter) {
LogBufferElementCollection::iterator it;
uid_t uid = reader->getUid();
@@ -1070,11 +950,11 @@
// NB: calling out to another object with wrlock() held (safe)
if (filter) {
- int ret = filter(element);
- if (ret == false) {
+ FlushToResult ret = filter(element);
+ if (ret == FlushToResult::kSkip) {
continue;
}
- if (ret != true) {
+ if (ret == FlushToResult::kStop) {
break;
}
}
@@ -1088,13 +968,13 @@
// is due to spam filter. chatty to chatty of different
// source is also due to spam filter.
lastTid[element->getLogId()] =
- (element->getDropped() && !sameTid) ? 0 : element->getTid();
+ (element->getDropped() && !sameTid) ? 0 : element->getTid();
}
unlock();
// range locking in LastLogTimes looks after us
- curr = element->flushTo(reader, this, sameTid);
+ curr = element->flushTo(reader, stats_, sameTid);
if (curr == element->FLUSH_ERROR) {
return curr;
@@ -1106,14 +986,3 @@
return curr;
}
-
-std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
- unsigned int logMask) {
- wrlock();
-
- std::string ret = stats.format(uid, pid, logMask);
-
- unlock();
-
- return ret;
-}
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
new file mode 100644
index 0000000..d9cd24f
--- /dev/null
+++ b/logd/ChattyLogBuffer.h
@@ -0,0 +1,97 @@
+/*
+ * 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/log.h>
+#include <private/android_filesystem_config.h>
+#include <sysutils/SocketClient.h>
+
+#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
+#include "LogWhiteBlackList.h"
+
+typedef std::list<LogBufferElement*> LogBufferElementCollection;
+
+class LogReaderList;
+class LogReaderThread;
+
+class ChattyLogBuffer : public LogBuffer {
+ LogBufferElementCollection mLogElements;
+ pthread_rwlock_t mLogElementsLock;
+
+ // watermark of any worst/chatty uid processing
+ typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap;
+ LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
+ // watermark of any worst/chatty pid of system processing
+ typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap;
+ LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
+
+ unsigned long mMaxSize[LOG_ID_MAX];
+
+ LogBufferElement* lastLoggedElements[LOG_ID_MAX];
+ LogBufferElement* droppedElements[LOG_ID_MAX];
+ void log(LogBufferElement* elem);
+
+ public:
+ ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
+ LogStatistics* stats);
+ ~ChattyLogBuffer();
+ void Init() override;
+
+ int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
+ uint16_t len) override;
+ uint64_t FlushTo(
+ SocketClient* writer, uint64_t start, pid_t* lastTid, bool privileged, bool security,
+ const std::function<FlushToResult(const LogBufferElement* element)>& filter) override;
+
+ bool Clear(log_id_t id, uid_t uid = AID_ROOT) override;
+ unsigned long GetSize(log_id_t id) override;
+ int SetSize(log_id_t id, unsigned long size) override;
+
+ private:
+ void wrlock() { pthread_rwlock_wrlock(&mLogElementsLock); }
+ void rdlock() { pthread_rwlock_rdlock(&mLogElementsLock); }
+ void unlock() { pthread_rwlock_unlock(&mLogElementsLock); }
+
+ void maybePrune(log_id_t id);
+ void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows);
+
+ bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
+ LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it,
+ bool coalesce = false);
+
+ // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if
+ // there are no logs for the given log type. Requires mLogElementsLock to be held.
+ LogBufferElementCollection::iterator GetOldest(log_id_t log_id);
+
+ LogReaderList* reader_list_;
+ LogTags* tags_;
+ PruneList* prune_;
+ LogStatistics* stats_;
+
+ // Keeps track of the iterator to the oldest log message of a given log type, as an
+ // optimization when pruning logs. Use GetOldest() to retrieve.
+ std::optional<LogBufferElementCollection::iterator> oldest_[LOG_ID_MAX];
+};
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 4044dc9..0ff19f8 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "CommandListener.h"
+
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
@@ -35,12 +37,11 @@
#include <private/android_filesystem_config.h>
#include <sysutils/SocketClient.h>
-#include "CommandListener.h"
-#include "LogCommand.h"
#include "LogUtils.h"
-CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune)
- : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune) {
+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));
@@ -80,7 +81,7 @@
return 0;
}
- cli->sendMsg(buf()->clear((log_id_t)id, uid) ? "busy" : "success");
+ cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "busy" : "success");
return 0;
}
@@ -98,7 +99,7 @@
return 0;
}
- unsigned long size = buf()->getSize((log_id_t)id);
+ unsigned long size = buf()->GetSize((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
@@ -125,7 +126,7 @@
}
unsigned long size = atol(argv[2]);
- if (buf()->setSize((log_id_t)id, size)) {
+ if (buf()->SetSize((log_id_t)id, size)) {
cli->sendMsg("Range Error");
return 0;
}
@@ -148,7 +149,7 @@
return 0;
}
- unsigned long size = buf()->getSizeUsed((log_id_t)id);
+ unsigned long size = stats()->Sizes((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
@@ -209,7 +210,7 @@
}
}
- cli->sendMsg(PackageString(buf()->formatStatistics(uid, pid, logMask)).c_str());
+ cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str());
return 0;
}
@@ -298,7 +299,7 @@
setname();
android::prdebug("logd reinit");
- buf()->init();
+ buf()->Init();
prune()->init(nullptr);
// This only works on userdebug and eng devices to re-read the
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index c90c247..fd934f7 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -22,12 +22,13 @@
#include "LogCommand.h"
#include "LogListener.h"
#include "LogReader.h"
+#include "LogStatistics.h"
#include "LogTags.h"
#include "LogWhiteBlackList.h"
class CommandListener : public FrameworkListener {
public:
- CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune);
+ CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics);
virtual ~CommandListener() {}
private:
@@ -36,20 +37,22 @@
LogBuffer* buf_;
LogTags* tags_;
PruneList* prune_;
+ LogStatistics* stats_;
-#define LogCmd(name, command_string) \
- class name##Cmd : public LogCommand { \
- public: \
- explicit name##Cmd(CommandListener* parent) \
- : LogCommand(#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_; } \
- CommandListener* parent_; \
+#define LogCmd(name, command_string) \
+ class name##Cmd : public LogCommand { \
+ public: \
+ explicit name##Cmd(CommandListener* parent) \
+ : LogCommand(#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);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 37067bd..0ce9796 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogAudit.h"
+
#include <ctype.h>
#include <endian.h>
#include <errno.h>
@@ -34,10 +36,7 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include "LogAudit.h"
-#include "LogBuffer.h"
#include "LogKlog.h"
-#include "LogReader.h"
#include "LogUtils.h"
#include "libaudit.h"
@@ -45,16 +44,14 @@
'<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
-LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
+LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats)
: SocketListener(getLogSocket(), false),
logbuf(buf),
- reader(reader),
fdDmesg(fdDmesg),
- main(__android_logger_property_get_bool("ro.logd.auditd.main",
- BOOL_DEFAULT_TRUE)),
- events(__android_logger_property_get_bool("ro.logd.auditd.events",
- BOOL_DEFAULT_TRUE)),
- initialized(false) {
+ main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)),
+ events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)),
+ initialized(false),
+ stats_(stats) {
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
'l',
'o',
@@ -211,9 +208,7 @@
++cp;
}
tid = pid;
- logbuf->wrlock();
- uid = logbuf->pidToUid(pid);
- logbuf->unlock();
+ uid = stats_->PidToUid(pid);
memmove(pidptr, cp, strlen(cp) + 1);
}
@@ -247,22 +242,10 @@
static const char audit_str[] = " audit(";
char* timeptr = strstr(str, audit_str);
- if (timeptr &&
- ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
+ 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);
- if (!isMonotonic()) {
- if (android::isMonotonic(now)) {
- LogKlog::convertMonotonicToReal(now);
- }
- } else {
- if (!android::isMonotonic(now)) {
- LogKlog::convertRealToMonotonic(now);
- }
- }
- } else if (isMonotonic()) {
- now = log_time(CLOCK_MONOTONIC);
} else {
now = log_time(CLOCK_REALTIME);
}
@@ -291,9 +274,8 @@
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);
+ 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;
}
@@ -313,9 +295,7 @@
pid = tid;
comm = "auditd";
} else {
- logbuf->wrlock();
- comm = commfree = logbuf->pidToName(pid);
- logbuf->unlock();
+ comm = commfree = stats_->PidToName(pid);
if (!comm) {
comm = "unknown";
}
@@ -347,9 +327,8 @@
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);
+ 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;
@@ -361,7 +340,6 @@
free(str);
if (notify) {
- reader->notifyNewLog(notify);
if (rc < 0) {
rc = message_len;
}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index c3d7a3e..181920e 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -14,36 +14,30 @@
* limitations under the License.
*/
-#ifndef _LOGD_LOG_AUDIT_H__
-#define _LOGD_LOG_AUDIT_H__
+#pragma once
#include <map>
#include <sysutils/SocketListener.h>
#include "LogBuffer.h"
-
-class LogReader;
+#include "LogStatistics.h"
class LogAudit : public SocketListener {
LogBuffer* logbuf;
- LogReader* reader;
int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
bool main;
bool events;
bool initialized;
- public:
- LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
+ public:
+ LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats);
int log(char* buf, size_t len);
- bool isMonotonic() {
- return logbuf->isMonotonic();
- }
- protected:
+ protected:
virtual bool onDataAvailable(SocketClient* cli);
- private:
+ private:
static int getLogSocket();
std::map<std::string, std::string> populateDenialMap();
std::string denialParse(const std::string& denial, char terminator,
@@ -51,6 +45,6 @@
void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
int logPrint(const char* fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
-};
-#endif
+ LogStatistics* stats_;
+};
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index eb41efb..887e5f0 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 The Android Open Source Project
+ * 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.
@@ -18,153 +18,37 @@
#include <sys/types.h>
-#include <list>
-#include <optional>
-#include <string>
+#include <functional>
-#include <android/log.h>
-#include <private/android_filesystem_config.h>
+#include <log/log.h>
#include <sysutils/SocketClient.h>
#include "LogBufferElement.h"
-#include "LogReaderThread.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogWhiteBlackList.h"
-//
-// We are either in 1970ish (MONOTONIC) or 2016+ish (REALTIME) so to
-// differentiate without prejudice, we use 1972 to delineate, earlier
-// is likely monotonic, later is real. Otherwise we start using a
-// dividing line between monotonic and realtime if more than a minute
-// difference between them.
-//
-namespace android {
-
-static bool isMonotonic(const log_time& mono) {
- static const uint32_t EPOCH_PLUS_2_YEARS = 2 * 24 * 60 * 60 * 1461 / 4;
- static const uint32_t EPOCH_PLUS_MINUTE = 60;
-
- if (mono.tv_sec >= EPOCH_PLUS_2_YEARS) {
- return false;
- }
-
- log_time now(CLOCK_REALTIME);
-
- /* Timezone and ntp time setup? */
- if (now.tv_sec >= EPOCH_PLUS_2_YEARS) {
- return true;
- }
-
- /* no way to differentiate realtime from monotonic time */
- if (now.tv_sec < EPOCH_PLUS_MINUTE) {
- return false;
- }
-
- log_time cpu(CLOCK_MONOTONIC);
- /* too close to call to differentiate monotonic times from realtime */
- if ((cpu.tv_sec + EPOCH_PLUS_MINUTE) >= now.tv_sec) {
- return false;
- }
-
- /* dividing line half way between monotonic and realtime */
- return mono.tv_sec < ((cpu.tv_sec + now.tv_sec) / 2);
-}
-}
-
-typedef std::list<LogBufferElement*> LogBufferElementCollection;
+enum class FlushToResult {
+ kSkip,
+ kStop,
+ kWrite,
+};
class LogBuffer {
- LogBufferElementCollection mLogElements;
- pthread_rwlock_t mLogElementsLock;
+ public:
+ virtual ~LogBuffer() {}
- LogStatistics stats;
+ virtual void Init() = 0;
- // watermark of any worst/chatty uid processing
- typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
- LogBufferIteratorMap;
- LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
- // watermark of any worst/chatty pid of system processing
- typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator>
- LogBufferPidIteratorMap;
- LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
-
- unsigned long mMaxSize[LOG_ID_MAX];
-
- bool monotonic;
-
- LogBufferElement* lastLoggedElements[LOG_ID_MAX];
- LogBufferElement* droppedElements[LOG_ID_MAX];
- void log(LogBufferElement* elem);
-
- public:
- LastLogTimes& mTimes;
-
- LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune);
- ~LogBuffer();
- void init();
- bool isMonotonic() {
- return monotonic;
- }
-
- 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);
+ 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;
// lastTid is an optional context to help detect if the last previous
// valid message was from the same source so we can differentiate chatty
// filter types (identical or expired)
- uint64_t flushTo(SocketClient* writer, uint64_t start,
- pid_t* lastTid, // &lastTid[LOG_ID_MAX] or nullptr
- bool privileged, bool security,
- const std::function<int(const LogBufferElement* element)>& filter);
+ virtual uint64_t FlushTo(
+ SocketClient* writer, uint64_t start,
+ pid_t* last_tid, // nullable
+ bool privileged, bool security,
+ const std::function<FlushToResult(const LogBufferElement* element)>& filter) = 0;
- bool clear(log_id_t id, uid_t uid = AID_ROOT);
- unsigned long getSize(log_id_t id);
- int setSize(log_id_t id, unsigned long size);
- unsigned long getSizeUsed(log_id_t id);
-
- std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask);
-
- void enableStatistics() {
- stats.enableStatistics();
- }
-
- // helper must be protected directly or implicitly by wrlock()/unlock()
- const char* pidToName(pid_t pid) {
- return stats.pidToName(pid);
- }
- uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
- const char* uidToName(uid_t uid) {
- return stats.uidToName(uid);
- }
- void wrlock() {
- pthread_rwlock_wrlock(&mLogElementsLock);
- }
- void rdlock() {
- pthread_rwlock_rdlock(&mLogElementsLock);
- }
- void unlock() {
- pthread_rwlock_unlock(&mLogElementsLock);
- }
-
- private:
- static constexpr size_t minPrune = 4;
- static constexpr size_t maxPrune = 256;
-
- void maybePrune(log_id_t id);
- void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows);
-
- bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
- LogBufferElementCollection::iterator erase(
- LogBufferElementCollection::iterator it, bool coalesce = false);
-
- // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if
- // there are no logs for the given log type. Requires mLogElementsLock to be held.
- LogBufferElementCollection::iterator GetOldest(log_id_t log_id);
-
- LogTags* tags_;
- PruneList* prune_;
-
- // Keeps track of the iterator to the oldest log message of a given log type, as an
- // optimization when pruning logs. Use GetOldest() to retrieve.
- std::optional<LogBufferElementCollection::iterator> oldest_[LOG_ID_MAX];
-};
+ virtual bool Clear(log_id_t id, uid_t uid) = 0;
+ virtual unsigned long GetSize(log_id_t id) = 0;
+ virtual int SetSize(log_id_t id, unsigned long size) = 0;
+};
\ No newline at end of file
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 916ed42..32f641b 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogBufferElement.h"
+
#include <ctype.h>
#include <endian.h>
#include <fcntl.h>
@@ -25,10 +27,9 @@
#include <log/log_read.h>
#include <private/android_logger.h>
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
#include "LogCommand.h"
#include "LogReader.h"
+#include "LogStatistics.h"
#include "LogUtils.h"
const uint64_t LogBufferElement::FLUSH_ERROR(0);
@@ -153,7 +154,7 @@
}
// assumption: mMsg == NULL
-size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent,
+size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogStatistics* stats,
bool lastSame) {
static const char tag[] = "chatty";
@@ -163,17 +164,13 @@
}
static const char format_uid[] = "uid=%u%s%s %s %u line%s";
- parent->wrlock();
- const char* name = parent->uidToName(mUid);
- parent->unlock();
+ const char* name = stats->UidToName(mUid);
const char* commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
commName = android::tidToName(mPid);
}
if (!commName) {
- parent->wrlock();
- commName = parent->pidToName(mPid);
- parent->unlock();
+ commName = stats->PidToName(mPid);
}
if (name && name[0] && commName && (name[0] == commName[0])) {
size_t len = strlen(name + 1);
@@ -246,7 +243,7 @@
return retval;
}
-uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool lastSame) {
+uint64_t LogBufferElement::flushTo(SocketClient* reader, LogStatistics* stats, bool lastSame) {
struct logger_entry entry = {};
entry.hdr_size = sizeof(struct logger_entry);
@@ -264,7 +261,7 @@
char* buffer = nullptr;
if (mDropped) {
- entry.len = populateDroppedMessage(buffer, parent, lastSame);
+ entry.len = populateDroppedMessage(buffer, stats, lastSame);
if (!entry.len) return mSequence;
iovec[1].iov_base = buffer;
} else {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 434b7db..3d0b65e 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -24,7 +24,7 @@
#include <log/log.h>
#include <sysutils/SocketClient.h>
-class LogBuffer;
+class LogStatistics;
#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
// non-chatty UIDs less than this age in hours
@@ -33,8 +33,6 @@
#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
class __attribute__((packed)) LogBufferElement {
- friend LogBuffer;
-
// sized to match reality of incoming log packets
const uint32_t mUid;
const uint32_t mPid;
@@ -55,10 +53,9 @@
static atomic_int_fast64_t sequence;
// assumption: mDropped == true
- size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
- bool lastSame);
+ size_t populateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame);
- public:
+ public:
LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
pid_t tid, const char* msg, uint16_t len);
LogBufferElement(const LogBufferElement& elem);
@@ -98,5 +95,5 @@
}
static const uint64_t FLUSH_ERROR;
- uint64_t flushTo(SocketClient* writer, LogBuffer* parent, bool lastSame);
+ uint64_t flushTo(SocketClient* writer, LogStatistics* parent, bool lastSame);
};
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 5788ada..1ea87a9 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogKlog.h"
+
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
@@ -29,8 +31,6 @@
#include <private/android_logger.h>
#include "LogBuffer.h"
-#include "LogKlog.h"
-#include "LogReader.h"
#define KMSG_PRIORITY(PRI) \
'<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
@@ -201,15 +201,14 @@
? log_time(log_time::EPOCH)
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
-LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
- bool auditd)
+LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
: SocketListener(fdRead, false),
logbuf(buf),
- reader(reader),
signature(CLOCK_MONOTONIC),
initialized(false),
enableLogging(true),
- auditd(auditd) {
+ auditd(auditd),
+ stats_(stats) {
static const char klogd_message[] = "%s%s%" PRIu64 "\n";
char buffer[strlen(priority_message) + strlen(klogdStr) +
strlen(klogd_message) + 20];
@@ -309,8 +308,6 @@
}
buf = cp;
- if (isMonotonic()) return now;
-
const char* b;
if (((b = android::strnstr(cp, len, suspendStr))) &&
(((b += strlen(suspendStr)) - cp) < len)) {
@@ -356,11 +353,7 @@
convertMonotonicToReal(now);
} else {
- if (isMonotonic()) {
- now = log_time(CLOCK_MONOTONIC);
- } else {
- now = log_time(CLOCK_REALTIME);
- }
+ now = log_time(CLOCK_REALTIME);
}
return now;
}
@@ -431,45 +424,6 @@
return pri;
}
-// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
-// compensated start time.
-void LogKlog::synchronize(const char* buf, ssize_t len) {
- const char* cp = android::strnstr(buf, len, suspendStr);
- if (!cp) {
- cp = android::strnstr(buf, len, resumeStr);
- if (!cp) return;
- } else {
- const char* rp = android::strnstr(buf, len, resumeStr);
- if (rp && (rp < cp)) cp = rp;
- }
-
- do {
- --cp;
- } while ((cp > buf) && (*cp != '\n'));
- if (*cp == '\n') {
- ++cp;
- }
- parseKernelPrio(cp, len - (cp - buf));
-
- log_time now = sniffTime(cp, len - (cp - buf), true);
-
- const char* suspended = android::strnstr(buf, len, suspendedStr);
- if (!suspended || (suspended > cp)) {
- return;
- }
- cp = suspended;
-
- do {
- --cp;
- } while ((cp > buf) && (*cp != '\n'));
- if (*cp == '\n') {
- ++cp;
- }
- parseKernelPrio(cp, len - (cp - buf));
-
- sniffTime(cp, len - (cp - buf), true);
-}
-
// Convert kernel log priority number into an Android Logger priority number
static int convertKernelPrioToAndroidPrio(int pri) {
switch (pri & LOG_PRIMASK) {
@@ -573,9 +527,7 @@
const pid_t tid = pid;
uid_t uid = AID_ROOT;
if (pid) {
- logbuf->wrlock();
- uid = logbuf->pidToUid(pid);
- logbuf->unlock();
+ uid = stats_->PidToUid(pid);
}
// Parse (rules at top) to pull out a tag from the incoming kernel message.
@@ -789,7 +741,7 @@
memcpy(np, p, b);
np[b] = '\0';
- if (!isMonotonic()) {
+ {
// 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
@@ -815,12 +767,7 @@
}
// Log message
- int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
-
- // notify readers
- if (rc > 0) {
- reader->notifyNewLog(static_cast<unsigned int>(1 << LOG_ID_KERNEL));
- }
+ int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
return rc;
}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 6bfd6a8..77b24bc 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-#ifndef _LOGD_LOG_KLOG_H__
-#define _LOGD_LOG_KLOG_H__
+#pragma once
#include <private/android_logger.h>
#include <sysutils/SocketListener.h>
+#include "LogStatistics.h"
+
class LogBuffer;
-class LogReader;
class LogKlog : public SocketListener {
LogBuffer* logbuf;
- LogReader* reader;
const log_time signature;
// Set once thread is started, separates KLOG_ACTION_READ_ALL
// and KLOG_ACTION_READ phases.
@@ -38,27 +37,18 @@
static log_time correction;
- public:
- LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
- bool auditd);
+ public:
+ LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats);
int log(const char* buf, ssize_t len);
- void synchronize(const char* buf, ssize_t len);
- bool isMonotonic() {
- return logbuf->isMonotonic();
- }
- static void convertMonotonicToReal(log_time& real) {
- real += correction;
- }
- static void convertRealToMonotonic(log_time& real) {
- real -= correction;
- }
+ static void convertMonotonicToReal(log_time& real) { real += correction; }
- protected:
- log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
- pid_t sniffPid(const char*& buf, ssize_t len);
- void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
- virtual bool onDataAvailable(SocketClient* cli);
+ protected:
+ log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
+ pid_t sniffPid(const char*& buf, ssize_t len);
+ void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
+ virtual bool onDataAvailable(SocketClient* cli);
+
+ private:
+ LogStatistics* stats_;
};
-
-#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 138ab28..d2e2efa 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -22,6 +22,8 @@
#include <sys/un.h>
#include <unistd.h>
+#include <thread>
+
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -30,34 +32,43 @@
#include "LogListener.h"
#include "LogUtils.h"
-LogListener::LogListener(LogBuffer* buf, LogReader* reader)
- : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}
+LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
-bool LogListener::onDataAvailable(SocketClient* cli) {
- static bool name_set;
- if (!name_set) {
- prctl(PR_SET_NAME, "logd.writer");
- name_set = true;
+bool LogListener::StartListener() {
+ if (socket_ <= 0) {
+ return false;
}
+ auto thread = std::thread(&LogListener::ThreadFunction, this);
+ thread.detach();
+ return true;
+}
+void LogListener::ThreadFunction() {
+ prctl(PR_SET_NAME, "logd.writer");
+
+ while (true) {
+ HandleData();
+ }
+}
+
+void LogListener::HandleData() {
// + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
- char buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
- struct iovec iov = { buffer, sizeof(buffer) - 1 };
+ __attribute__((uninitialized)) char
+ buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
+ struct iovec iov = {buffer, sizeof(buffer) - 1};
alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
nullptr, 0, &iov, 1, control, sizeof(control), 0,
};
- int socket = cli->getSocket();
-
// To clear the entire buffer is secure/safe, but this contributes to 1.68%
// overhead under logging load. We are safe because we check counts, but
// still need to clear null terminator
// memset(buffer, 0, sizeof(buffer));
- ssize_t n = recvmsg(socket, &hdr, 0);
+ ssize_t n = recvmsg(socket_, &hdr, 0);
if (n <= (ssize_t)(sizeof(android_log_header_t))) {
- return false;
+ return;
}
buffer[n] = 0;
@@ -75,14 +86,14 @@
}
if (cred == nullptr) {
- return false;
+ return;
}
if (cred->uid == AID_LOGD) {
// ignore log messages we send to ourself.
// Such log messages are often generated by libraries we depend on
// which use standard Android logging.
- return false;
+ return;
}
android_log_header_t* header =
@@ -90,13 +101,13 @@
log_id_t logId = static_cast<log_id_t>(header->id);
if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
logId == LOG_ID_KERNEL) {
- return false;
+ return;
}
if ((logId == LOG_ID_SECURITY) &&
(!__android_log_security() ||
!clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
- return false;
+ return;
}
char* msg = ((char*)buffer) + sizeof(android_log_header_t);
@@ -105,16 +116,11 @@
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
- int res = logbuf->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
- ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
- if (res > 0) {
- reader->notifyNewLog(static_cast<unsigned int>(1 << logId));
- }
-
- return true;
+ logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
+ ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
}
-int LogListener::getLogSocket() {
+int LogListener::GetLogSocket() {
static const char socketName[] = "logdw";
int sock = android_get_control_socket(socketName);
diff --git a/logd/LogListener.h b/logd/LogListener.h
index 8fe3da4..d468df8 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -14,24 +14,21 @@
* limitations under the License.
*/
-#ifndef _LOGD_LOG_LISTENER_H__
-#define _LOGD_LOG_LISTENER_H__
+#pragma once
-#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
#include "LogReader.h"
-class LogListener : public SocketListener {
- LogBuffer* logbuf;
- LogReader* reader;
+class LogListener {
+ public:
+ LogListener(LogBuffer* buf);
+ bool StartListener();
- public:
- LogListener(LogBuffer* buf, LogReader* reader);
+ private:
+ void ThreadFunction();
+ void HandleData();
+ static int GetLogSocket();
- protected:
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- static int getLogSocket();
+ int socket_;
+ LogBuffer* logbuf_;
};
-
-#endif
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 4702de5..6f91372 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,7 +21,10 @@
#include <sys/socket.h>
#include <sys/types.h>
+#include <chrono>
+
#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "LogBuffer.h"
@@ -33,27 +36,8 @@
return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
}
-LogReader::LogReader(LogBuffer* logbuf)
- : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
-}
-
-// When we are notified a new log entry is available, inform
-// listening sockets who are watching this entry's log id.
-void LogReader::notifyNewLog(unsigned int log_mask) {
- LastLogTimes& times = mLogbuf.mTimes;
-
- LogReaderThread::wrlock();
- for (const auto& entry : times) {
- if (!entry->IsWatchingMultiple(log_mask)) {
- continue;
- }
- if (entry->timeout().tv_sec || entry->timeout().tv_nsec) {
- continue;
- }
- entry->triggerReader_Locked();
- }
- LogReaderThread::unlock();
-}
+LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
+ : SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
// Note returning false will release the SocketClient instance.
bool LogReader::onDataAvailable(SocketClient* cli) {
@@ -74,15 +58,15 @@
// Clients are only allowed to send one command, disconnect them if they
// send another.
- LogReaderThread::wrlock();
- for (const auto& entry : mLogbuf.mTimes) {
- if (entry->client() == cli) {
- entry->release_Locked();
- LogReaderThread::unlock();
- return false;
+ {
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& entry : reader_list_->reader_threads()) {
+ if (entry->client() == cli) {
+ entry->release_Locked();
+ return false;
+ }
}
}
- LogReaderThread::unlock();
unsigned long tail = 0;
static const char _tail[] = " tail=";
@@ -99,11 +83,12 @@
start.strptime(cp + sizeof(_start) - 1, "%s.%q");
}
- uint64_t timeout = 0;
+ std::chrono::steady_clock::time_point deadline = {};
static const char _timeout[] = " timeout=";
cp = strstr(buffer, _timeout);
if (cp) {
- timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + log_time(CLOCK_MONOTONIC).nsec();
+ long timeout_seconds = atol(cp + sizeof(_timeout) - 1);
+ deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
}
unsigned int logMask = -1;
@@ -137,8 +122,8 @@
if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
// Allow writer to get some cycles, and wait for pending notifications
sched_yield();
- LogReaderThread::wrlock();
- LogReaderThread::unlock();
+ reader_list_->reader_threads_lock().lock();
+ reader_list_->reader_threads_lock().unlock();
sched_yield();
nonBlock = true;
}
@@ -150,34 +135,31 @@
// Convert realtime to sequence number
if (start != log_time::EPOCH) {
bool start_time_set = false;
- bool is_monotonic = logbuf().isMonotonic() && android::isMonotonic(start);
uint64_t last = sequence;
- auto log_find_start = [pid, logMask, start, is_monotonic, &sequence, &start_time_set,
- &last](const LogBufferElement* element) -> int {
+ auto log_find_start = [pid, logMask, start, &sequence, &start_time_set,
+ &last](const LogBufferElement* element) -> FlushToResult {
if (pid && pid != element->getPid()) {
- return 0;
+ return FlushToResult::kSkip;
}
if ((logMask & (1 << element->getLogId())) == 0) {
- return 0;
+ return FlushToResult::kSkip;
}
if (start == element->getRealTime()) {
sequence = element->getSequence();
start_time_set = true;
- return -1;
- } else if (!is_monotonic || android::isMonotonic(element->getRealTime())) {
+ return FlushToResult::kStop;
+ } else {
if (start < element->getRealTime()) {
sequence = last;
start_time_set = true;
- return -1;
+ return FlushToResult::kStop;
}
last = element->getSequence();
- } else {
- last = element->getSequence();
}
- return 0;
+ return FlushToResult::kSkip;
};
- logbuf().flushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start);
+ log_buffer_->FlushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start);
if (!start_time_set) {
if (nonBlock) {
@@ -190,42 +172,38 @@
android::prdebug(
"logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
- "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
+ "start=%" PRIu64 "ns deadline=%" PRIi64 "ns\n",
cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask,
- (int)pid, start.nsec(), timeout);
+ (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count()));
if (start == log_time::EPOCH) {
- timeout = 0;
+ deadline = {};
}
- LogReaderThread::wrlock();
- auto entry =
- std::make_unique<LogReaderThread>(*this, cli, nonBlock, tail, logMask, pid, start,
- sequence, timeout, privileged, can_read_security);
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ auto entry = std::make_unique<LogReaderThread>(*this, *reader_list_, cli, nonBlock, tail,
+ logMask, pid, start, sequence, deadline,
+ privileged, can_read_security);
if (!entry->startReader_Locked()) {
- LogReaderThread::unlock();
return false;
}
// release client and entry reference counts once done
cli->incRef();
- mLogbuf.mTimes.emplace_front(std::move(entry));
+ reader_list_->reader_threads().emplace_front(std::move(entry));
// Set acceptable upper limit to wait for slow reader processing b/27242723
struct timeval t = { LOGD_SNDTIMEO, 0 };
setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
sizeof(t));
- LogReaderThread::unlock();
-
return true;
}
void LogReader::doSocketDelete(SocketClient* cli) {
- LastLogTimes& times = mLogbuf.mTimes;
- LogReaderThread::wrlock();
- LastLogTimes::iterator it = times.begin();
- while (it != times.end()) {
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ auto it = reader_list_->reader_threads().begin();
+ while (it != reader_list_->reader_threads().end()) {
LogReaderThread* entry = it->get();
if (entry->client() == cli) {
entry->release_Locked();
@@ -233,7 +211,6 @@
}
it++;
}
- LogReaderThread::unlock();
}
int LogReader::getLogSocket() {
diff --git a/logd/LogReader.h b/logd/LogReader.h
index f00cc21..7df3f6b 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -18,6 +18,7 @@
#include <sysutils/SocketListener.h>
+#include "LogReaderList.h"
#include "LogReaderThread.h"
#define LOGD_SNDTIMEO 32
@@ -25,21 +26,19 @@
class LogBuffer;
class LogReader : public SocketListener {
- LogBuffer& mLogbuf;
+ public:
+ explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
- public:
- explicit LogReader(LogBuffer* logbuf);
- void notifyNewLog(unsigned int logMask);
+ LogBuffer* log_buffer() const { return log_buffer_; }
- LogBuffer& logbuf(void) const {
- return mLogbuf;
- }
-
- protected:
+ protected:
virtual bool onDataAvailable(SocketClient* cli);
- private:
+ private:
static int getLogSocket();
void doSocketDelete(SocketClient* cli);
+
+ LogBuffer* log_buffer_;
+ LogReaderList* reader_list_;
};
diff --git a/logd/LogReaderList.cpp b/logd/LogReaderList.cpp
new file mode 100644
index 0000000..220027b
--- /dev/null
+++ b/logd/LogReaderList.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LogReaderList.h"
+
+// When we are notified a new log entry is available, inform
+// listening sockets who are watching this entry's log id.
+void LogReaderList::NotifyNewLog(unsigned int log_mask) const {
+ auto lock = std::lock_guard{reader_threads_lock_};
+
+ for (const auto& entry : reader_threads_) {
+ if (!entry->IsWatchingMultiple(log_mask)) {
+ continue;
+ }
+ if (entry->deadline().time_since_epoch().count() != 0) {
+ continue;
+ }
+ entry->triggerReader_Locked();
+ }
+}
diff --git a/logd/LogReaderList.h b/logd/LogReaderList.h
new file mode 100644
index 0000000..0d84aba
--- /dev/null
+++ b/logd/LogReaderList.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <list>
+#include <memory>
+#include <mutex>
+
+#include "LogReaderThread.h"
+
+class LogReaderList {
+ public:
+ void NotifyNewLog(unsigned int log_mask) const;
+
+ std::list<std::unique_ptr<LogReaderThread>>& reader_threads() { return reader_threads_; }
+ std::mutex& reader_threads_lock() { return reader_threads_lock_; }
+
+ private:
+ std::list<std::unique_ptr<LogReaderThread>> reader_threads_;
+ mutable std::mutex reader_threads_lock_;
+};
\ No newline at end of file
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
index 5413c4d..e58e3eb 100644
--- a/logd/LogReaderThread.cpp
+++ b/logd/LogReaderThread.cpp
@@ -27,14 +27,14 @@
using namespace std::placeholders;
-pthread_mutex_t LogReaderThread::timesLock = PTHREAD_MUTEX_INITIALIZER;
-
-LogReaderThread::LogReaderThread(LogReader& reader, SocketClient* client, bool non_block,
- unsigned long tail, unsigned int log_mask, pid_t pid,
- log_time start_time, uint64_t start, uint64_t timeout,
+LogReaderThread::LogReaderThread(LogReader& reader, LogReaderList& reader_list,
+ SocketClient* client, bool non_block, unsigned long tail,
+ unsigned int log_mask, pid_t pid, log_time start_time,
+ uint64_t start, std::chrono::steady_clock::time_point deadline,
bool privileged, bool can_read_security_logs)
: leading_dropped_(false),
reader_(reader),
+ reader_list_(reader_list),
log_mask_(log_mask),
pid_(pid),
tail_(tail),
@@ -43,13 +43,11 @@
client_(client),
start_time_(start_time),
start_(start),
+ deadline_(deadline),
non_block_(non_block),
privileged_(privileged),
can_read_security_logs_(can_read_security_logs) {
- timeout_.tv_sec = timeout / NS_PER_SEC;
- timeout_.tv_nsec = timeout % NS_PER_SEC;
memset(last_tid_, 0, sizeof(last_tid_));
- pthread_cond_init(&thread_triggered_condition_, nullptr);
cleanSkip_Locked();
}
@@ -64,36 +62,35 @@
SocketClient* client = client_;
- LogBuffer& logbuf = reader_.logbuf();
+ LogBuffer& logbuf = *reader_.log_buffer();
leading_dropped_ = true;
- wrlock();
+ auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
uint64_t start = start_;
while (!release_) {
- if (timeout_.tv_sec || timeout_.tv_nsec) {
- if (pthread_cond_clockwait(&thread_triggered_condition_, ×Lock, CLOCK_MONOTONIC,
- &timeout_) == ETIMEDOUT) {
- timeout_.tv_sec = 0;
- timeout_.tv_nsec = 0;
+ if (deadline_.time_since_epoch().count() != 0) {
+ if (thread_triggered_condition_.wait_until(lock, deadline_) ==
+ std::cv_status::timeout) {
+ deadline_ = {};
}
if (release_) {
break;
}
}
- unlock();
+ lock.unlock();
if (tail_) {
- logbuf.flushTo(client, start, nullptr, privileged_, can_read_security_logs_,
+ logbuf.FlushTo(client, start, nullptr, privileged_, can_read_security_logs_,
std::bind(&LogReaderThread::FilterFirstPass, this, _1));
leading_dropped_ =
true; // TODO: Likely a bug, if leading_dropped_ was not true before calling
// flushTo(), then it should not be reset to true after.
}
- start = logbuf.flushTo(client, start, last_tid_, privileged_, can_read_security_logs_,
+ start = logbuf.FlushTo(client, start, last_tid_, privileged_, can_read_security_logs_,
std::bind(&LogReaderThread::FilterSecondPass, this, _1));
// We only ignore entries before the original start time for the first flushTo(), if we
@@ -105,7 +102,7 @@
start_time_.tv_sec = 0;
start_time_.tv_nsec = 0;
- wrlock();
+ lock.lock();
if (start == LogBufferElement::FLUSH_ERROR) {
break;
@@ -119,35 +116,30 @@
cleanSkip_Locked();
- if (!timeout_.tv_sec && !timeout_.tv_nsec) {
- pthread_cond_wait(&thread_triggered_condition_, ×Lock);
+ if (deadline_.time_since_epoch().count() == 0) {
+ thread_triggered_condition_.wait(lock);
}
}
- LogReader& reader = reader_;
- reader.release(client);
-
+ reader_.release(client);
client->decRef();
- LastLogTimes& times = reader.logbuf().mTimes;
- auto it = std::find_if(times.begin(), times.end(),
+ auto& log_reader_threads = reader_list_.reader_threads();
+ auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
[this](const auto& other) { return other.get() == this; });
- if (it != times.end()) {
- times.erase(it);
+ if (it != log_reader_threads.end()) {
+ log_reader_threads.erase(it);
}
-
- unlock();
}
// A first pass to count the number of elements
-int LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
- LogReaderThread::wrlock();
+FlushToResult LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
+ auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
if (leading_dropped_) {
if (element->getDropped()) {
- LogReaderThread::unlock();
- return false;
+ return FlushToResult::kSkip;
}
leading_dropped_ = false;
}
@@ -161,48 +153,46 @@
++count_;
}
- LogReaderThread::unlock();
-
- return false;
+ return FlushToResult::kSkip;
}
// A second pass to send the selected elements
-int LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
- LogReaderThread::wrlock();
+FlushToResult LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
+ auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
start_ = element->getSequence();
if (skip_ahead_[element->getLogId()]) {
skip_ahead_[element->getLogId()]--;
- goto skip;
+ return FlushToResult::kSkip;
}
if (leading_dropped_) {
if (element->getDropped()) {
- goto skip;
+ return FlushToResult::kSkip;
}
leading_dropped_ = false;
}
// Truncate to close race between first and second pass
if (non_block_ && tail_ && index_ >= count_) {
- goto stop;
+ return FlushToResult::kStop;
}
if (!IsWatching(element->getLogId())) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (pid_ && pid_ != element->getPid()) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (start_time_ != log_time::EPOCH && element->getRealTime() <= start_time_) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (release_) {
- goto stop;
+ return FlushToResult::kStop;
}
if (!tail_) {
@@ -212,7 +202,7 @@
++index_;
if (count_ > tail_ && index_ <= (count_ - tail_)) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (!non_block_) {
@@ -221,18 +211,9 @@
ok:
if (!skip_ahead_[element->getLogId()]) {
- LogReaderThread::unlock();
- return true;
+ return FlushToResult::kWrite;
}
- // FALLTHRU
-
-skip:
- LogReaderThread::unlock();
- return false;
-
-stop:
- LogReaderThread::unlock();
- return -1;
+ return FlushToResult::kSkip;
}
void LogReaderThread::cleanSkip_Locked(void) {
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
index 39a8b63..f828b6e 100644
--- a/logd/LogReaderThread.h
+++ b/logd/LogReaderThread.h
@@ -21,31 +21,31 @@
#include <sys/types.h>
#include <time.h>
+#include <chrono>
+#include <condition_variable>
#include <list>
#include <memory>
#include <log/log.h>
#include <sysutils/SocketClient.h>
+#include "LogBuffer.h"
+
class LogReader;
class LogBufferElement;
+class LogReaderList;
class LogReaderThread {
- static pthread_mutex_t timesLock;
-
public:
- LogReaderThread(LogReader& reader, SocketClient* client, bool non_block, unsigned long tail,
- unsigned int log_mask, pid_t pid, log_time start_time, uint64_t sequence,
- uint64_t timeout, bool privileged, bool can_read_security_logs);
-
- // Protect List manipulations
- static void wrlock() { pthread_mutex_lock(×Lock); }
- static void rdlock() { pthread_mutex_lock(×Lock); }
- static void unlock() { pthread_mutex_unlock(×Lock); }
+ LogReaderThread(LogReader& reader, LogReaderList& reader_list, SocketClient* client,
+ bool non_block, unsigned long tail, unsigned int log_mask, pid_t pid,
+ log_time start_time, uint64_t sequence,
+ std::chrono::steady_clock::time_point deadline, bool privileged,
+ bool can_read_security_logs);
bool startReader_Locked();
- void triggerReader_Locked() { pthread_cond_signal(&thread_triggered_condition_); }
+ void triggerReader_Locked() { thread_triggered_condition_.notify_all(); }
void triggerSkip_Locked(log_id_t id, unsigned int skip) { skip_ahead_[id] = skip; }
void cleanSkip_Locked();
@@ -54,7 +54,7 @@
// gracefully shut down the socket.
shutdown(client_->getSocket(), SHUT_RDWR);
release_ = true;
- pthread_cond_signal(&thread_triggered_condition_);
+ thread_triggered_condition_.notify_all();
}
bool IsWatching(log_id_t id) const { return log_mask_ & (1 << id); }
@@ -62,13 +62,13 @@
const SocketClient* client() const { return client_; }
uint64_t start() const { return start_; }
- const timespec& timeout() const { return timeout_; }
+ std::chrono::steady_clock::time_point deadline() const { return deadline_; }
private:
void ThreadFunction();
// flushTo filter callbacks
- int FilterFirstPass(const LogBufferElement* element);
- int FilterSecondPass(const LogBufferElement* element);
+ FlushToResult FilterFirstPass(const LogBufferElement* element);
+ FlushToResult FilterSecondPass(const LogBufferElement* element);
// Set to true to cause the thread to end and the LogReaderThread to delete itself.
bool release_ = false;
@@ -77,10 +77,12 @@
bool leading_dropped_;
// Condition variable for waking the reader thread if there are messages pending for its client.
- pthread_cond_t thread_triggered_condition_;
+ std::condition_variable thread_triggered_condition_;
// Reference to the parent thread that manages log reader sockets.
LogReader& reader_;
+ // Reference to the parent list that shares its lock with each instance
+ LogReaderList& reader_list_;
// A mask of the logs buffers that are read by this reader.
const unsigned int log_mask_;
// If set to non-zero, only pids equal to this are read by the reader.
@@ -110,9 +112,9 @@
log_time start_time_;
// The point from which the reader will read logs once awoken.
uint64_t start_;
- // CLOCK_MONOTONIC based timeout used for log wrapping. If this timeout expires before logs
+ // CLOCK_MONOTONIC based deadline used for log wrapping. If this deadline expires before logs
// wrap, then wake up and send the logs to the reader anyway.
- timespec timeout_;
+ std::chrono::steady_clock::time_point deadline_;
// If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
const bool non_block_;
@@ -122,5 +124,3 @@
// Whether or not this reader can read security logs. See CanReadSecurityLogs().
bool can_read_security_logs_;
};
-
-typedef std::list<std::unique_ptr<LogReaderThread>> LastLogTimes;
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 431b778..14bcb63 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogStatistics.h"
+
#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -27,14 +29,12 @@
#include <private/android_logger.h>
-#include "LogStatistics.h"
-
static const uint64_t hourSec = 60 * 60;
static const uint64_t monthSec = 31 * 24 * hourSec;
-size_t LogStatistics::SizesTotal;
+std::atomic<size_t> LogStatistics::SizesTotal;
-LogStatistics::LogStatistics() : enable(false) {
+LogStatistics::LogStatistics(bool enable_statistics) : enable(enable_statistics) {
log_time now(CLOCK_REALTIME);
log_id_for_each(id) {
mSizes[id] = 0;
@@ -79,7 +79,8 @@
}
}
-void LogStatistics::addTotal(LogBufferElement* element) {
+void LogStatistics::AddTotal(LogBufferElement* element) {
+ auto lock = std::lock_guard{lock_};
if (element->getDropped()) return;
log_id_t log_id = element->getLogId();
@@ -89,7 +90,8 @@
++mElementsTotal[log_id];
}
-void LogStatistics::add(LogBufferElement* element) {
+void LogStatistics::Add(LogBufferElement* element) {
+ auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] += size;
@@ -159,7 +161,8 @@
}
}
-void LogStatistics::subtract(LogBufferElement* element) {
+void LogStatistics::Subtract(LogBufferElement* element) {
+ auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] -= size;
@@ -204,7 +207,8 @@
// Atomically set an entry to drop
// entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::drop(LogBufferElement* element) {
+void LogStatistics::Drop(LogBufferElement* element) {
+ auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] -= size;
@@ -238,9 +242,13 @@
tagNameTable.subtract(TagNameKey(element), element);
}
+const char* LogStatistics::UidToName(uid_t uid) const {
+ auto lock = std::lock_guard{lock_};
+ return UidToNameLocked(uid);
+}
+
// caller must own and free character string
-// Requires parent LogBuffer::wrlock() to be held
-const char* LogStatistics::uidToName(uid_t uid) const {
+const char* LogStatistics::UidToNameLocked(uid_t uid) const {
// Local hard coded favourites
if (uid == AID_LOGD) {
return strdup("auditd");
@@ -297,6 +305,80 @@
return name;
}
+template <typename TKey, typename TEntry>
+void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+ int* worst, size_t* worst_sizes,
+ size_t* second_worst_sizes) const {
+ std::array<const TEntry*, 2> max_entries;
+ table.MaxEntries(AID_ROOT, 0, &max_entries);
+ if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+ return;
+ }
+ *worst_sizes = max_entries[0]->getSizes();
+ // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
+ // 100 characters.
+ if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->getDropped())) {
+ *worst = max_entries[0]->getKey();
+ *second_worst_sizes = max_entries[1]->getSizes();
+ if (*second_worst_sizes < threshold) {
+ *second_worst_sizes = threshold;
+ }
+ }
+}
+
+void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+ size_t* second_worst_sizes) const {
+ auto lock = std::lock_guard{lock_};
+ WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+ size_t* second_worst_sizes) const {
+ auto lock = std::lock_guard{lock_};
+ WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+ size_t* second_worst_sizes) const {
+ auto lock = std::lock_guard{lock_};
+ std::array<const PidEntry*, 2> max_entries;
+ pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
+ if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+ return;
+ }
+
+ *worst = max_entries[0]->getKey();
+ *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
+}
+
+// Prune at most 10% of the log entries or maxPrune, whichever is less.
+bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
+ unsigned long* prune_rows) const {
+ static constexpr size_t kMinPrune = 4;
+ static constexpr size_t kMaxPrune = 256;
+
+ auto lock = std::lock_guard{lock_};
+ size_t sizes = mSizes[id];
+ if (sizes <= max_size) {
+ return false;
+ }
+ size_t size_over = sizes - ((max_size * 9) / 10);
+ size_t elements = mElements[id] - mDroppedElements[id];
+ size_t min_elements = elements / 100;
+ if (min_elements < kMinPrune) {
+ min_elements = kMinPrune;
+ }
+ *prune_rows = elements * size_over / sizes;
+ if (*prune_rows < min_elements) {
+ *prune_rows = min_elements;
+ }
+ if (*prune_rows > kMaxPrune) {
+ *prune_rows = kMaxPrune;
+ }
+
+ return true;
+}
+
std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
bool isprune = worstUidEnabledForLogid(id);
return formatLine(android::base::StringPrintf(name.c_str(),
@@ -308,10 +390,10 @@
}
// Helper to truncate name, if too long, and add name dressings
-static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
- std::string& name, std::string& size, size_t nameLen) {
+void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
+ size_t nameLen) const {
const char* allocNameTmp = nullptr;
- if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
+ if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
if (nameTmp) {
size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
size_t len = EntryBaseConstants::total_len -
@@ -332,12 +414,12 @@
}
}
-std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
+std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const REQUIRES(stat.lock_) {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%u", uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, nullptr, uid, name, size, 6);
+ stat.FormatTmp(nullptr, uid, name, size, 6);
std::string pruned = "";
if (worstUidEnabledForLogid(id)) {
@@ -347,9 +429,9 @@
it != stat.uidTable[id].end(); ++it) {
totalDropped += it->second.getDropped();
}
- size_t sizes = stat.sizes(id);
- size_t totalSize = stat.sizesTotal(id);
- size_t totalElements = stat.elementsTotal(id);
+ size_t sizes = stat.mSizes[id];
+ size_t totalSize = stat.mSizesTotal[id];
+ size_t totalElements = stat.mElementsTotal[id];
float totalVirtualSize =
(float)sizes + (float)totalDropped * totalSize / totalElements;
size_t entrySize = getSizes();
@@ -401,12 +483,9 @@
}
static const size_t maximum_sorted_entries = 32;
- std::unique_ptr<const PidEntry* []> sorted =
- stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
+ std::array<const PidEntry*, maximum_sorted_entries> sorted;
+ stat.pidSystemTable[id].MaxEntries(uid, 0, &sorted);
- if (!sorted.get()) {
- return output;
- }
std::string byPid;
size_t index;
bool hasDropped = false;
@@ -440,14 +519,14 @@
std::string("BYTES"), std::string("NUM"));
}
-std::string PidEntry::format(const LogStatistics& stat,
- log_id_t /* id */) const {
+std::string PidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
+ REQUIRES(stat.lock_) {
uid_t uid = getUid();
pid_t pid = getPid();
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, getName(), uid, name, size, 12);
+ stat.FormatTmp(getName(), uid, name, size, 12);
std::string pruned = "";
size_t dropped = getDropped();
@@ -465,13 +544,13 @@
std::string("NUM"));
}
-std::string TidEntry::format(const LogStatistics& stat,
- log_id_t /* id */) const {
+std::string TidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
+ REQUIRES(stat.lock_) {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, getName(), uid, name, size, 12);
+ stat.FormatTmp(getName(), uid, name, size, 12);
std::string pruned = "";
size_t dropped = getDropped();
@@ -611,8 +690,36 @@
return output;
}
-std::string LogStatistics::format(uid_t uid, pid_t pid,
- unsigned int logMask) const {
+template <typename TKey, typename TEntry>
+std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
+ pid_t pid, const std::string& name, log_id_t id) const
+ REQUIRES(lock_) {
+ static const size_t maximum_sorted_entries = 32;
+ std::string output;
+ std::array<const TEntry*, maximum_sorted_entries> sorted;
+ table.MaxEntries(uid, pid, &sorted);
+ bool header_printed = false;
+ for (size_t index = 0; index < maximum_sorted_entries; ++index) {
+ const TEntry* entry = sorted[index];
+ if (!entry) {
+ break;
+ }
+ if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
+ break;
+ }
+ if (!header_printed) {
+ output += "\n\n";
+ output += entry->formatHeader(name, id);
+ header_printed = true;
+ }
+ output += entry->format(*this, id);
+ }
+ return output;
+}
+
+std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
+ auto lock = std::lock_guard{lock_};
+
static const uint16_t spaces_total = 19;
// Report on total logging, current and for all time
@@ -642,9 +749,9 @@
if (!(logMask & (1 << id))) continue;
oldLength = output.length();
if (spaces < 0) spaces = 0;
- size_t szs = sizesTotal(id);
+ size_t szs = mSizesTotal[id];
totalSize += szs;
- size_t els = elementsTotal(id);
+ size_t els = mElementsTotal[id];
totalEls += els;
output +=
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
@@ -663,11 +770,11 @@
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
- size_t els = elements(id);
+ size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
- size_t szs = sizes(id);
+ size_t szs = mSizes[id];
totalSize += szs;
totalEls += els;
output +=
@@ -749,7 +856,7 @@
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
- size_t els = elements(id);
+ size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
@@ -758,7 +865,7 @@
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
-sizeof(uint64_t)) +
sizeof(std::list<LogBufferElement*>);
- size_t szs = sizes(id) + els * overhead;
+ size_t szs = mSizes[id] + els * overhead;
totalSize += szs;
output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
spaces -= output.length() - oldLength;
@@ -779,39 +886,38 @@
name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
: "Logging for your UID in %s log buffer:";
- output += uidTable[id].format(*this, uid, pid, name, id);
+ output += FormatTable(uidTable[id], uid, pid, name, id);
}
if (enable) {
name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
: "Logging for this PID:";
- output += pidTable.format(*this, uid, pid, name);
+ output += FormatTable(pidTable, uid, pid, name);
name = "Chattiest TIDs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tidTable.format(*this, uid, pid, name);
+ output += FormatTable(tidTable, uid, pid, name);
}
if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
name = "Chattiest events log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
+ output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
}
if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
name = "Chattiest security log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output +=
- securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
+ output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
}
if (enable) {
name = "Chattiest TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tagNameTable.format(*this, uid, pid, name);
+ output += FormatTable(tagNameTable, uid, pid, name);
}
return output;
@@ -839,12 +945,14 @@
}
}
-uid_t LogStatistics::pidToUid(pid_t pid) {
+uid_t LogStatistics::PidToUid(pid_t pid) {
+ auto lock = std::lock_guard{lock_};
return pidTable.add(pid)->second.getUid();
}
// caller must free character string
-const char* LogStatistics::pidToName(pid_t pid) const {
+const char* LogStatistics::PidToName(pid_t pid) const {
+ auto lock = std::lock_guard{lock_};
// An inconvenient truth ... getName() can alter the object
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
const char* name = writablePidTable.add(pid)->second.getName();
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 0782de3..53c9bb6 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LOGD_LOG_STATISTICS_H__
-#define _LOGD_LOG_STATISTICS_H__
+#pragma once
#include <ctype.h>
#include <inttypes.h>
@@ -25,12 +24,15 @@
#include <sys/types.h>
#include <algorithm> // std::max
+#include <array>
#include <memory>
+#include <mutex>
#include <string>
#include <string_view>
#include <unordered_map>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include <android/log.h>
#include <log/log_time.h>
#include <private/android_filesystem_config.h>
@@ -79,16 +81,12 @@
typedef
typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
- std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
- size_t len) const {
- if (!len) {
- std::unique_ptr<const TEntry* []> sorted(nullptr);
- return sorted;
- }
-
- const TEntry** retval = new const TEntry*[len];
- memset(retval, 0, sizeof(*retval) * len);
-
+ // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
+ // entries are found, their positions are set to nullptr.
+ template <size_t len>
+ void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
+ auto& retval = *out;
+ retval.fill(nullptr);
for (const_iterator it = map.begin(); it != map.end(); ++it) {
const TEntry& entry = it->second;
@@ -113,8 +111,6 @@
retval[index] = &entry;
}
}
- std::unique_ptr<const TEntry* []> sorted(retval);
- return sorted;
}
inline iterator add(const TKey& key, const LogBufferElement* element) {
@@ -170,35 +166,6 @@
inline const_iterator end() const {
return map.end();
}
-
- std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
- const std::string& name = std::string(""),
- log_id_t id = LOG_ID_MAX) const {
- static const size_t maximum_sorted_entries = 32;
- std::string output;
- std::unique_ptr<const TEntry* []> sorted =
- sort(uid, pid, maximum_sorted_entries);
- if (!sorted.get()) {
- return output;
- }
- bool headerPrinted = false;
- for (size_t index = 0; index < maximum_sorted_entries; ++index) {
- const TEntry* entry = sorted[index];
- if (!entry) {
- break;
- }
- if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
- break;
- }
- if (!headerPrinted) {
- output += "\n\n";
- output += entry->formatHeader(name, id);
- headerPrinted = true;
- }
- output += entry->format(stat, id);
- }
- return output;
- }
};
namespace EntryBaseConstants {
@@ -627,84 +594,51 @@
std::string format(const LogStatistics& stat, log_id_t id) const;
};
-template <typename TEntry>
-class LogFindWorst {
- std::unique_ptr<const TEntry* []> sorted;
-
- public:
- explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
- : sorted(std::move(sorted)) {
- }
-
- void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
- size_t threshold) {
- if (sorted.get() && sorted[0] && sorted[1]) {
- worst_sizes = sorted[0]->getSizes();
- if ((worst_sizes > threshold)
- // Allow time horizon to extend roughly tenfold, assume
- // average entry length is 100 characters.
- && (worst_sizes > (10 * sorted[0]->getDropped()))) {
- worst = sorted[0]->getKey();
- second_worst_sizes = sorted[1]->getSizes();
- if (second_worst_sizes < threshold) {
- second_worst_sizes = threshold;
- }
- }
- }
- }
-
- void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
- if (sorted.get() && sorted[0] && sorted[1]) {
- worst = sorted[0]->getKey();
- second_worst_sizes =
- worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
- }
- }
-};
-
// Log Statistics
class LogStatistics {
friend UidEntry;
+ friend PidEntry;
+ friend TidEntry;
- size_t mSizes[LOG_ID_MAX];
- size_t mElements[LOG_ID_MAX];
- size_t mDroppedElements[LOG_ID_MAX];
- size_t mSizesTotal[LOG_ID_MAX];
- size_t mElementsTotal[LOG_ID_MAX];
- log_time mOldest[LOG_ID_MAX];
- log_time mNewest[LOG_ID_MAX];
- log_time mNewestDropped[LOG_ID_MAX];
- static size_t SizesTotal;
+ size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
+ size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
+ size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
+ size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
+ size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
+ log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
+ log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
+ log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
+ static std::atomic<size_t> SizesTotal;
bool enable;
// uid to size list
typedef LogHashtable<uid_t, UidEntry> uidTable_t;
- uidTable_t uidTable[LOG_ID_MAX];
+ uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
// pid of system to size list
typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
- pidSystemTable_t pidSystemTable[LOG_ID_MAX];
+ pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
// pid to uid list
typedef LogHashtable<pid_t, PidEntry> pidTable_t;
- pidTable_t pidTable;
+ pidTable_t pidTable GUARDED_BY(lock_);
// tid to uid list
typedef LogHashtable<pid_t, TidEntry> tidTable_t;
- tidTable_t tidTable;
+ tidTable_t tidTable GUARDED_BY(lock_);
// tag list
typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
- tagTable_t tagTable;
+ tagTable_t tagTable GUARDED_BY(lock_);
// security tag list
- tagTable_t securityTagTable;
+ tagTable_t securityTagTable GUARDED_BY(lock_);
// global tag list
typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
tagNameTable_t tagNameTable;
- size_t sizeOf() const {
+ size_t sizeOf() const REQUIRES(lock_) {
size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
tagTable.sizeOf() + securityTagTable.sizeOf() +
tagNameTable.sizeOf() +
@@ -729,62 +663,59 @@
return size;
}
- public:
- LogStatistics();
+ public:
+ LogStatistics(bool enable_statistics);
- void enableStatistics() {
- enable = true;
- }
-
- void addTotal(LogBufferElement* entry);
- void add(LogBufferElement* entry);
- void subtract(LogBufferElement* entry);
+ void AddTotal(LogBufferElement* entry) EXCLUDES(lock_);
+ void Add(LogBufferElement* entry) EXCLUDES(lock_);
+ void Subtract(LogBufferElement* entry) EXCLUDES(lock_);
// entry->setDropped(1) must follow this call
- void drop(LogBufferElement* entry);
+ void Drop(LogBufferElement* entry) EXCLUDES(lock_);
// Correct for coalescing two entries referencing dropped content
- void erase(LogBufferElement* element) {
+ void Erase(LogBufferElement* element) EXCLUDES(lock_) {
+ auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
--mElements[log_id];
--mDroppedElements[log_id];
}
- LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
- return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
- }
- LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
- log_id id) {
- return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
- }
- LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
- return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
- }
+ void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+ size_t* second_worst_sizes) const EXCLUDES(lock_);
+ void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+ size_t* second_worst_sizes) const EXCLUDES(lock_);
+ void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+ size_t* second_worst_sizes) const EXCLUDES(lock_);
- // fast track current value by id only
- size_t sizes(log_id_t id) const {
+ bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
+ EXCLUDES(lock_);
+
+ // Snapshot of the sizes for a given log buffer.
+ size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
+ auto lock = std::lock_guard{lock_};
return mSizes[id];
}
- size_t elements(log_id_t id) const {
- return mElements[id];
- }
- size_t realElements(log_id_t id) const {
- return mElements[id] - mDroppedElements[id];
- }
- size_t sizesTotal(log_id_t id) const {
- return mSizesTotal[id];
- }
- size_t elementsTotal(log_id_t id) const {
- return mElementsTotal[id];
- }
+ // TODO: Get rid of this entirely.
static size_t sizesTotal() {
return SizesTotal;
}
- std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
+ std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
- // helper (must be locked directly or implicitly by mLogElementsLock)
- const char* pidToName(pid_t pid) const;
- uid_t pidToUid(pid_t pid);
- const char* uidToName(uid_t uid) const;
+ const char* PidToName(pid_t pid) const EXCLUDES(lock_);
+ uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
+ const char* UidToName(uid_t uid) const EXCLUDES(lock_);
+
+ private:
+ template <typename TKey, typename TEntry>
+ void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+ int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
+ template <typename TKey, typename TEntry>
+ std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
+ const std::string& name = std::string(""),
+ log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
+ void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
+ size_t nameLen) const REQUIRES(lock_);
+ const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
+
+ mutable std::mutex lock_;
};
-
-#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index 3e52b38..8250808 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -37,6 +37,7 @@
#include <log/log_read.h>
#include <private/android_filesystem_config.h>
+#include "LogStatistics.h"
#include "LogTags.h"
#include "LogUtils.h"
@@ -99,8 +100,7 @@
struct tm tm;
localtime_r(&now, &tm);
char timebuf[20];
- size_t len =
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
+ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
android::base::WriteStringToFd(
android::base::StringPrintf(
"# Rebuilt %.20s, content owned by logd\n", timebuf),
@@ -189,7 +189,6 @@
// Read the event log tags file, and build up our internal database
void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
bool etc = !strcmp(filename, system_event_log_tags);
- bool debug = !etc && !strcmp(filename, debug_event_log_tags);
if (!etc) {
RebuildFileEventLogTags(filename, warn);
@@ -495,7 +494,7 @@
// Every 16K (half the smallest configurable pmsg buffer size) record
static const size_t rate_to_pmsg = 16 * 1024;
- if (lastTotal && ((android::sizesTotal() - lastTotal) < rate_to_pmsg)) {
+ if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
return;
}
@@ -548,7 +547,7 @@
*/
struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
android_log_header_t header = {
.id = LOG_ID_EVENTS,
@@ -665,7 +664,7 @@
}
}
- lastTotal = android::sizesTotal();
+ lastTotal = LogStatistics::sizesTotal();
if (!lastTotal) ++lastTotal;
// record totals for next watermark.
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index f9cd42d..3fe1bbe 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -32,8 +32,6 @@
char* uidToName(uid_t uid);
void prdebug(const char* fmt, ...) __printflike(1, 2);
-// Furnished in LogStatistics.cpp.
-size_t sizesTotal();
// Caller must own and free returned value
char* pidToName(pid_t pid);
char* tidToName(pid_t tid);
diff --git a/logd/README.property b/logd/README.property
index 1b7e165..6a9369a 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -44,10 +44,6 @@
oldest entries of chattiest UID, and
the chattiest PID of system
(1000, or AID_SYSTEM).
-persist.logd.timestamp string ro The recording timestamp source.
- "m[onotonic]" is the only supported
- key character, otherwise realtime.
-ro.logd.timestamp string realtime default for persist.logd.timestamp
log.tag string persist The global logging level, VERBOSE,
DEBUG, INFO, WARN, ERROR, ASSERT or
SILENT. Only the first character is
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
index 299242d..f65fbdf 100644
--- a/logd/fuzz/Android.bp
+++ b/logd/fuzz/Android.bp
@@ -25,6 +25,7 @@
"liblog",
"liblogd",
"libcutils",
+ "libsysutils",
],
cflags: ["-Werror"],
}
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index 8156612..8f90f50 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -15,8 +15,10 @@
*/
#include <string>
-#include "../LogBuffer.h"
+#include "../ChattyLogBuffer.h"
+#include "../LogReaderList.h"
#include "../LogReaderThread.h"
+#include "../LogStatistics.h"
// We don't want to waste a lot of entropy on messages
#define MAX_MSG_LENGTH 5
@@ -36,7 +38,8 @@
unsigned int log_mask;
};
-int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer) {
+int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer,
+ LogStatistics* stats) {
const uint8_t* data = *pdata;
const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
data += sizeof(LogInput);
@@ -69,9 +72,9 @@
// Other elements not in enum.
log_id_t log_id = static_cast<log_id_t>(unsigned(logInput->log_id) % (LOG_ID_MAX + 1));
- log_buffer->log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
+ log_buffer->Log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
sizeof(uint32_t) + msg_length + 1);
- log_buffer->formatStatistics(logInput->uid, logInput->pid, logInput->log_mask);
+ stats->Format(logInput->uid, logInput->pid, logInput->log_mask);
*pdata = data;
return 1;
}
@@ -93,25 +96,25 @@
return 0;
}
- LastLogTimes times;
+ LogReaderList reader_list;
LogTags tags;
PruneList prune_list;
- LogBuffer log_buffer(×, &tags, &prune_list);
+ LogStatistics stats(true);
+ LogBuffer* log_buffer = new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats);
size_t data_left = size;
const uint8_t** pdata = &data;
- log_buffer.enableStatistics();
prune_list.init(nullptr);
// We want to get pruning code to get called.
- log_id_for_each(i) { log_buffer.setSize(i, 10000); }
+ log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- if (!write_log_messages(pdata, &data_left, &log_buffer)) {
+ if (!write_log_messages(pdata, &data_left, log_buffer, &stats)) {
return 0;
}
}
- log_id_for_each(i) { log_buffer.clear(i); }
+ log_id_for_each(i) { log_buffer->Clear(i, 0); }
return 0;
}
} // namespace android
diff --git a/logd/main.cpp b/logd/main.cpp
index cc45eb3..6e1144b 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -47,11 +47,13 @@
#include <processgroup/sched_policy.h>
#include <utils/threads.h>
+#include "ChattyLogBuffer.h"
#include "CommandListener.h"
#include "LogAudit.h"
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogListener.h"
+#include "LogStatistics.h"
#include "LogTags.h"
#include "LogUtils.h"
@@ -109,21 +111,6 @@
return 0;
}
-// Property helper
-static bool check_flag(const char* prop, const char* flag) {
- const char* cp = strcasestr(prop, flag);
- if (!cp) {
- return false;
- }
- // We only will document comma (,)
- static const char sep[] = ",:;|+ \t\f";
- if ((cp != prop) && !strchr(sep, cp[-1])) {
- return false;
- }
- cp += strlen(flag);
- return !*cp || !!strchr(sep, *cp);
-}
-
static int fdDmesg = -1;
void android::prdebug(const char* fmt, ...) {
if (fdDmesg < 0) {
@@ -201,10 +188,6 @@
}
buf[--len] = '\0';
- if (kl && kl->isMonotonic()) {
- kl->synchronize(buf.get(), len);
- }
-
ssize_t sublen;
for (char *ptr = nullptr, *tok = buf.get();
(rc >= 0) && !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
@@ -289,31 +272,28 @@
// A cache of event log tags
LogTags log_tags;
+
// Pruning configuration.
PruneList prune_list;
+ // Partial (required for chatty) or full logging statistics.
+ bool enable_full_log_statistics = __android_logger_property_get_bool(
+ "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
+ BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
+ LogStatistics log_statistics(enable_full_log_statistics);
+
// Serves the purpose of managing the last logs times read on a
// socket connection, and as a reader lock on a range of log
// entries.
-
- LastLogTimes* times = new LastLogTimes();
+ LogReaderList reader_list;
// LogBuffer is the object which is responsible for holding all
// log entries.
-
- LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list);
-
- if (__android_logger_property_get_bool(
- "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
- BOOL_DEFAULT_FLAG_ENG |
- BOOL_DEFAULT_FLAG_SVELTE)) {
- logBuf->enableStatistics();
- }
+ LogBuffer* logBuf = new ChattyLogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics);
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
-
- LogReader* reader = new LogReader(logBuf);
+ LogReader* reader = new LogReader(logBuf, &reader_list);
if (reader->startListener()) {
return EXIT_FAILURE;
}
@@ -321,17 +301,14 @@
// LogListener listens on /dev/socket/logdw for client
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
-
- LogListener* swl = new LogListener(logBuf, reader);
- // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
- if (swl->startListener(600)) {
+ LogListener* swl = new LogListener(logBuf);
+ if (!swl->StartListener()) {
return EXIT_FAILURE;
}
// Command listener listens on /dev/socket/logd for incoming logd
// administrative commands.
-
- CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list);
+ CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list, &log_statistics);
if (cl->startListener()) {
return EXIT_FAILURE;
}
@@ -339,25 +316,22 @@
// LogAudit listens on NETLINK_AUDIT socket for selinux
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
-
LogAudit* al = nullptr;
if (auditd) {
- al = new LogAudit(logBuf, reader,
- __android_logger_property_get_bool(
- "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
- ? fdDmesg
- : -1);
+ int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
+ ? fdDmesg
+ : -1;
+ al = new LogAudit(logBuf, dmesg_fd, &log_statistics);
}
LogKlog* kl = nullptr;
if (klogd) {
- kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);
+ kl = new LogKlog(logBuf, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
}
readDmesg(al, kl);
// failure is an option ... messages are in dmesg (required by standard)
-
if (kl && kl->startListener()) {
delete kl;
}
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 1dd5c86..55737e9 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -606,7 +606,7 @@
// A few tries to get it right just in case wrap kicks in due to
// content providers being active during the test.
int i = 5;
- log_time start(android_log_clockid());
+ log_time start(CLOCK_REALTIME);
start.tv_sec -= 30; // reach back a moderate period of time
while (--i) {
@@ -682,7 +682,7 @@
if (msg > start) {
start = msg;
start.tv_sec += 30;
- log_time now = log_time(android_log_clockid());
+ log_time now = log_time(CLOCK_REALTIME);
if (start > now) {
start = now;
--start.tv_sec;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a380ebb..00a58bf 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -547,8 +547,8 @@
enter_default_mount_ns
# /data/apex is now available. Start apexd to scan and activate APEXes.
- mkdir /data/apex 0750 root system encryption=None
- mkdir /data/apex/active 0750 root system
+ mkdir /data/apex 0755 root system encryption=None
+ mkdir /data/apex/active 0755 root system
mkdir /data/apex/backup 0700 root system
mkdir /data/apex/hashtree 0700 root system
mkdir /data/apex/sessions 0700 root system