Merge "Add section parsing and function name handling."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index bfb1144..ff7b71f 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -49,6 +49,7 @@
#include "adb_auth.h"
#include "adb_io.h"
#include "adb_listeners.h"
+#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps/chrono.h"
#include "transport.h"
@@ -656,6 +657,26 @@
#endif
+static void ReportServerStartupFailure(pid_t pid) {
+ fprintf(stderr, "ADB server didn't ACK\n");
+ fprintf(stderr, "Full server startup log: %s\n", GetLogFilePath().c_str());
+ fprintf(stderr, "Server had pid: %d\n", pid);
+
+ unique_fd fd(adb_open(GetLogFilePath().c_str(), O_RDONLY));
+ if (fd == -1) return;
+
+ // Let's not show more than 128KiB of log...
+ adb_lseek(fd, -128 * 1024, SEEK_END);
+ std::string content;
+ if (!android::base::ReadFdToString(fd, &content)) return;
+
+ std::string header = android::base::StringPrintf("--- adb starting (pid %d) ---", pid);
+ std::vector<std::string> lines = android::base::Split(content, "\n");
+ int i = lines.size() - 1;
+ while (i >= 0 && lines[i] != header) --i;
+ while (static_cast<size_t>(i) < lines.size()) fprintf(stderr, "%s\n", lines[i++].c_str());
+}
+
int launch_server(const std::string& socket_spec) {
#if defined(_WIN32)
/* we need to start the server in the background */
@@ -835,7 +856,8 @@
memcmp(temp, expected, expected_length) == 0) {
got_ack = true;
} else {
- fprintf(stderr, "ADB server didn't ACK\n");
+ ReportServerStartupFailure(GetProcessId(process_handle.get()));
+ return -1;
}
} else {
const DWORD err = GetLastError();
@@ -909,12 +931,9 @@
"--reply-fd", reply_fd, NULL);
// this should not return
fprintf(stderr, "adb: execl returned %d: %s\n", result, strerror(errno));
- } else {
+ } else {
// parent side of the fork
-
- char temp[3];
-
- temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+ char temp[3] = {};
// wait for the "OK\n" message
adb_close(fd[1]);
int ret = adb_read(fd[0], temp, 3);
@@ -925,7 +944,7 @@
return -1;
}
if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
+ ReportServerStartupFailure(pid);
return -1;
}
}
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6f2403d..bb26e70 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -278,3 +278,29 @@
fprintf(stderr, "\n");
return 1;
}
+
+std::string GetLogFilePath() {
+#if defined(_WIN32)
+ const char log_name[] = "adb.log";
+ WCHAR temp_path[MAX_PATH];
+
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
+ DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
+ if (nchars >= arraysize(temp_path) || nchars == 0) {
+ // If string truncation or some other error.
+ fatal("cannot retrieve temporary file path: %s\n",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
+
+ std::string temp_path_utf8;
+ if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
+ fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
+ }
+
+ return temp_path_utf8 + log_name;
+#else
+ const char* tmp_dir = getenv("TMPDIR");
+ if (tmp_dir == nullptr) tmp_dir = "/tmp";
+ return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
+#endif
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 11c0ec9..f764a0e 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -89,4 +89,6 @@
}
};
+std::string GetLogFilePath();
+
#endif
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 62798cd..f0d0ce7 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -39,33 +39,7 @@
#include "sysdeps/chrono.h"
#include "transport.h"
-static std::string GetLogFilePath() {
-#if defined(_WIN32)
- const char log_name[] = "adb.log";
- WCHAR temp_path[MAX_PATH];
-
- // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
- DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
- if (nchars >= arraysize(temp_path) || nchars == 0) {
- // If string truncation or some other error.
- fatal("cannot retrieve temporary file path: %s\n",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
-
- std::string temp_path_utf8;
- if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
- fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
- }
-
- return temp_path_utf8 + log_name;
-#else
- const char* tmp_dir = getenv("TMPDIR");
- if (tmp_dir == nullptr) tmp_dir = "/tmp";
- return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
-#endif
-}
-
-static void setup_daemon_logging(void) {
+static void setup_daemon_logging() {
const std::string log_file_path(GetLogFilePath());
int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
if (fd == -1) {
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
index 8420f03..9c2f0d6 100644
--- a/debuggerd/client/debuggerd_client_test.cpp
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -27,6 +27,7 @@
#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -36,8 +37,20 @@
using namespace std::chrono_literals;
using android::base::unique_fd;
+static int getThreadCount() {
+ int threadCount = 1024;
+ std::vector<std::string> characteristics =
+ android::base::Split(android::base::GetProperty("ro.build.characteristics", ""), ",");
+ if (std::find(characteristics.begin(), characteristics.end(), "embedded")
+ != characteristics.end()) {
+ // 128 is the realistic number for iot devices.
+ threadCount = 128;
+ }
+ return threadCount;
+}
+
TEST(debuggerd_client, race) {
- static constexpr int THREAD_COUNT = 1024;
+ static int THREAD_COUNT = getThreadCount();
pid_t forkpid = fork();
ASSERT_NE(-1, forkpid);
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index df7201d..4b1e51d 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -282,7 +282,10 @@
ATRACE_NAME("after reparent");
// Die if we take too long.
- alarm(2);
+ //
+ // Note: processes with many threads and minidebug-info can take a bit to
+ // unwind, do not make this too small. b/62828735
+ alarm(5);
std::string attach_error;
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 4660f3d..b51fc66 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -311,7 +311,7 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_BACKTRACE_FRAME(result, "tgkill");
+ ASSERT_BACKTRACE_FRAME(result, "abort");
}
TEST_F(CrasherTest, signal) {
@@ -458,7 +458,7 @@
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
ConsumeFd(std::move(output_fd), &result);
- ASSERT_BACKTRACE_FRAME(result, "tgkill");
+ ASSERT_BACKTRACE_FRAME(result, "abort");
}
TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
@@ -478,7 +478,7 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_BACKTRACE_FRAME(result, "tgkill");
+ ASSERT_BACKTRACE_FRAME(result, "abort");
}
TEST_F(CrasherTest, capabilities) {
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index edc7be5..996d714 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -168,6 +168,26 @@
case TRAP_BRANCH: return "TRAP_BRANCH";
case TRAP_HWBKPT: return "TRAP_HWBKPT";
}
+ if ((code & 0xff) == SIGTRAP) {
+ switch ((code >> 8) & 0xff) {
+ case PTRACE_EVENT_FORK:
+ return "PTRACE_EVENT_FORK";
+ case PTRACE_EVENT_VFORK:
+ return "PTRACE_EVENT_VFORK";
+ case PTRACE_EVENT_CLONE:
+ return "PTRACE_EVENT_CLONE";
+ case PTRACE_EVENT_EXEC:
+ return "PTRACE_EVENT_EXEC";
+ case PTRACE_EVENT_VFORK_DONE:
+ return "PTRACE_EVENT_VFORK_DONE";
+ case PTRACE_EVENT_EXIT:
+ return "PTRACE_EVENT_EXIT";
+ case PTRACE_EVENT_SECCOMP:
+ return "PTRACE_EVENT_SECCOMP";
+ case PTRACE_EVENT_STOP:
+ return "PTRACE_EVENT_STOP";
+ }
+ }
static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
break;
}
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index b920ebc..7685476 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -172,7 +172,7 @@
1 /* max_concurrent_dumps */);
/* static */ CrashQueue* const CrashQueue::java_trace =
- (kJavaTraceDumpsEnabled ? new CrashQueue("/data/anr", "anr_" /* file_name_prefix */,
+ (kJavaTraceDumpsEnabled ? new CrashQueue("/data/anr", "trace_" /* file_name_prefix */,
64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
: nullptr);
@@ -345,7 +345,14 @@
}
if (!crash->crash_path.empty()) {
- LOG(ERROR) << "Tombstone written to: " << crash->crash_path;
+ if (crash->crash_type == kDebuggerdJavaBacktrace) {
+ LOG(ERROR) << "Traces for pid " << crash->crash_pid << " written to: " << crash->crash_path;
+ } else {
+ // NOTE: Several tools parse this log message to figure out where the
+ // tombstone associated with a given native crash was written. Any changes
+ // to this message must be carefully considered.
+ LOG(ERROR) << "Tombstone written to: " << crash->crash_path;
+ }
}
fail:
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 84981bf..5e0bfe4 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -847,7 +847,9 @@
}
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
- if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ if (__android_log_is_debuggable() &&
+ (rc == FS_MGR_SETUP_VERITY_DISABLED ||
+ rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
LINFO << "Verity disabled";
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
LERROR << "Could not set up verified partition, skipping!";
@@ -1061,7 +1063,9 @@
}
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
- if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ if (__android_log_is_debuggable() &&
+ (rc == FS_MGR_SETUP_VERITY_DISABLED ||
+ rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
LINFO << "Verity disabled";
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
LERROR << "Could not set up verified partition, skipping!";
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 0177fdf..1d832b3 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -766,7 +766,7 @@
// setup is needed at all.
if (!is_device_secure()) {
LINFO << "Verity setup skipped for " << mount_point;
- return FS_MGR_SETUP_VERITY_SUCCESS;
+ return FS_MGR_SETUP_VERITY_SKIPPED;
}
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 9079a43..047fd54 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -140,6 +140,7 @@
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
+#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2)
#define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 45b6eda..4e3b885 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -116,6 +116,10 @@
{ "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
{ "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
{ "Cold", BATTERY_HEALTH_COLD },
+ // battery health values from JEITA spec
+ { "Warm", BATTERY_HEALTH_GOOD },
+ { "Cool", BATTERY_HEALTH_GOOD },
+ { "Hot", BATTERY_HEALTH_OVERHEAT },
{ NULL, 0 },
};
diff --git a/init/action.cpp b/init/action.cpp
index 21abe02..206100e 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,13 +18,11 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "util.h"
using android::base::Join;
-using android::base::StringPrintf;
Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
: func_(f), args_(args), line_(line) {}
@@ -98,10 +96,10 @@
android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
- std::string source = StringPrintf(" (%s:%d)", filename_.c_str(), command.line());
- LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
- << " returned " << result << " took " << duration_ms << "ms.";
+ LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
+ << ":" << command.line() << ") returned " << result << " took " << duration_ms
+ << "ms.";
}
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 1eacb36..c78bec7 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -43,7 +43,6 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
@@ -535,11 +534,10 @@
}
}
- std::string prop_name = android::base::StringPrintf("ro.boottime.init.mount_all.%s",
- prop_post_fix);
+ std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
Timer t;
int ret = mount_fstab(fstabfile, mount_mode);
- property_set(prop_name.c_str(), std::to_string(t.duration_ms()).c_str());
+ property_set(prop_name, std::to_string(t.duration_ms()));
if (import_rc) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
@@ -567,9 +565,7 @@
}
static int do_setprop(const std::vector<std::string>& args) {
- const char* name = args[1].c_str();
- const char* value = args[2].c_str();
- property_set(name, value);
+ property_set(args[1], args[2]);
return 0;
}
@@ -652,8 +648,7 @@
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
int mode, int status) {
- property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
- android::base::StringPrintf("%d", mode).c_str());
+ property_set("partition."s + mount_point + ".verified", std::to_string(mode));
}
static int do_verity_update_state(const std::vector<std::string>& args) {
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 6f729a3..ed65a05 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -58,7 +58,7 @@
std::for_each(publishedName.begin(), publishedName.end(),
[] (char& c) { c = isalnum(c) ? c : '_'; });
- std::string val = android::base::StringPrintf("%d", fd);
+ std::string val = std::to_string(fd);
add_environment(publishedName.c_str(), val.c_str());
// make sure we don't close on exec
@@ -74,7 +74,8 @@
}
void SocketInfo::Clean() const {
- unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
+ std::string path = android::base::StringPrintf("%s/%s", ANDROID_SOCKET_DIR, name().c_str());
+ unlink(path.c_str());
}
int SocketInfo::Create(const std::string& context) const {
diff --git a/init/devices.cpp b/init/devices.cpp
index c52d8f8..2943fb7 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -147,21 +147,34 @@
}
}
-// Given a path that may start with a platform device, find the length of the
-// platform device prefix. If it doesn't start with a platform device, return false
-bool PlatformDeviceList::Find(const std::string& path, std::string* out_path) const {
- out_path->clear();
- // platform_devices is searched backwards, since parents are added before their children,
- // and we want to match as deep of a child as we can.
- for (auto it = platform_devices_.crbegin(); it != platform_devices_.crend(); ++it) {
- auto platform_device_path_length = it->length();
- if (platform_device_path_length < path.length() &&
- path[platform_device_path_length] == '/' &&
- android::base::StartsWith(path, it->c_str())) {
- *out_path = *it;
+// Given a path that may start with a platform device, find the parent platform device by finding a
+// parent directory with a 'subsystem' symlink that points to the platform bus.
+// If it doesn't start with a platform device, return false
+bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
+ platform_device_path->clear();
+
+ // Uevents don't contain the mount point, so we need to add it here.
+ path.insert(0, sysfs_mount_point_);
+
+ std::string directory = android::base::Dirname(path);
+
+ while (directory != "/" && directory != ".") {
+ std::string subsystem_link_path;
+ if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
+ subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
+ // We need to remove the mount point that we added above before returning.
+ directory.erase(0, sysfs_mount_point_.size());
+ *platform_device_path = directory;
return true;
}
+
+ auto last_slash = path.rfind('/');
+ if (last_slash == std::string::npos) return false;
+
+ path.erase(last_slash);
+ directory = android::base::Dirname(path);
}
+
return false;
}
@@ -258,7 +271,7 @@
std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
std::string parent_device;
- if (!platform_devices_.Find(uevent.path, &parent_device)) return {};
+ if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
// skip path to the parent driver
std::string path = uevent.path.substr(parent_device.length());
@@ -316,7 +329,7 @@
std::string device;
std::string type;
- if (platform_devices_.Find(uevent.path, &device)) {
+ if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/";
@@ -388,14 +401,6 @@
}
}
-void DeviceHandler::HandlePlatformDeviceEvent(const Uevent& uevent) {
- if (uevent.action == "add") {
- platform_devices_.Add(uevent.path);
- } else if (uevent.action == "remove") {
- platform_devices_.Remove(uevent.path);
- }
-}
-
void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
@@ -458,8 +463,6 @@
if (uevent.subsystem == "block") {
HandleBlockDeviceEvent(uevent);
- } else if (uevent.subsystem == "platform") {
- HandlePlatformDeviceEvent(uevent);
} else {
HandleGenericDeviceEvent(uevent);
}
@@ -472,7 +475,8 @@
sysfs_permissions_(std::move(sysfs_permissions)),
subsystems_(std::move(subsystems)),
sehandle_(selinux_android_file_context_handle()),
- skip_restorecon_(skip_restorecon) {}
+ skip_restorecon_(skip_restorecon),
+ sysfs_mount_point_("/sys") {}
DeviceHandler::DeviceHandler()
: DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
diff --git a/init/devices.h b/init/devices.h
index 09a0ce3..362c38c 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -93,20 +93,6 @@
DevnameSource devname_source_;
};
-class PlatformDeviceList {
- public:
- void Add(const std::string& path) { platform_devices_.emplace_back(path); }
- void Remove(const std::string& path) {
- auto it = std::find(platform_devices_.begin(), platform_devices_.end(), path);
- if (it != platform_devices_.end()) platform_devices_.erase(it);
- }
- bool Find(const std::string& path, std::string* out_path) const;
- auto size() const { return platform_devices_.size(); }
-
- private:
- std::vector<std::string> platform_devices_;
-};
-
class DeviceHandler {
public:
friend class DeviceHandlerTester;
@@ -119,16 +105,11 @@
void HandleDeviceEvent(const Uevent& uevent);
- void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
-
- void HandlePlatformDeviceEvent(const Uevent& uevent);
- void HandleBlockDeviceEvent(const Uevent& uevent) const;
- void HandleGenericDeviceEvent(const Uevent& uevent) const;
-
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
private:
+ bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const;
void MakeDevice(const std::string& path, int block, int major, int minor,
@@ -136,13 +117,17 @@
std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
int minor, const std::vector<std::string>& links) const;
+ void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
+
+ void HandleBlockDeviceEvent(const Uevent& uevent) const;
+ void HandleGenericDeviceEvent(const Uevent& uevent) const;
std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_;
- PlatformDeviceList platform_devices_;
selabel_handle* sehandle_;
bool skip_restorecon_;
+ std::string sysfs_mount_point_;
};
// Exposed for testing
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 41b101b..e1e4e49 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -16,33 +16,29 @@
#include "devices.h"
-#include <string>
-#include <vector>
-
#include <android-base/scopeguard.h>
+#include <android-base/test_utils.h>
#include <gtest/gtest.h>
+#include "util.h"
+
+using namespace std::string_literals;
+
class DeviceHandlerTester {
public:
- void AddPlatformDevice(const std::string& path) {
- Uevent uevent = {
- .action = "add", .subsystem = "platform", .path = path,
- };
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
- void RemovePlatformDevice(const std::string& path) {
- Uevent uevent = {
- .action = "remove", .subsystem = "platform", .path = path,
- };
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
- void TestGetSymlinks(const std::string& platform_device_name, const Uevent& uevent,
+ void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
const std::vector<std::string> expected_links, bool block) {
- AddPlatformDevice(platform_device_name);
- auto platform_device_remover = android::base::make_scope_guard(
- [this, &platform_device_name]() { RemovePlatformDevice(platform_device_name); });
+ TemporaryDir fake_sys_root;
+ device_handler_.sysfs_mount_point_ = fake_sys_root.path;
+
+ std::string platform_device_dir = fake_sys_root.path + platform_device;
+ mkdir_recursive(platform_device_dir, 0777, nullptr);
+
+ std::string platform_bus = fake_sys_root.path + "/bus/platform"s;
+ mkdir_recursive(platform_bus, 0777, nullptr);
+ symlink(platform_bus.c_str(), (platform_device_dir + "/subsystem").c_str());
+
+ mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
std::vector<std::string> result;
if (block) {
@@ -65,30 +61,6 @@
DeviceHandler device_handler_;
};
-TEST(device_handler, PlatformDeviceList) {
- PlatformDeviceList platform_device_list;
-
- platform_device_list.Add("/devices/platform/some_device_name");
- platform_device_list.Add("/devices/platform/some_device_name/longer");
- platform_device_list.Add("/devices/platform/other_device_name");
- EXPECT_EQ(3U, platform_device_list.size());
-
- std::string out_path;
- EXPECT_FALSE(platform_device_list.Find("/devices/platform/not_found", &out_path));
- EXPECT_EQ("", out_path);
-
- EXPECT_FALSE(platform_device_list.Find("/devices/platform/some_device_name_with_same_prefix",
- &out_path));
-
- EXPECT_TRUE(platform_device_list.Find("/devices/platform/some_device_name/longer/longer_child",
- &out_path));
- EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
-
- EXPECT_TRUE(
- platform_device_list.Find("/devices/platform/some_device_name/other_child", &out_path));
- EXPECT_EQ("/devices/platform/some_device_name", out_path);
-}
-
TEST(device_handler, get_character_device_symlinks_success) {
const char* platform_device = "/devices/platform/some_device_name";
Uevent uevent = {
diff --git a/init/init.cpp b/init/init.cpp
index 999fada..d6e9130 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -42,7 +42,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <keyutils.h>
@@ -71,9 +70,10 @@
#include "util.h"
#include "watchdogd.h"
+using namespace std::string_literals;
+
using android::base::boot_clock;
using android::base::GetProperty;
-using android::base::StringPrintf;
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
@@ -219,7 +219,7 @@
panic();
}
- property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration_ms()).c_str());
+ property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration_ms()));
return 0;
}
@@ -449,14 +449,14 @@
if (for_emulator) {
// In the emulator, export any kernel option with the "ro.kernel." prefix.
- property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
+ property_set("ro.kernel." + key, value);
return;
}
if (key == "qemu") {
strlcpy(qemu, value.c_str(), sizeof(qemu));
} else if (android::base::StartsWith(key, "androidboot.")) {
- property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());
+ property_set("ro.boot." + key.substr(12), value);
}
}
@@ -487,7 +487,7 @@
};
for (size_t i = 0; i < arraysize(prop_map); i++) {
std::string value = GetProperty(prop_map[i].src_prop, "");
- property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
+ property_set(prop_map[i].dst_prop, (!value.empty()) ? value : prop_map[i].default_value);
}
}
@@ -511,8 +511,7 @@
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
- std::string property_name = StringPrintf("ro.boot.%s", dp->d_name);
- property_set(property_name.c_str(), dt_file.c_str());
+ property_set("ro.boot."s + dp->d_name, dt_file);
}
}
@@ -1002,7 +1001,7 @@
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
- setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);
+ setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 0f2b1f3..4faca89 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <chrono>
#include <memory>
#include <set>
#include <string>
@@ -35,6 +36,8 @@
#include "uevent_listener.h"
#include "util.h"
+using namespace std::chrono_literals;
+
// Class Declarations
// ------------------
class FirstStageMount {
@@ -49,11 +52,11 @@
bool InitDevices();
protected:
- void InitRequiredDevices();
- void InitVerityDevice(const std::string& verity_device);
+ bool InitRequiredDevices();
+ bool InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
- virtual RegenerationAction UeventCallback(const Uevent& uevent);
+ virtual ListenerAction UeventCallback(const Uevent& uevent);
// Pure virtual functions.
virtual bool GetRequiredDevices() = 0;
@@ -86,7 +89,7 @@
~FirstStageMountVBootV2() override = default;
protected:
- RegenerationAction UeventCallback(const Uevent& uevent) override;
+ ListenerAction UeventCallback(const Uevent& uevent) override;
bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
@@ -141,55 +144,60 @@
}
bool FirstStageMount::InitDevices() {
- if (!GetRequiredDevices()) return false;
-
- InitRequiredDevices();
-
- // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
- // So if it isn't empty here, it means some partitions are not found.
- if (!required_devices_partition_names_.empty()) {
- LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
- << android::base::Join(required_devices_partition_names_, ", ");
- return false;
- } else {
- return true;
- }
+ return GetRequiredDevices() && InitRequiredDevices();
}
// Creates devices with uevent->partition_name matching one in the member variable
// required_devices_partition_names_. Found partitions will then be removed from it
// for the subsequent member function to check which devices are NOT created.
-void FirstStageMount::InitRequiredDevices() {
+bool FirstStageMount::InitRequiredDevices() {
if (required_devices_partition_names_.empty()) {
- return;
+ return true;
}
if (need_dm_verity_) {
const std::string dm_path = "/devices/virtual/misc/device-mapper";
- uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path,
- [this, &dm_path](const Uevent& uevent) {
- if (uevent.path == dm_path) {
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kStop;
- }
- return RegenerationAction::kContinue;
- });
+ bool found = false;
+ auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
+ if (uevent.path == dm_path) {
+ device_handler_.HandleDeviceEvent(uevent);
+ found = true;
+ return ListenerAction::kStop;
+ }
+ return ListenerAction::kContinue;
+ };
+ uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
+ if (!found) {
+ uevent_listener_.Poll(dm_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "device-mapper device not found";
+ return false;
+ }
}
- uevent_listener_.RegenerateUevents(
- [this](const Uevent& uevent) { return UeventCallback(uevent); });
+ auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
+ uevent_listener_.RegenerateUevents(uevent_callback);
+
+ // UeventCallback() will remove found partitions from required_devices_partition_names_.
+ // So if it isn't empty here, it means some partitions are not found.
+ if (!required_devices_partition_names_.empty()) {
+ uevent_listener_.Poll(uevent_callback, 10s);
+ }
+
+ if (!required_devices_partition_names_.empty()) {
+ LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
+ << android::base::Join(required_devices_partition_names_, ", ");
+ return false;
+ }
+
+ return true;
}
-RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
- // We need platform devices to create symlinks.
- if (uevent.subsystem == "platform") {
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kContinue;
- }
-
+ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
// Ignores everything that is not a block device.
if (uevent.subsystem != "block") {
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
if (!uevent.partition_name.empty()) {
@@ -198,34 +206,46 @@
// suffix when A/B is used.
auto iter = required_devices_partition_names_.find(uevent.partition_name);
if (iter != required_devices_partition_names_.end()) {
- LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
+ LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
required_devices_partition_names_.erase(iter);
device_handler_.HandleDeviceEvent(uevent);
if (required_devices_partition_names_.empty()) {
- return RegenerationAction::kStop;
+ return ListenerAction::kStop;
} else {
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
}
}
// Not found a partition or find an unneeded partition, continue to find others.
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-void FirstStageMount::InitVerityDevice(const std::string& verity_device) {
+bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
const std::string device_name(basename(verity_device.c_str()));
const std::string syspath = "/sys/block/" + device_name;
+ bool found = false;
- uevent_listener_.RegenerateUeventsForPath(
- syspath, [&device_name, &verity_device, this](const Uevent& uevent) {
- if (uevent.device_name == device_name) {
- LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kStop;
- }
- return RegenerationAction::kContinue;
- });
+ auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
+ if (uevent.device_name == device_name) {
+ LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+ device_handler_.HandleDeviceEvent(uevent);
+ found = true;
+ return ListenerAction::kStop;
+ }
+ return ListenerAction::kContinue;
+ };
+
+ uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
+ if (!found) {
+ uevent_listener_.Poll(verity_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "dm-verity device not found";
+ return false;
+ }
+
+ return true;
}
bool FirstStageMount::MountPartitions() {
@@ -286,13 +306,17 @@
bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_verified(fstab_rec)) {
int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
- if (ret == FS_MGR_SETUP_VERITY_DISABLED) {
- LOG(INFO) << "Verity disabled for '" << fstab_rec->mount_point << "'";
- } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
+ switch (ret) {
+ case FS_MGR_SETUP_VERITY_SKIPPED:
+ case FS_MGR_SETUP_VERITY_DISABLED:
+ LOG(INFO) << "Verity disabled/skipped for '" << fstab_rec->mount_point << "'";
+ break;
+ case FS_MGR_SETUP_VERITY_SUCCESS:
// The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
// Needs to create it because ueventd isn't started in init first stage.
- InitVerityDevice(fstab_rec->blk_device);
- } else {
+ return InitVerityDevice(fstab_rec->blk_device);
+ break;
+ default:
return false;
}
}
@@ -351,7 +375,7 @@
return true;
}
-RegenerationAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
+ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
// Check if this uevent corresponds to one of the required partitions and store its symlinks if
// so, in order to create FsManagerAvbHandle later.
// Note that the parent callback removes partitions from the list of required partitions
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b43da4e..31e6e48 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -45,7 +45,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <bootimg.h>
#include <fs_mgr.h>
@@ -56,8 +55,6 @@
#include "init.h"
#include "util.h"
-using android::base::StringPrintf;
-
#define PERSISTENT_PROPERTY_DIR "/data/property"
#define RECOVERY_MOUNT_POINT "/recovery"
@@ -714,7 +711,7 @@
boot_img_hdr hdr;
if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
- property_set("ro.recovery_id", hex.c_str());
+ property_set("ro.recovery_id", hex);
} else {
PLOG(ERROR) << "error reading /recovery";
}
diff --git a/init/service.cpp b/init/service.cpp
index b73ddfb..d8c6875 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -198,13 +198,12 @@
return;
}
- std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
- property_set(prop_name.c_str(), new_state.c_str());
+ std::string prop_name = "init.svc." + name_;
+ property_set(prop_name, new_state);
if (new_state == "running") {
uint64_t start_ns = time_started_.time_since_epoch().count();
- property_set(StringPrintf("ro.boottime.%s", name_.c_str()).c_str(),
- StringPrintf("%" PRIu64, start_ns).c_str());
+ property_set("ro.boottime." + name_, std::to_string(start_ns));
}
}
@@ -716,7 +715,7 @@
StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str()));
}
}
- std::string pid_str = StringPrintf("%d", getpid());
+ std::string pid_str = std::to_string(getpid());
for (const auto& file : writepid_files_) {
if (!WriteStringToFile(pid_str, file)) {
PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
@@ -757,7 +756,7 @@
}
if (oom_score_adjust_ != -1000) {
- std::string oom_str = StringPrintf("%d", oom_score_adjust_);
+ std::string oom_str = std::to_string(oom_score_adjust_);
std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
if (!WriteStringToFile(oom_str, oom_file)) {
PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
@@ -776,9 +775,9 @@
}
if ((flags_ & SVC_EXEC) != 0) {
- LOG(INFO) << android::base::StringPrintf(
- "SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...", pid_, uid_, gid_,
- supp_gids_.size(), !seclabel_.empty() ? seclabel_.c_str() : "default");
+ LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
+ << supp_gids_.size() << " context "
+ << (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
}
NotifyStateChange("running");
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 4d56d84..183837b 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -21,7 +21,6 @@
#include <unistd.h>
#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
#include "init.h"
#include "service.h"
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 27c5d23..c748984 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -121,8 +121,8 @@
// make sure we don't overrun the socket's buffer.
//
-RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
- RegenerateCallback callback) const {
+ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
+ const ListenerCallback& callback) const {
int dfd = dirfd(d);
int fd = openat(dfd, "uevent", O_WRONLY);
@@ -132,7 +132,7 @@
Uevent uevent;
while (ReadUevent(&uevent)) {
- if (callback(uevent) == RegenerationAction::kStop) return RegenerationAction::kStop;
+ if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
}
}
@@ -147,49 +147,67 @@
if (d2 == 0) {
close(fd);
} else {
- if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) {
- return RegenerationAction::kStop;
+ if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
+ return ListenerAction::kStop;
}
}
}
// default is always to continue looking for uevents
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
-RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path,
- RegenerateCallback callback) const {
+ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
+ const ListenerCallback& callback) const {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
- if (!d) return RegenerationAction::kContinue;
+ if (!d) return ListenerAction::kContinue;
return RegenerateUeventsForDir(d.get(), callback);
}
static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
-void UeventListener::RegenerateUevents(RegenerateCallback callback) const {
+void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
for (const auto path : kRegenerationPaths) {
- if (RegenerateUeventsForPath(path, callback) == RegenerationAction::kStop) return;
+ if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
}
}
-void UeventListener::DoPolling(PollCallback callback) const {
+void UeventListener::Poll(const ListenerCallback& callback,
+ const std::optional<std::chrono::milliseconds> relative_timeout) const {
+ using namespace std::chrono;
+
pollfd ufd;
ufd.events = POLLIN;
ufd.fd = device_fd_;
+ auto start_time = steady_clock::now();
+
while (true) {
ufd.revents = 0;
- int nr = poll(&ufd, 1, -1);
- if (nr <= 0) {
+
+ int timeout_ms = -1;
+ if (relative_timeout) {
+ auto now = steady_clock::now();
+ auto time_elapsed = duration_cast<milliseconds>(now - start_time);
+ if (time_elapsed > *relative_timeout) return;
+
+ auto remaining_timeout = *relative_timeout - time_elapsed;
+ timeout_ms = remaining_timeout.count();
+ }
+
+ int nr = poll(&ufd, 1, timeout_ms);
+ if (nr == 0) return;
+ if (nr < 0) {
+ PLOG(ERROR) << "poll() of uevent socket failed, continuing";
continue;
}
if (ufd.revents & POLLIN) {
- // We're non-blocking, so if we receive a poll event keep processing until there
+ // We're non-blocking, so if we receive a poll event keep processing until
// we have exhausted all uevent messages.
Uevent uevent;
while (ReadUevent(&uevent)) {
- callback(uevent);
+ if (callback(uevent) == ListenerAction::kStop) return;
}
}
}
diff --git a/init/uevent_listener.h b/init/uevent_listener.h
index ba31aaa..0dae102 100644
--- a/init/uevent_listener.h
+++ b/init/uevent_listener.h
@@ -19,7 +19,9 @@
#include <dirent.h>
+#include <chrono>
#include <functional>
+#include <optional>
#include <android-base/unique_fd.h>
@@ -27,26 +29,26 @@
#define UEVENT_MSG_LEN 2048
-enum class RegenerationAction {
+enum class ListenerAction {
kStop = 0, // Stop regenerating uevents as we've handled the one(s) we're interested in.
kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
};
-using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
-using PollCallback = std::function<void(const Uevent&)>;
+using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
class UeventListener {
public:
UeventListener();
- void RegenerateUevents(RegenerateCallback callback) const;
- RegenerationAction RegenerateUeventsForPath(const std::string& path,
- RegenerateCallback callback) const;
- void DoPolling(PollCallback callback) const;
+ void RegenerateUevents(const ListenerCallback& callback) const;
+ ListenerAction RegenerateUeventsForPath(const std::string& path,
+ const ListenerCallback& callback) const;
+ void Poll(const ListenerCallback& callback,
+ const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
private:
bool ReadUevent(Uevent* uevent) const;
- RegenerationAction RegenerateUeventsForDir(DIR* d, RegenerateCallback callback) const;
+ ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;
android::base::unique_fd device_fd_;
};
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index d121647..2fd8058 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -29,7 +29,6 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <selinux/android.h>
#include <selinux/selinux.h>
@@ -128,15 +127,7 @@
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
auto& uevent = uevent_queue_[i];
- if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
- device_handler_.FixupSysPermissions(uevent.path, uevent.subsystem);
- }
-
- if (uevent.subsystem == "block") {
- device_handler_.HandleBlockDeviceEvent(uevent);
- } else {
- device_handler_.HandleGenericDeviceEvent(uevent);
- }
+ device_handler_.HandleDeviceEvent(uevent);
}
_exit(EXIT_SUCCESS);
}
@@ -145,16 +136,8 @@
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
- // This is the one mutable part of DeviceHandler, in which platform devices are
- // added to a vector for later reference. Since there is no communication after
- // fork()'ing subprocess handlers, all platform devices must be in the vector before
- // we fork, and therefore they must be handled in this loop.
- if (uevent.subsystem == "platform") {
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
uevent_queue_.emplace_back(std::move(uevent));
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
});
}
@@ -282,9 +265,10 @@
cold_boot.Run();
}
- uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
+ uevent_listener.Poll([&device_handler](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
device_handler.HandleDeviceEvent(uevent);
+ return ListenerAction::kContinue;
});
return 0;
diff --git a/libmemunreachable/Allocator.cpp b/libmemunreachable/Allocator.cpp
index 6fe67a4..213be17 100644
--- a/libmemunreachable/Allocator.cpp
+++ b/libmemunreachable/Allocator.cpp
@@ -33,9 +33,11 @@
#include "android-base/macros.h"
-#include "anon_vma_naming.h"
#include "Allocator.h"
#include "LinkedList.h"
+#include "anon_vma_naming.h"
+
+namespace android {
// runtime interfaces used:
// abort
@@ -57,10 +59,9 @@
static constexpr size_t kUsableChunkSize = kChunkSize - kPageSize;
static constexpr size_t kMaxBucketAllocationSize = kChunkSize / 4;
static constexpr size_t kMinBucketAllocationSize = 8;
-static constexpr unsigned int kNumBuckets = const_log2(kMaxBucketAllocationSize)
- - const_log2(kMinBucketAllocationSize) + 1;
-static constexpr unsigned int kUsablePagesPerChunk = kUsableChunkSize
- / kPageSize;
+static constexpr unsigned int kNumBuckets =
+ const_log2(kMaxBucketAllocationSize) - const_log2(kMinBucketAllocationSize) + 1;
+static constexpr unsigned int kUsablePagesPerChunk = kUsableChunkSize / kPageSize;
std::atomic<int> heap_count;
@@ -93,7 +94,7 @@
void FreeLocked(void* ptr);
struct MapAllocation {
- void *ptr;
+ void* ptr;
size_t size;
MapAllocation* next;
};
@@ -107,8 +108,7 @@
}
static inline unsigned int size_to_bucket(size_t size) {
- if (size < kMinBucketAllocationSize)
- return kMinBucketAllocationSize;
+ if (size < kMinBucketAllocationSize) return kMinBucketAllocationSize;
return log2(size - 1) + 1 - const_log2(kMinBucketAllocationSize);
}
@@ -140,8 +140,7 @@
// Trim beginning
if (aligned_ptr != ptr) {
- ptrdiff_t extra = reinterpret_cast<uintptr_t>(aligned_ptr)
- - reinterpret_cast<uintptr_t>(ptr);
+ ptrdiff_t extra = reinterpret_cast<uintptr_t>(aligned_ptr) - reinterpret_cast<uintptr_t>(ptr);
munmap(ptr, extra);
map_size -= extra;
ptr = aligned_ptr;
@@ -151,14 +150,13 @@
if (map_size != size) {
assert(map_size > size);
assert(ptr != NULL);
- munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(ptr) + size),
- map_size - size);
+ munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(ptr) + size), map_size - size);
}
-#define PR_SET_VMA 0x53564d41
-#define PR_SET_VMA_ANON_NAME 0
- prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
- reinterpret_cast<uintptr_t>(ptr), size, "leak_detector_malloc");
+#define PR_SET_VMA 0x53564d41
+#define PR_SET_VMA_ANON_NAME 0
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(ptr), size,
+ "leak_detector_malloc");
return ptr;
}
@@ -170,36 +168,31 @@
Chunk(HeapImpl* heap, int bucket);
~Chunk() {}
- void *Alloc();
+ void* Alloc();
void Free(void* ptr);
void Purge();
bool Empty();
static Chunk* ptr_to_chunk(void* ptr) {
- return reinterpret_cast<Chunk*>(reinterpret_cast<uintptr_t>(ptr)
- & ~(kChunkSize - 1));
+ return reinterpret_cast<Chunk*>(reinterpret_cast<uintptr_t>(ptr) & ~(kChunkSize - 1));
}
static bool is_chunk(void* ptr) {
return (reinterpret_cast<uintptr_t>(ptr) & (kChunkSize - 1)) != 0;
}
- unsigned int free_count() {
- return free_count_;
- }
- HeapImpl* heap() {
- return heap_;
- }
- LinkedList<Chunk*> node_; // linked list sorted by minimum free count
+ unsigned int free_count() { return free_count_; }
+ HeapImpl* heap() { return heap_; }
+ LinkedList<Chunk*> node_; // linked list sorted by minimum free count
private:
DISALLOW_COPY_AND_ASSIGN(Chunk);
HeapImpl* heap_;
unsigned int bucket_;
- unsigned int allocation_size_; // size of allocations in chunk, min 8 bytes
- unsigned int max_allocations_; // maximum number of allocations in the chunk
- unsigned int first_free_bitmap_; // index into bitmap for first non-full entry
- unsigned int free_count_; // number of available allocations
- unsigned int frees_since_purge_; // number of calls to Free since last Purge
+ unsigned int allocation_size_; // size of allocations in chunk, min 8 bytes
+ unsigned int max_allocations_; // maximum number of allocations in the chunk
+ unsigned int first_free_bitmap_; // index into bitmap for first non-full entry
+ unsigned int free_count_; // number of available allocations
+ unsigned int frees_since_purge_; // number of calls to Free since last Purge
// bitmap of pages that have been dirtied
uint32_t dirty_pages_[div_round_up(kUsablePagesPerChunk, 32)];
@@ -210,13 +203,10 @@
char data_[0];
unsigned int ptr_to_n(void* ptr) {
- ptrdiff_t offset = reinterpret_cast<uintptr_t>(ptr)
- - reinterpret_cast<uintptr_t>(data_);
+ ptrdiff_t offset = reinterpret_cast<uintptr_t>(ptr) - reinterpret_cast<uintptr_t>(data_);
return offset / allocation_size_;
}
- void* n_to_ptr(unsigned int n) {
- return data_ + n * allocation_size_;
- }
+ void* n_to_ptr(unsigned int n) { return data_ + n * allocation_size_; }
};
static_assert(sizeof(Chunk) <= kPageSize, "header must fit in page");
@@ -225,23 +215,27 @@
assert(count == sizeof(Chunk));
void* mem = MapAligned(kChunkSize, kChunkSize);
if (!mem) {
- abort(); //throw std::bad_alloc;
+ abort(); // throw std::bad_alloc;
}
return mem;
}
// Override new operator on chunk to use mmap to allocate kChunkSize
-void Chunk::operator delete(void *ptr) {
+void Chunk::operator delete(void* ptr) {
assert(reinterpret_cast<Chunk*>(ptr) == ptr_to_chunk(ptr));
munmap(ptr, kChunkSize);
}
-Chunk::Chunk(HeapImpl* heap, int bucket) :
- node_(this), heap_(heap), bucket_(bucket), allocation_size_(
- bucket_to_size(bucket)), max_allocations_(
- kUsableChunkSize / allocation_size_), first_free_bitmap_(0), free_count_(
- max_allocations_), frees_since_purge_(0) {
+Chunk::Chunk(HeapImpl* heap, int bucket)
+ : node_(this),
+ heap_(heap),
+ bucket_(bucket),
+ allocation_size_(bucket_to_size(bucket)),
+ max_allocations_(kUsableChunkSize / allocation_size_),
+ first_free_bitmap_(0),
+ free_count_(max_allocations_),
+ frees_since_purge_(0) {
memset(dirty_pages_, 0, sizeof(dirty_pages_));
memset(free_bitmap_, 0xff, sizeof(free_bitmap_));
}
@@ -254,8 +248,7 @@
assert(free_count_ > 0);
unsigned int i = first_free_bitmap_;
- while (free_bitmap_[i] == 0)
- i++;
+ while (free_bitmap_[i] == 0) i++;
assert(i < arraysize(free_bitmap_));
unsigned int bit = __builtin_ffs(free_bitmap_[i]) - 1;
assert(free_bitmap_[i] & (1U << bit));
@@ -306,38 +299,35 @@
void Chunk::Purge() {
frees_since_purge_ = 0;
- //unsigned int allocsPerPage = kPageSize / allocation_size_;
+ // unsigned int allocsPerPage = kPageSize / allocation_size_;
}
// Override new operator on HeapImpl to use mmap to allocate a page
-void* HeapImpl::operator new(std::size_t count __attribute__((unused)))
- noexcept {
+void* HeapImpl::operator new(std::size_t count __attribute__((unused))) noexcept {
assert(count == sizeof(HeapImpl));
void* mem = MapAligned(kPageSize, kPageSize);
if (!mem) {
- abort(); //throw std::bad_alloc;
+ abort(); // throw std::bad_alloc;
}
heap_count++;
return mem;
}
-void HeapImpl::operator delete(void *ptr) {
+void HeapImpl::operator delete(void* ptr) {
munmap(ptr, kPageSize);
}
-HeapImpl::HeapImpl() :
- free_chunks_(), full_chunks_(), map_allocation_list_(NULL) {
-}
+HeapImpl::HeapImpl() : free_chunks_(), full_chunks_(), map_allocation_list_(NULL) {}
bool HeapImpl::Empty() {
for (unsigned int i = 0; i < kNumBuckets; i++) {
- for (LinkedList<Chunk*> *it = free_chunks_[i].next(); it->data() != NULL; it = it->next()) {
+ for (LinkedList<Chunk*>* it = free_chunks_[i].next(); it->data() != NULL; it = it->next()) {
if (!it->data()->Empty()) {
return false;
}
}
- for (LinkedList<Chunk*> *it = full_chunks_[i].next(); it->data() != NULL; it = it->next()) {
+ for (LinkedList<Chunk*>* it = full_chunks_[i].next(); it->data() != NULL; it = it->next()) {
if (!it->data()->Empty()) {
return false;
}
@@ -350,12 +340,12 @@
HeapImpl::~HeapImpl() {
for (unsigned int i = 0; i < kNumBuckets; i++) {
while (!free_chunks_[i].empty()) {
- Chunk *chunk = free_chunks_[i].next()->data();
+ Chunk* chunk = free_chunks_[i].next()->data();
chunk->node_.remove();
delete chunk;
}
while (!full_chunks_[i].empty()) {
- Chunk *chunk = full_chunks_[i].next()->data();
+ Chunk* chunk = full_chunks_[i].next()->data();
chunk->node_.remove();
delete chunk;
}
@@ -373,18 +363,18 @@
}
int bucket = size_to_bucket(size);
if (free_chunks_[bucket].empty()) {
- Chunk *chunk = new Chunk(this, bucket);
+ Chunk* chunk = new Chunk(this, bucket);
free_chunks_[bucket].insert(chunk->node_);
}
return free_chunks_[bucket].next()->data()->Alloc();
}
-void HeapImpl::Free(void *ptr) {
+void HeapImpl::Free(void* ptr) {
std::lock_guard<std::mutex> lk(m_);
FreeLocked(ptr);
}
-void HeapImpl::FreeLocked(void *ptr) {
+void HeapImpl::FreeLocked(void* ptr) {
if (!Chunk::is_chunk(ptr)) {
HeapImpl::MapFree(ptr);
} else {
@@ -397,12 +387,11 @@
void* HeapImpl::MapAlloc(size_t size) {
size = (size + kPageSize - 1) & ~(kPageSize - 1);
- MapAllocation* allocation = reinterpret_cast<MapAllocation*>(AllocLocked(
- sizeof(MapAllocation)));
+ MapAllocation* allocation = reinterpret_cast<MapAllocation*>(AllocLocked(sizeof(MapAllocation)));
void* ptr = MapAligned(size, kChunkSize);
if (!ptr) {
FreeLocked(allocation);
- abort(); //throw std::bad_alloc;
+ abort(); // throw std::bad_alloc;
}
allocation->ptr = ptr;
allocation->size = size;
@@ -412,10 +401,9 @@
return ptr;
}
-void HeapImpl::MapFree(void *ptr) {
- MapAllocation **allocation = &map_allocation_list_;
- while (*allocation && (*allocation)->ptr != ptr)
- allocation = &(*allocation)->next;
+void HeapImpl::MapFree(void* ptr) {
+ MapAllocation** allocation = &map_allocation_list_;
+ while (*allocation && (*allocation)->ptr != ptr) allocation = &(*allocation)->next;
assert(*allocation != nullptr);
@@ -425,22 +413,22 @@
*allocation = (*allocation)->next;
}
-void HeapImpl::MoveToFreeList(Chunk *chunk, int bucket) {
+void HeapImpl::MoveToFreeList(Chunk* chunk, int bucket) {
MoveToList(chunk, &free_chunks_[bucket]);
}
-void HeapImpl::MoveToFullList(Chunk *chunk, int bucket) {
+void HeapImpl::MoveToFullList(Chunk* chunk, int bucket) {
MoveToList(chunk, &full_chunks_[bucket]);
}
-void HeapImpl::MoveToList(Chunk *chunk, LinkedList<Chunk*>* head) {
+void HeapImpl::MoveToList(Chunk* chunk, LinkedList<Chunk*>* head) {
// Remove from old list
chunk->node_.remove();
- LinkedList<Chunk*> *node = head;
+ LinkedList<Chunk*>* node = head;
// Insert into new list, sorted by lowest free count
- while (node->next() != head && node->data() != nullptr
- && node->data()->free_count() < chunk->free_count())
+ while (node->next() != head && node->data() != nullptr &&
+ node->data()->free_count() < chunk->free_count())
node = node->next();
node->insert(chunk->node_);
@@ -469,10 +457,12 @@
impl_->Free(ptr);
}
-void Heap::deallocate(HeapImpl*impl, void* ptr) {
+void Heap::deallocate(HeapImpl* impl, void* ptr) {
impl->Free(ptr);
}
bool Heap::empty() {
return impl_->Empty();
}
+
+} // namespace android
diff --git a/libmemunreachable/Allocator.h b/libmemunreachable/Allocator.h
index 5390739..837a12b 100644
--- a/libmemunreachable/Allocator.h
+++ b/libmemunreachable/Allocator.h
@@ -27,18 +27,20 @@
#include <unordered_map>
#include <unordered_set>
#include <vector>
+
+namespace android {
+
extern std::atomic<int> heap_count;
class HeapImpl;
-template<typename T>
+template <typename T>
class Allocator;
-
// Non-templated class that implements wraps HeapImpl to keep
// implementation out of the header file
class Heap {
-public:
+ public:
Heap();
~Heap();
@@ -59,110 +61,99 @@
static void deallocate(HeapImpl* impl, void* ptr);
// Allocate a class of type T
- template<class T>
+ template <class T>
T* allocate() {
return reinterpret_cast<T*>(allocate(sizeof(T)));
}
// Comparators, copied objects will be equal
- bool operator ==(const Heap& other) const {
- return impl_ == other.impl_;
- }
- bool operator !=(const Heap& other) const {
- return !(*this == other);
- }
+ bool operator==(const Heap& other) const { return impl_ == other.impl_; }
+ bool operator!=(const Heap& other) const { return !(*this == other); }
// std::unique_ptr wrapper that allocates using allocate and deletes using
// deallocate
- template<class T>
+ template <class T>
using unique_ptr = std::unique_ptr<T, std::function<void(void*)>>;
- template<class T, class... Args>
+ template <class T, class... Args>
unique_ptr<T> make_unique(Args&&... args) {
HeapImpl* impl = impl_;
- return unique_ptr<T>(new (allocate<T>()) T(std::forward<Args>(args)...),
- [impl](void* ptr) {
- reinterpret_cast<T*>(ptr)->~T();
- deallocate(impl, ptr);
- });
+ return unique_ptr<T>(new (allocate<T>()) T(std::forward<Args>(args)...), [impl](void* ptr) {
+ reinterpret_cast<T*>(ptr)->~T();
+ deallocate(impl, ptr);
+ });
}
// std::unique_ptr wrapper that allocates using allocate and deletes using
// deallocate
- template<class T>
+ template <class T>
using shared_ptr = std::shared_ptr<T>;
- template<class T, class... Args>
+ template <class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);
-protected:
+ protected:
HeapImpl* impl_;
bool owns_impl_;
};
// STLAllocator implements the std allocator interface on top of a Heap
-template<typename T>
+template <typename T>
class STLAllocator {
-public:
+ public:
using value_type = T;
- ~STLAllocator() {
- }
+ ~STLAllocator() {}
// Construct an STLAllocator on top of a Heap
- STLAllocator(const Heap& heap) : // NOLINT, implicit
- heap_(heap) {
- }
+ STLAllocator(const Heap& heap)
+ : // NOLINT, implicit
+ heap_(heap) {}
// Rebind an STLAllocator from an another STLAllocator
- template<typename U>
- STLAllocator(const STLAllocator<U>& other) : // NOLINT, implicit
- heap_(other.heap_) {
- }
+ template <typename U>
+ STLAllocator(const STLAllocator<U>& other)
+ : // NOLINT, implicit
+ heap_(other.heap_) {}
STLAllocator(const STLAllocator&) = default;
STLAllocator<T>& operator=(const STLAllocator<T>&) = default;
- T* allocate(std::size_t n) {
- return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T)));
- }
+ T* allocate(std::size_t n) { return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T))); }
- void deallocate(T* ptr, std::size_t) {
- heap_.deallocate(ptr);
- }
+ void deallocate(T* ptr, std::size_t) { heap_.deallocate(ptr); }
- template<typename U>
- bool operator ==(const STLAllocator<U>& other) const {
+ template <typename U>
+ bool operator==(const STLAllocator<U>& other) const {
return heap_ == other.heap_;
}
- template<typename U>
- inline bool operator !=(const STLAllocator<U>& other) const {
+ template <typename U>
+ inline bool operator!=(const STLAllocator<U>& other) const {
return !(this == other);
}
- template<typename U>
+ template <typename U>
friend class STLAllocator;
-protected:
+ protected:
Heap heap_;
};
-
// Allocator extends STLAllocator with some convenience methods for allocating
// a single object and for constructing unique_ptr and shared_ptr objects with
// appropriate deleters.
-template<class T>
+template <class T>
class Allocator : public STLAllocator<T> {
public:
~Allocator() {}
- Allocator(const Heap& other) : // NOLINT, implicit
- STLAllocator<T>(other) {
- }
+ Allocator(const Heap& other)
+ : // NOLINT, implicit
+ STLAllocator<T>(other) {}
- template<typename U>
- Allocator(const STLAllocator<U>& other) : // NOLINT, implicit
- STLAllocator<T>(other) {
- }
+ template <typename U>
+ Allocator(const STLAllocator<U>& other)
+ : // NOLINT, implicit
+ STLAllocator<T>(other) {}
Allocator(const Allocator&) = default;
Allocator<T>& operator=(const Allocator<T>&) = default;
@@ -171,24 +162,20 @@
using STLAllocator<T>::deallocate;
using STLAllocator<T>::heap_;
- T* allocate() {
- return STLAllocator<T>::allocate(1);
- }
- void deallocate(void* ptr) {
- heap_.deallocate(ptr);
- }
+ T* allocate() { return STLAllocator<T>::allocate(1); }
+ void deallocate(void* ptr) { heap_.deallocate(ptr); }
using shared_ptr = Heap::shared_ptr<T>;
- template<class... Args>
- shared_ptr make_shared(Args&& ...args) {
+ template <class... Args>
+ shared_ptr make_shared(Args&&... args) {
return heap_.template make_shared<T>(std::forward<Args>(args)...);
}
using unique_ptr = Heap::unique_ptr<T>;
- template<class... Args>
- unique_ptr make_unique(Args&& ...args) {
+ template <class... Args>
+ unique_ptr make_unique(Args&&... args) {
return heap_.template make_unique<T>(std::forward<Args>(args)...);
}
};
@@ -196,33 +183,36 @@
// std::unique_ptr wrapper that allocates using allocate and deletes using
// deallocate. Implemented outside class definition in order to pass
// Allocator<T> to shared_ptr.
-template<class T, class... Args>
+template <class T, class... Args>
inline Heap::shared_ptr<T> Heap::make_shared(Args&&... args) {
return std::allocate_shared<T, Allocator<T>, Args...>(Allocator<T>(*this),
- std::forward<Args>(args)...);
+ std::forward<Args>(args)...);
}
namespace allocator {
-template<class T>
+template <class T>
using vector = std::vector<T, Allocator<T>>;
-template<class T>
+template <class T>
using list = std::list<T, Allocator<T>>;
-template<class Key, class T, class Compare = std::less<Key>>
+template <class Key, class T, class Compare = std::less<Key>>
using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>;
-template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
-using unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>;
+template <class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
+using unordered_map =
+ std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>;
-template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
+template <class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>;
-template<class Key, class Compare = std::less<Key>>
+template <class Key, class Compare = std::less<Key>>
using set = std::set<Key, Compare, Allocator<Key>>;
using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
}
+} // namespace android
+
#endif
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 4269eaa..cdac76b 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -23,7 +23,6 @@
cc_library_shared {
name: "libmemunreachable",
- vendor_available: true,
defaults: ["libmemunreachable_defaults"],
srcs: [
"Allocator.cpp",
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index c365ae5..2403ad0 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -28,6 +28,8 @@
#include "ScopedSignalHandler.h"
#include "log.h"
+namespace android {
+
bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
if (end == begin) {
end = begin + 1;
@@ -114,8 +116,8 @@
return true;
}
-bool HeapWalker::Leaked(allocator::vector<Range>& leaked, size_t limit,
- size_t* num_leaks_out, size_t* leak_bytes_out) {
+bool HeapWalker::Leaked(allocator::vector<Range>& leaked, size_t limit, size_t* num_leaks_out,
+ size_t* leak_bytes_out) {
leaked.clear();
size_t num_leaks = 0;
@@ -148,9 +150,9 @@
static bool MapOverPage(void* addr) {
const size_t page_size = sysconf(_SC_PAGE_SIZE);
- void *page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size-1));
+ void* page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size - 1));
- void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+ void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (ret == MAP_FAILED) {
MEM_ALOGE("failed to map page at %p: %s", page, strerror(errno));
return false;
@@ -159,7 +161,8 @@
return true;
}
-void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si, void* /*uctx*/) {
+void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si,
+ void* /*uctx*/) {
uintptr_t addr = reinterpret_cast<uintptr_t>(si->si_addr);
if (addr != walking_ptr_) {
handler.reset();
@@ -172,3 +175,5 @@
}
ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
+
+} // namespace android
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index b25696f..5c7ec13 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -25,6 +25,8 @@
#include "ScopedSignalHandler.h"
#include "Tarjan.h"
+namespace android {
+
// A range [begin, end)
struct Range {
uintptr_t begin;
@@ -34,31 +36,31 @@
bool operator==(const Range& other) const {
return this->begin == other.begin && this->end == other.end;
}
- bool operator!=(const Range& other) const {
- return !(*this == other);
- }
+ bool operator!=(const Range& other) const { return !(*this == other); }
};
// Comparator for Ranges that returns equivalence for overlapping ranges
struct compare_range {
- bool operator()(const Range& a, const Range& b) const {
- return a.end <= b.begin;
- }
+ bool operator()(const Range& a, const Range& b) const { return a.end <= b.begin; }
};
class HeapWalker {
public:
- explicit HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
- allocations_(allocator), allocation_bytes_(0),
- roots_(allocator), root_vals_(allocator),
- segv_handler_(allocator), walking_ptr_(0) {
+ explicit HeapWalker(Allocator<HeapWalker> allocator)
+ : allocator_(allocator),
+ allocations_(allocator),
+ allocation_bytes_(0),
+ roots_(allocator),
+ root_vals_(allocator),
+ segv_handler_(allocator),
+ walking_ptr_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
- segv_handler_.install(SIGSEGV,
- [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+ segv_handler_.install(
+ SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
this->HandleSegFault(handler, signal, siginfo, uctx);
- });
+ });
}
~HeapWalker() {}
@@ -68,15 +70,14 @@
bool DetectLeaks();
- bool Leaked(allocator::vector<Range>&, size_t limit, size_t* num_leaks,
- size_t* leak_bytes);
+ bool Leaked(allocator::vector<Range>&, size_t limit, size_t* num_leaks, size_t* leak_bytes);
size_t Allocations();
size_t AllocationBytes();
- template<class F>
+ template <class F>
void ForEachPtrInRange(const Range& range, F&& f);
- template<class F>
+ template <class F>
void ForEachAllocation(F&& f);
struct AllocationInfo {
@@ -84,7 +85,6 @@
};
private:
-
void RecurseRoot(const Range& root);
bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
@@ -103,7 +103,7 @@
uintptr_t walking_ptr_;
};
-template<class F>
+template <class F>
inline void HeapWalker::ForEachPtrInRange(const Range& range, F&& f) {
uintptr_t begin = (range.begin + (sizeof(uintptr_t) - 1)) & ~(sizeof(uintptr_t) - 1);
// TODO(ccross): we might need to consider a pointer to the end of a buffer
@@ -118,7 +118,7 @@
}
}
-template<class F>
+template <class F>
inline void HeapWalker::ForEachAllocation(F&& f) {
for (auto& it : allocations_) {
const Range& range = it.first;
@@ -127,4 +127,6 @@
}
}
+} // namespace android
+
#endif
diff --git a/libmemunreachable/Leak.h b/libmemunreachable/Leak.h
index eaeeea7..de64b64 100644
--- a/libmemunreachable/Leak.h
+++ b/libmemunreachable/Leak.h
@@ -26,9 +26,9 @@
// as a key in std::unordered_map.
namespace std {
-template<>
-struct hash<Leak::Backtrace> {
- std::size_t operator()(const Leak::Backtrace& key) const {
+template <>
+struct hash<android::Leak::Backtrace> {
+ std::size_t operator()(const android::Leak::Backtrace& key) const {
std::size_t seed = 0;
hash_combine(seed, key.num_frames);
@@ -40,7 +40,7 @@
}
private:
- template<typename T>
+ template <typename T>
inline void hash_combine(std::size_t& seed, const T& v) const {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
@@ -49,9 +49,12 @@
} // namespace std
+namespace android {
+
static bool operator==(const Leak::Backtrace& lhs, const Leak::Backtrace& rhs) {
return (lhs.num_frames == rhs.num_frames) &&
- memcmp(lhs.frames, rhs.frames, lhs.num_frames * sizeof(lhs.frames[0])) == 0;
+ memcmp(lhs.frames, rhs.frames, lhs.num_frames * sizeof(lhs.frames[0])) == 0;
+}
}
#endif
diff --git a/libmemunreachable/LeakFolding.cpp b/libmemunreachable/LeakFolding.cpp
index be4d20c..69f320c 100644
--- a/libmemunreachable/LeakFolding.cpp
+++ b/libmemunreachable/LeakFolding.cpp
@@ -22,6 +22,8 @@
#include "Tarjan.h"
#include "log.h"
+namespace android {
+
// Converts possibly cyclic graph of leaks to a DAG by combining
// strongly-connected components into a object, stored in the scc pointer
// of each node in the component.
@@ -31,11 +33,11 @@
Allocator<SCCInfo> scc_allocator = allocator_;
- for (auto& scc_nodes: scc_list) {
+ for (auto& scc_nodes : scc_list) {
Allocator<SCCInfo>::unique_ptr leak_scc;
leak_scc = scc_allocator.make_unique(scc_allocator);
- for (auto& node: scc_nodes) {
+ for (auto& node : scc_nodes) {
node->ptr->scc = leak_scc.get();
leak_scc->count++;
leak_scc->size += node->ptr->range.size();
@@ -46,7 +48,7 @@
for (auto& it : leak_map_) {
LeakInfo& leak = it.second;
- for (auto& ref: leak.node.references_out) {
+ for (auto& ref : leak.node.references_out) {
if (leak.scc != ref->ptr->scc) {
leak.scc->node.Edge(&ref->ptr->scc->node);
}
@@ -55,17 +57,14 @@
}
void LeakFolding::AccumulateLeaks(SCCInfo* dominator) {
- std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_,
- [&](SCCInfo* scc) {
- if (scc->accumulator != dominator) {
- scc->accumulator = dominator;
- dominator->cuumulative_size += scc->size;
- dominator->cuumulative_count += scc->count;
- scc->node.Foreach([&](SCCInfo* ref) {
- walk(ref);
- });
- }
- });
+ std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_, [&](SCCInfo* scc) {
+ if (scc->accumulator != dominator) {
+ scc->accumulator = dominator;
+ dominator->cuumulative_size += scc->size;
+ dominator->cuumulative_count += scc->count;
+ scc->node.Foreach([&](SCCInfo* ref) { walk(ref); });
+ }
+ });
walk(dominator);
}
@@ -73,27 +72,25 @@
Allocator<LeakInfo> leak_allocator = allocator_;
// Find all leaked allocations insert them into leak_map_ and leak_graph_
- heap_walker_.ForEachAllocation(
- [&](const Range& range, HeapWalker::AllocationInfo& allocation) {
- if (!allocation.referenced_from_root) {
- auto it = leak_map_.emplace(std::piecewise_construct,
- std::forward_as_tuple(range),
- std::forward_as_tuple(range, allocator_));
- LeakInfo& leak = it.first->second;
- leak_graph_.push_back(&leak.node);
- }
- });
+ heap_walker_.ForEachAllocation([&](const Range& range, HeapWalker::AllocationInfo& allocation) {
+ if (!allocation.referenced_from_root) {
+ auto it = leak_map_.emplace(std::piecewise_construct, std::forward_as_tuple(range),
+ std::forward_as_tuple(range, allocator_));
+ LeakInfo& leak = it.first->second;
+ leak_graph_.push_back(&leak.node);
+ }
+ });
// Find references between leaked allocations and connect them in leak_graph_
for (auto& it : leak_map_) {
LeakInfo& leak = it.second;
heap_walker_.ForEachPtrInRange(leak.range,
- [&](Range& ptr_range, HeapWalker::AllocationInfo* ptr_info) {
- if (!ptr_info->referenced_from_root) {
- LeakInfo* ptr_leak = &leak_map_.at(ptr_range);
- leak.node.Edge(&ptr_leak->node);
- }
- });
+ [&](Range& ptr_range, HeapWalker::AllocationInfo* ptr_info) {
+ if (!ptr_info->referenced_from_root) {
+ LeakInfo* ptr_leak = &leak_map_.at(ptr_range);
+ leak.node.Edge(&ptr_leak->node);
+ }
+ });
}
// Convert the cyclic graph to a DAG by grouping strongly connected components
@@ -110,8 +107,8 @@
return true;
}
-bool LeakFolding::Leaked(allocator::vector<LeakFolding::Leak>& leaked,
- size_t* num_leaks_out, size_t* leak_bytes_out) {
+bool LeakFolding::Leaked(allocator::vector<LeakFolding::Leak>& leaked, size_t* num_leaks_out,
+ size_t* leak_bytes_out) {
size_t num_leaks = 0;
size_t leak_bytes = 0;
for (auto& it : leak_map_) {
@@ -123,9 +120,8 @@
for (auto& it : leak_map_) {
const LeakInfo& leak = it.second;
if (leak.scc->dominator) {
- leaked.emplace_back(Leak{leak.range,
- leak.scc->cuumulative_count - 1,
- leak.scc->cuumulative_size - leak.range.size()});
+ leaked.emplace_back(Leak{leak.range, leak.scc->cuumulative_count - 1,
+ leak.scc->cuumulative_size - leak.range.size()});
}
}
@@ -138,3 +134,5 @@
return true;
}
+
+} // namespace android
diff --git a/libmemunreachable/LeakFolding.h b/libmemunreachable/LeakFolding.h
index 9c6a525..09affac 100644
--- a/libmemunreachable/LeakFolding.h
+++ b/libmemunreachable/LeakFolding.h
@@ -19,11 +19,16 @@
#include "HeapWalker.h"
+namespace android {
+
class LeakFolding {
public:
LeakFolding(Allocator<void> allocator, HeapWalker& heap_walker)
- : allocator_(allocator), heap_walker_(heap_walker),
- leak_map_(allocator), leak_graph_(allocator), leak_scc_(allocator) {}
+ : allocator_(allocator),
+ heap_walker_(heap_walker),
+ leak_map_(allocator),
+ leak_graph_(allocator),
+ leak_scc_(allocator) {}
bool FoldLeaks();
@@ -33,8 +38,7 @@
size_t referenced_size;
};
- bool Leaked(allocator::vector<Leak>& leaked,
- size_t* num_leaks_out, size_t* leak_bytes_out);
+ bool Leaked(allocator::vector<Leak>& leaked, size_t* num_leaks_out, size_t* leak_bytes_out);
private:
DISALLOW_COPY_AND_ASSIGN(LeakFolding);
@@ -54,9 +58,15 @@
bool dominator;
SCCInfo* accumulator;
- explicit SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
- count(0), size(0), cuumulative_count(0), cuumulative_size(0),
- dominator(false), accumulator(nullptr) {}
+ explicit SCCInfo(Allocator<SCCInfo> allocator)
+ : node(this, allocator),
+ count(0),
+ size(0),
+ cuumulative_count(0),
+ cuumulative_size(0),
+ dominator(false),
+ accumulator(nullptr) {}
+
private:
SCCInfo(SCCInfo&&) = delete;
DISALLOW_COPY_AND_ASSIGN(SCCInfo);
@@ -71,8 +81,7 @@
SCCInfo* scc;
LeakInfo(const Range& range, Allocator<LeakInfo> allocator)
- : node(this, allocator), range(range),
- scc(nullptr) {}
+ : node(this, allocator), range(range), scc(nullptr) {}
private:
DISALLOW_COPY_AND_ASSIGN(LeakInfo);
@@ -86,4 +95,6 @@
allocator::vector<Allocator<SCCInfo>::unique_ptr> leak_scc_;
};
-#endif // LIBMEMUNREACHABLE_LEAK_FOLDING_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_LEAK_FOLDING_H_
diff --git a/libmemunreachable/LeakPipe.cpp b/libmemunreachable/LeakPipe.cpp
index 78117e2..8ea9ad6 100644
--- a/libmemunreachable/LeakPipe.cpp
+++ b/libmemunreachable/LeakPipe.cpp
@@ -21,9 +21,11 @@
#include "log.h"
+namespace android {
+
bool LeakPipe::SendFd(int sock, int fd) {
- struct msghdr hdr{};
- struct iovec iov{};
+ struct msghdr hdr {};
+ struct iovec iov {};
unsigned int data = 0xfdfdfdfd;
alignas(struct cmsghdr) char cmsgbuf[CMSG_SPACE(sizeof(int))];
@@ -56,8 +58,8 @@
}
int LeakPipe::ReceiveFd(int sock) {
- struct msghdr hdr{};
- struct iovec iov{};
+ struct msghdr hdr {};
+ struct iovec iov {};
unsigned int data;
alignas(struct cmsghdr) char cmsgbuf[CMSG_SPACE(sizeof(int))];
@@ -87,3 +89,5 @@
return *(int*)CMSG_DATA(cmsg);
}
+
+} // namespace android
diff --git a/libmemunreachable/LeakPipe.h b/libmemunreachable/LeakPipe.h
index 3ea2d8f..94d4aa4 100644
--- a/libmemunreachable/LeakPipe.h
+++ b/libmemunreachable/LeakPipe.h
@@ -26,6 +26,8 @@
#include "ScopedPipe.h"
#include "log.h"
+namespace android {
+
// LeakPipe implements a pipe that can transfer vectors of simple objects
// between processes. The pipe is created in the sending process and
// transferred over a socketpair that was created before forking. This ensures
@@ -34,15 +36,13 @@
class LeakPipe {
public:
LeakPipe() {
- int ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv_);
+ int ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv_);
if (ret < 0) {
MEM_LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
}
}
- ~LeakPipe() {
- Close();
- }
+ ~LeakPipe() { Close(); }
void Close() {
close(sv_[0]);
@@ -77,13 +77,9 @@
public:
LeakPipeBase() : fd_(-1) {}
- ~LeakPipeBase() {
- Close();
- }
+ ~LeakPipeBase() { Close(); }
- void SetFd(int fd) {
- fd_ = fd;
- }
+ void SetFd(int fd) { fd_ = fd; }
void Close() {
close(fd_);
@@ -101,7 +97,7 @@
public:
using LeakPipeBase::LeakPipeBase;
- template<typename T>
+ template <typename T>
bool Send(const T& value) {
ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
if (ret < 0) {
@@ -115,7 +111,7 @@
return true;
}
- template<class T, class Alloc = std::allocator<T>>
+ template <class T, class Alloc = std::allocator<T>>
bool SendVector(const std::vector<T, Alloc>& vector) {
size_t size = vector.size() * sizeof(T);
if (!Send(size)) {
@@ -139,7 +135,7 @@
public:
using LeakPipeBase::LeakPipeBase;
- template<typename T>
+ template <typename T>
bool Receive(T* value) {
ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
if (ret < 0) {
@@ -153,7 +149,7 @@
return true;
}
- template<class T, class Alloc = std::allocator<T>>
+ template <class T, class Alloc = std::allocator<T>>
bool ReceiveVector(std::vector<T, Alloc>& vector) {
size_t size = 0;
if (!Receive(&size)) {
@@ -178,16 +174,11 @@
return true;
}
-
};
- LeakPipeReceiver& Receiver() {
- return receiver_;
- }
+ LeakPipeReceiver& Receiver() { return receiver_; }
- LeakPipeSender& Sender() {
- return sender_;
- }
+ LeakPipeSender& Sender() { return sender_; }
private:
LeakPipeReceiver receiver_;
@@ -198,4 +189,6 @@
int sv_[2];
};
-#endif // LIBMEMUNREACHABLE_LEAK_PIPE_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_LEAK_PIPE_H_
diff --git a/libmemunreachable/LineBuffer.cpp b/libmemunreachable/LineBuffer.cpp
index d3580c0..4ea0542 100644
--- a/libmemunreachable/LineBuffer.cpp
+++ b/libmemunreachable/LineBuffer.cpp
@@ -23,8 +23,10 @@
#include "LineBuffer.h"
-LineBuffer::LineBuffer(int fd, char* buffer, size_t buffer_len) : fd_(fd), buffer_(buffer), buffer_len_(buffer_len) {
-}
+namespace android {
+
+LineBuffer::LineBuffer(int fd, char* buffer, size_t buffer_len)
+ : fd_(fd), buffer_(buffer), buffer_len_(buffer_len) {}
bool LineBuffer::GetLine(char** line, size_t* line_len) {
while (true) {
@@ -60,3 +62,5 @@
bytes_ += bytes;
}
}
+
+} // namespace android
diff --git a/libmemunreachable/LineBuffer.h b/libmemunreachable/LineBuffer.h
index a015c46..cc6cd0c 100644
--- a/libmemunreachable/LineBuffer.h
+++ b/libmemunreachable/LineBuffer.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace android {
+
class LineBuffer {
public:
LineBuffer(int fd, char* buffer, size_t buffer_len);
@@ -33,4 +35,6 @@
size_t bytes_ = 0;
};
-#endif // _LIBMEMUNREACHABLE_LINE_BUFFER_H
+} // namespace android
+
+#endif // _LIBMEMUNREACHABLE_LINE_BUFFER_H
diff --git a/libmemunreachable/LinkedList.h b/libmemunreachable/LinkedList.h
index 132842d..36fe9fd 100644
--- a/libmemunreachable/LinkedList.h
+++ b/libmemunreachable/LinkedList.h
@@ -17,44 +17,47 @@
#ifndef LIBMEMUNREACHABLE_LINKED_LIST_H_
#define LIBMEMUNREACHABLE_LINKED_LIST_H_
-template<class T>
+namespace android {
+
+template <class T>
class LinkedList {
-public:
- LinkedList() : next_(this), prev_(this), data_() {}
- explicit LinkedList(T data) : LinkedList() {
- data_ = data;
- }
- ~LinkedList() {}
- void insert(LinkedList<T>& node) {
- assert(node.empty());
- node.next_ = this->next_;
- node.next_->prev_ = &node;
- this->next_ = &node;
- node.prev_ = this;
- }
- void remove() {
- this->next_->prev_ = this->prev_;
- this->prev_->next_ = this->next_;
- this->next_ = this;
- this->prev_ = this;
- }
- T data() { return data_; }
- bool empty() { return next_ == this && prev_ == this; }
- LinkedList<T> *next() { return next_; }
-private:
- LinkedList<T> *next_;
- LinkedList<T> *prev_;
- T data_;
+ public:
+ LinkedList() : next_(this), prev_(this), data_() {}
+ explicit LinkedList(T data) : LinkedList() { data_ = data; }
+ ~LinkedList() {}
+ void insert(LinkedList<T>& node) {
+ assert(node.empty());
+ node.next_ = this->next_;
+ node.next_->prev_ = &node;
+ this->next_ = &node;
+ node.prev_ = this;
+ }
+ void remove() {
+ this->next_->prev_ = this->prev_;
+ this->prev_->next_ = this->next_;
+ this->next_ = this;
+ this->prev_ = this;
+ }
+ T data() { return data_; }
+ bool empty() { return next_ == this && prev_ == this; }
+ LinkedList<T>* next() { return next_; }
+
+ private:
+ LinkedList<T>* next_;
+ LinkedList<T>* prev_;
+ T data_;
};
-template<class T>
+template <class T>
class LinkedListHead {
-public:
- LinkedListHead() : node_() {}
- ~LinkedListHead() {}
+ public:
+ LinkedListHead() : node_() {}
+ ~LinkedListHead() {}
-private:
- LinkedList<T> node_;
+ private:
+ LinkedList<T> node_;
};
+} // namespace android
+
#endif
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index 1c84744..a1f74c3 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -15,16 +15,17 @@
*/
#include <inttypes.h>
+#include <string.h>
#include <functional>
#include <iomanip>
#include <mutex>
-#include <string>
#include <sstream>
+#include <string>
#include <unordered_map>
-#include <backtrace.h>
#include <android-base/macros.h>
+#include <backtrace.h>
#include "Allocator.h"
#include "HeapWalker.h"
@@ -37,30 +38,33 @@
#include "Semaphore.h"
#include "ThreadCapture.h"
-#include "memunreachable/memunreachable.h"
#include "bionic.h"
#include "log.h"
-
-const size_t Leak::contents_length;
+#include "memunreachable/memunreachable.h"
using namespace std::chrono_literals;
+namespace android {
+
+const size_t Leak::contents_length;
+
class MemUnreachable {
public:
- MemUnreachable(pid_t pid, Allocator<void> allocator) : pid_(pid), allocator_(allocator),
- heap_walker_(allocator_) {}
+ MemUnreachable(pid_t pid, Allocator<void> allocator)
+ : pid_(pid), allocator_(allocator), heap_walker_(allocator_) {}
bool CollectAllocations(const allocator::vector<ThreadInfo>& threads,
- const allocator::vector<Mapping>& mappings);
- bool GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit,
- size_t* num_leaks, size_t* leak_bytes);
+ const allocator::vector<Mapping>& mappings);
+ bool GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit, size_t* num_leaks,
+ size_t* leak_bytes);
size_t Allocations() { return heap_walker_.Allocations(); }
size_t AllocationBytes() { return heap_walker_.AllocationBytes(); }
+
private:
bool ClassifyMappings(const allocator::vector<Mapping>& mappings,
- allocator::vector<Mapping>& heap_mappings,
- allocator::vector<Mapping>& anon_mappings,
- allocator::vector<Mapping>& globals_mappings,
- allocator::vector<Mapping>& stack_mappings);
+ allocator::vector<Mapping>& heap_mappings,
+ allocator::vector<Mapping>& anon_mappings,
+ allocator::vector<Mapping>& globals_mappings,
+ allocator::vector<Mapping>& stack_mappings);
DISALLOW_COPY_AND_ASSIGN(MemUnreachable);
pid_t pid_;
Allocator<void> allocator_;
@@ -68,16 +72,17 @@
};
static void HeapIterate(const Mapping& heap_mapping,
- const std::function<void(uintptr_t, size_t)>& func) {
+ const std::function<void(uintptr_t, size_t)>& func) {
malloc_iterate(heap_mapping.begin, heap_mapping.end - heap_mapping.begin,
- [](uintptr_t base, size_t size, void* arg) {
- auto f = reinterpret_cast<const std::function<void(uintptr_t, size_t)>*>(arg);
- (*f)(base, size);
- }, const_cast<void*>(reinterpret_cast<const void*>(&func)));
+ [](uintptr_t base, size_t size, void* arg) {
+ auto f = reinterpret_cast<const std::function<void(uintptr_t, size_t)>*>(arg);
+ (*f)(base, size);
+ },
+ const_cast<void*>(reinterpret_cast<const void*>(&func)));
}
bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
- const allocator::vector<Mapping>& mappings) {
+ const allocator::vector<Mapping>& mappings) {
MEM_ALOGI("searching process %d for allocations", pid_);
allocator::vector<Mapping> heap_mappings{mappings};
allocator::vector<Mapping> anon_mappings{mappings};
@@ -118,8 +123,8 @@
return true;
}
-bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks,
- size_t limit, size_t* num_leaks, size_t* leak_bytes) {
+bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit,
+ size_t* num_leaks, size_t* leak_bytes) {
MEM_ALOGI("sweeping process %d for unreachable memory", pid_);
leaks.clear();
@@ -127,7 +132,6 @@
return false;
}
-
allocator::vector<Range> leaked1{allocator_};
heap_walker_.Leaked(leaked1, 0, num_leaks, leak_bytes);
@@ -152,12 +156,12 @@
// in backtrace_map.
leaks.reserve(leaked.size());
- for (auto& it: leaked) {
+ for (auto& it : leaked) {
leaks.emplace_back();
Leak* leak = &leaks.back();
- ssize_t num_backtrace_frames = malloc_backtrace(reinterpret_cast<void*>(it.range.begin),
- leak->backtrace.frames, leak->backtrace.max_frames);
+ ssize_t num_backtrace_frames = malloc_backtrace(
+ reinterpret_cast<void*>(it.range.begin), leak->backtrace.frames, leak->backtrace.max_frames);
if (num_backtrace_frames > 0) {
leak->backtrace.num_frames = num_backtrace_frames;
@@ -183,14 +187,13 @@
leak->referenced_size = it.referenced_size;
leak->total_size = leak->size + leak->referenced_size;
memcpy(leak->contents, reinterpret_cast<void*>(it.range.begin),
- std::min(leak->size, Leak::contents_length));
+ std::min(leak->size, Leak::contents_length));
}
MEM_ALOGI("folding done");
- std::sort(leaks.begin(), leaks.end(), [](const Leak& a, const Leak& b) {
- return a.total_size > b.total_size;
- });
+ std::sort(leaks.begin(), leaks.end(),
+ [](const Leak& a, const Leak& b) { return a.total_size > b.total_size; });
if (leaks.size() > limit) {
leaks.resize(limit);
@@ -205,11 +208,10 @@
}
bool MemUnreachable::ClassifyMappings(const allocator::vector<Mapping>& mappings,
- allocator::vector<Mapping>& heap_mappings,
- allocator::vector<Mapping>& anon_mappings,
- allocator::vector<Mapping>& globals_mappings,
- allocator::vector<Mapping>& stack_mappings)
-{
+ allocator::vector<Mapping>& heap_mappings,
+ allocator::vector<Mapping>& anon_mappings,
+ allocator::vector<Mapping>& globals_mappings,
+ allocator::vector<Mapping>& stack_mappings) {
heap_mappings.clear();
anon_mappings.clear();
globals_mappings.clear();
@@ -245,7 +247,8 @@
stack_mappings.emplace_back(*it);
} else if (mapping_name.size() == 0) {
globals_mappings.emplace_back(*it);
- } else if (has_prefix(mapping_name, "[anon:") && mapping_name != "[anon:leak_detector_malloc]") {
+ } else if (has_prefix(mapping_name, "[anon:") &&
+ mapping_name != "[anon:leak_detector_malloc]") {
// TODO(ccross): it would be nice to treat named anonymous mappings as
// possible leaks, but naming something in a .bss or .data section makes
// it impossible to distinguish them from mmaped and then named mappings.
@@ -256,7 +259,7 @@
return true;
}
-template<typename T>
+template <typename T>
static inline const char* plural(T val) {
return (val == 1) ? "" : "s";
}
@@ -403,7 +406,6 @@
}
std::string Leak::ToString(bool log_contents) const {
-
std::ostringstream oss;
oss << " " << std::dec << size;
@@ -492,8 +494,8 @@
oss << std::endl;
for (auto it = leaks.begin(); it != leaks.end(); it++) {
- oss << it->ToString(log_contents);
- oss << std::endl;
+ oss << it->ToString(log_contents);
+ oss << std::endl;
}
return oss.str();
@@ -511,9 +513,11 @@
return info.ToString(log_contents);
}
+} // namespace android
+
bool LogUnreachableMemory(bool log_contents, size_t limit) {
- UnreachableMemoryInfo info;
- if (!GetUnreachableMemory(info, limit)) {
+ android::UnreachableMemoryInfo info;
+ if (!android::GetUnreachableMemory(info, limit)) {
return false;
}
@@ -523,10 +527,9 @@
return true;
}
-
bool NoLeaks() {
- UnreachableMemoryInfo info;
- if (!GetUnreachableMemory(info, 0)) {
+ android::UnreachableMemoryInfo info;
+ if (!android::GetUnreachableMemory(info, 0)) {
return false;
}
diff --git a/libmemunreachable/ProcessMappings.cpp b/libmemunreachable/ProcessMappings.cpp
index 57b2321..9a06870 100644
--- a/libmemunreachable/ProcessMappings.cpp
+++ b/libmemunreachable/ProcessMappings.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <inttypes.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <string.h>
#include <unistd.h>
@@ -25,6 +25,8 @@
#include "ProcessMappings.h"
#include "log.h"
+namespace android {
+
// This function is not re-entrant since it uses a static buffer for
// the line data.
bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
@@ -42,8 +44,8 @@
int name_pos;
char perms[5];
Mapping mapping{};
- if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %*x %*x:%*x %*d %n",
- &mapping.begin, &mapping.end, perms, &name_pos) == 3) {
+ if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %*x %*x:%*x %*d %n", &mapping.begin,
+ &mapping.end, perms, &name_pos) == 3) {
if (perms[0] == 'r') {
mapping.read = true;
}
@@ -64,3 +66,5 @@
}
return true;
}
+
+} // namespace android
diff --git a/libmemunreachable/ProcessMappings.h b/libmemunreachable/ProcessMappings.h
index d3b7496..a0e97e9 100644
--- a/libmemunreachable/ProcessMappings.h
+++ b/libmemunreachable/ProcessMappings.h
@@ -19,6 +19,8 @@
#include "Allocator.h"
+namespace android {
+
struct Mapping {
uintptr_t begin;
uintptr_t end;
@@ -33,4 +35,6 @@
// the line data.
bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings);
-#endif // LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index 73b0493..aca2a82 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -23,17 +23,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <unistd.h>
#include "android-base/macros.h"
+#include "PtracerThread.h"
#include "anon_vma_naming.h"
#include "log.h"
-#include "PtracerThread.h"
+
+namespace android {
class Stack {
public:
@@ -41,7 +43,7 @@
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
page_size_ = sysconf(_SC_PAGE_SIZE);
- size_ += page_size_*2; // guard pages
+ size_ += page_size_ * 2; // guard pages
base_ = mmap(NULL, size_, prot, flags, -1, 0);
if (base_ == MAP_FAILED) {
base_ = NULL;
@@ -52,22 +54,20 @@
mprotect(base_, page_size_, PROT_NONE);
mprotect(top(), page_size_, PROT_NONE);
};
- ~Stack() {
- munmap(base_, size_);
- };
+ ~Stack() { munmap(base_, size_); };
void* top() {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base_) + size_ - page_size_);
};
+
private:
DISALLOW_COPY_AND_ASSIGN(Stack);
- void *base_;
+ void* base_;
size_t size_;
size_t page_size_;
};
-PtracerThread::PtracerThread(const std::function<int()>& func) :
- child_pid_(0) {
+PtracerThread::PtracerThread(const std::function<int()>& func) : child_pid_(0) {
stack_ = std::make_unique<Stack>(PTHREAD_STACK_MIN);
if (stack_->top() == nullptr) {
MEM_LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
@@ -93,14 +93,13 @@
std::unique_lock<std::mutex> lk(m_);
// Convert from void(*)(void*) to lambda with captures
- auto proxy = [](void *arg) -> int {
+ auto proxy = [](void* arg) -> int {
prctl(PR_SET_NAME, "libmemunreachable ptrace thread");
return (*reinterpret_cast<std::function<int()>*>(arg))();
};
- child_pid_ = clone(proxy, stack_->top(),
- CLONE_VM|CLONE_FS|CLONE_FILES/*|CLONE_UNTRACED*/,
- reinterpret_cast<void*>(&func_));
+ child_pid_ = clone(proxy, stack_->top(), CLONE_VM | CLONE_FS | CLONE_FILES /*|CLONE_UNTRACED*/,
+ reinterpret_cast<void*>(&func_));
if (child_pid_ < 0) {
MEM_ALOGE("failed to clone child: %s", strerror(errno));
return false;
@@ -151,3 +150,5 @@
void PtracerThread::ClearTracer() {
prctl(PR_SET_PTRACER, 0);
}
+
+} // namespace android
diff --git a/libmemunreachable/PtracerThread.h b/libmemunreachable/PtracerThread.h
index f88b599..4f9c420 100644
--- a/libmemunreachable/PtracerThread.h
+++ b/libmemunreachable/PtracerThread.h
@@ -24,6 +24,8 @@
#include "Allocator.h"
+namespace android {
+
class Stack;
// PtracerThread is similar to std::thread, except that it creates a "thread"
@@ -36,6 +38,7 @@
~PtracerThread();
bool Start();
int Join();
+
private:
void SetTracer(pid_t);
void ClearTracer();
@@ -47,4 +50,6 @@
pid_t child_pid_;
};
-#endif // LIBMEMUNREACHABLE_PTRACER_THREAD_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_PTRACER_THREAD_H_
diff --git a/libmemunreachable/ScopedAlarm.h b/libmemunreachable/ScopedAlarm.h
index 287f479..bb50b9e 100644
--- a/libmemunreachable/ScopedAlarm.h
+++ b/libmemunreachable/ScopedAlarm.h
@@ -23,15 +23,15 @@
#include <chrono>
#include <functional>
+namespace android {
+
class ScopedAlarm {
public:
ScopedAlarm(std::chrono::microseconds us, std::function<void()> func) {
func_ = func;
- struct sigaction oldact{};
- struct sigaction act{};
- act.sa_handler = [](int) {
- ScopedAlarm::func_();
- };
+ struct sigaction oldact {};
+ struct sigaction act {};
+ act.sa_handler = [](int) { ScopedAlarm::func_(); };
sigaction(SIGALRM, &act, &oldact);
std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(us);
@@ -43,11 +43,15 @@
~ScopedAlarm() {
itimerval t = itimerval{};
setitimer(ITIMER_REAL, &t, NULL);
- struct sigaction act{};
+ struct sigaction act {};
act.sa_handler = SIG_DFL;
sigaction(SIGALRM, &act, NULL);
}
+
private:
static std::function<void()> func_;
};
+
+} // namespace android
+
#endif
diff --git a/libmemunreachable/ScopedDisableMalloc.h b/libmemunreachable/ScopedDisableMalloc.h
index 758d317..655e826 100644
--- a/libmemunreachable/ScopedDisableMalloc.h
+++ b/libmemunreachable/ScopedDisableMalloc.h
@@ -21,16 +21,16 @@
#include "android-base/macros.h"
+#include "ScopedAlarm.h"
#include "bionic.h"
#include "log.h"
-#include "ScopedAlarm.h"
-class DisableMallocGuard{
+namespace android {
+
+class DisableMallocGuard {
public:
- DisableMallocGuard() : disabled_(false){}
- ~DisableMallocGuard() {
- Enable();
- }
+ DisableMallocGuard() : disabled_(false) {}
+ ~DisableMallocGuard() { Enable(); }
void Disable() {
if (!disabled_) {
@@ -45,6 +45,7 @@
disabled_ = false;
}
}
+
private:
DISALLOW_COPY_AND_ASSIGN(DisableMallocGuard);
bool disabled_;
@@ -59,13 +60,9 @@
// here.
class ScopedDisableMalloc {
public:
- ScopedDisableMalloc() {
- disable_malloc_.Disable();
- }
+ ScopedDisableMalloc() { disable_malloc_.Disable(); }
- ~ScopedDisableMalloc() {
- disable_malloc_.Enable();
- }
+ ~ScopedDisableMalloc() { disable_malloc_.Enable(); }
private:
DISALLOW_COPY_AND_ASSIGN(ScopedDisableMalloc);
@@ -74,18 +71,15 @@
class ScopedDisableMallocTimeout {
public:
- explicit ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) :
- timeout_(timeout), timed_out_(false), disable_malloc_() {
+ explicit ScopedDisableMallocTimeout(
+ std::chrono::milliseconds timeout = std::chrono::milliseconds(2000))
+ : timeout_(timeout), timed_out_(false), disable_malloc_() {
Disable();
}
- ~ScopedDisableMallocTimeout() {
- Enable();
- }
+ ~ScopedDisableMallocTimeout() { Enable(); }
- bool timed_out() {
- return timed_out_;
- }
+ bool timed_out() { return timed_out_; }
void Enable() {
disable_malloc_.Enable();
@@ -110,4 +104,6 @@
DisableMallocGuard disable_malloc_;
};
-#endif // LIBMEMUNREACHABLE_SCOPED_DISABLE_MALLOC_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_SCOPED_DISABLE_MALLOC_H_
diff --git a/libmemunreachable/ScopedPipe.h b/libmemunreachable/ScopedPipe.h
index 7f44953..adabfd8 100644
--- a/libmemunreachable/ScopedPipe.h
+++ b/libmemunreachable/ScopedPipe.h
@@ -21,6 +21,8 @@
#include "log.h"
+namespace android {
+
class ScopedPipe {
public:
ScopedPipe() : pipefd_{-1, -1} {
@@ -29,28 +31,22 @@
MEM_LOG_ALWAYS_FATAL("failed to open pipe");
}
}
- ~ScopedPipe() {
- Close();
- }
+ ~ScopedPipe() { Close(); }
ScopedPipe(ScopedPipe&& other) {
SetReceiver(other.ReleaseReceiver());
SetSender(other.ReleaseSender());
}
- ScopedPipe& operator = (ScopedPipe&& other) {
+ ScopedPipe& operator=(ScopedPipe&& other) {
SetReceiver(other.ReleaseReceiver());
SetSender(other.ReleaseSender());
return *this;
}
- void CloseReceiver() {
- close(ReleaseReceiver());
- }
+ void CloseReceiver() { close(ReleaseReceiver()); }
- void CloseSender() {
- close(ReleaseSender());
- }
+ void CloseSender() { close(ReleaseSender()); }
void Close() {
CloseReceiver();
@@ -78,4 +74,7 @@
int pipefd_[2];
};
+
+} // namespace android
+
#endif
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index ada2ae4..f62f368 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -26,18 +26,18 @@
#include "log.h"
+namespace android {
+
class ScopedSignalHandler {
public:
using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
explicit ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
- ~ScopedSignalHandler() {
- reset();
- }
+ ~ScopedSignalHandler() { reset(); }
template <class F>
void install(int signal, F&& f) {
- MEM_LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+ if (signal != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
handler_ = SignalFn(std::allocator_arg, allocator_,
[=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
@@ -65,7 +65,6 @@
}
}
-
private:
using SignalFn = std::function<void(int, siginfo_t*, void*)>;
DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
@@ -77,4 +76,6 @@
static SignalFn handler_;
};
-#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
diff --git a/libmemunreachable/Semaphore.h b/libmemunreachable/Semaphore.h
index 6bcf4ea..cd73972 100644
--- a/libmemunreachable/Semaphore.h
+++ b/libmemunreachable/Semaphore.h
@@ -22,6 +22,8 @@
#include "android-base/macros.h"
+namespace android {
+
class Semaphore {
public:
explicit Semaphore(int count = 0) : count_(count) {}
@@ -29,7 +31,7 @@
void Wait(std::chrono::milliseconds ms) {
std::unique_lock<std::mutex> lk(m_);
- cv_.wait_for(lk, ms, [&]{
+ cv_.wait_for(lk, ms, [&] {
if (count_ > 0) {
count_--;
return true;
@@ -44,6 +46,7 @@
}
cv_.notify_one();
}
+
private:
DISALLOW_COPY_AND_ASSIGN(Semaphore);
@@ -52,5 +55,6 @@
std::condition_variable cv_;
};
+} // namespace android
-#endif // LIBMEMUNREACHABLE_SEMAPHORE_H_
+#endif // LIBMEMUNREACHABLE_SEMAPHORE_H_
diff --git a/libmemunreachable/Tarjan.h b/libmemunreachable/Tarjan.h
index 2546341..355679f 100644
--- a/libmemunreachable/Tarjan.h
+++ b/libmemunreachable/Tarjan.h
@@ -24,7 +24,9 @@
#include "Allocator.h"
-template<class T>
+namespace android {
+
+template <class T>
class Node {
public:
allocator::set<Node<T>*> references_in;
@@ -34,39 +36,41 @@
T* ptr;
- Node(T* ptr, Allocator<Node> allocator) : references_in(allocator), references_out(allocator),
- ptr(ptr) {};
+ Node(T* ptr, Allocator<Node> allocator)
+ : references_in(allocator), references_out(allocator), ptr(ptr){};
Node(Node&& rhs) = default;
void Edge(Node<T>* ref) {
references_out.emplace(ref);
ref->references_in.emplace(this);
}
- template<class F>
+ template <class F>
void Foreach(F&& f) {
- for (auto& node: references_out) {
+ for (auto& node : references_out) {
f(node->ptr);
}
}
+
private:
DISALLOW_COPY_AND_ASSIGN(Node<T>);
};
-template<class T>
+template <class T>
using Graph = allocator::vector<Node<T>*>;
-template<class T>
+template <class T>
using SCC = allocator::vector<Node<T>*>;
-template<class T>
+template <class T>
using SCCList = allocator::vector<SCC<T>>;
-template<class T>
+template <class T>
class TarjanAlgorithm {
public:
- explicit TarjanAlgorithm(Allocator<void> allocator) : index_(0),
- stack_(allocator), components_(allocator) {}
+ explicit TarjanAlgorithm(Allocator<void> allocator)
+ : index_(0), stack_(allocator), components_(allocator) {}
void Execute(Graph<T>& graph, SCCList<T>& out);
+
private:
static constexpr size_t UNDEFINED_INDEX = static_cast<size_t>(-1);
void Tarjan(Node<T>* vertex, Graph<T>& graph);
@@ -76,17 +80,17 @@
SCCList<T> components_;
};
-template<class T>
+template <class T>
void TarjanAlgorithm<T>::Execute(Graph<T>& graph, SCCList<T>& out) {
stack_.clear();
components_.clear();
index_ = 0;
- for (auto& it: graph) {
+ for (auto& it : graph) {
it->index = UNDEFINED_INDEX;
it->lowlink = UNDEFINED_INDEX;
}
- for (auto& it: graph) {
+ for (auto& it : graph) {
if (it->index == UNDEFINED_INDEX) {
Tarjan(it, graph);
}
@@ -94,14 +98,14 @@
out.swap(components_);
}
-template<class T>
+template <class T>
void TarjanAlgorithm<T>::Tarjan(Node<T>* vertex, Graph<T>& graph) {
assert(vertex->index == UNDEFINED_INDEX);
vertex->index = index_;
vertex->lowlink = index_;
index_++;
stack_.push_back(vertex);
- for (auto& it: vertex->references_out) {
+ for (auto& it : vertex->references_out) {
Node<T>* vertex_next = it;
if (vertex_next->index == UNDEFINED_INDEX) {
Tarjan(vertex_next, graph);
@@ -123,10 +127,12 @@
}
}
-template<class T>
+template <class T>
void Tarjan(Graph<T>& graph, SCCList<T>& out) {
TarjanAlgorithm<T> tarjan{graph.get_allocator()};
tarjan.Execute(graph, out);
}
-#endif // LIBMEMUNREACHABLE_TARJAN_H_
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_TARJAN_H_
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index 3891f2d..45eb55d 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -21,13 +21,13 @@
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
-#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
+#include <unistd.h>
#include <map>
#include <memory>
@@ -39,6 +39,8 @@
#include "Allocator.h"
#include "log.h"
+namespace android {
+
// bionic interfaces used:
// atoi
// strlcat
@@ -50,12 +52,12 @@
// Convert a pid > 0 to a string. sprintf might allocate, so we can't use it.
// Returns a pointer somewhere in buf to a null terminated string, or NULL
// on error.
-static char *pid_to_str(char *buf, size_t len, pid_t pid) {
+static char* pid_to_str(char* buf, size_t len, pid_t pid) {
if (pid <= 0) {
return nullptr;
}
- char *ptr = buf + len - 1;
+ char* ptr = buf + len - 1;
*ptr = 0;
while (pid > 0) {
ptr--;
@@ -79,6 +81,7 @@
bool ReleaseThread(pid_t tid);
bool CapturedThreadInfo(ThreadInfoList& threads);
void InjectTestFunc(std::function<void(pid_t)>&& f) { inject_test_func_ = f; }
+
private:
int CaptureThread(pid_t tid);
bool ReleaseThread(pid_t tid, unsigned int signal);
@@ -92,9 +95,8 @@
std::function<void(pid_t)> inject_test_func_;
};
-ThreadCaptureImpl::ThreadCaptureImpl(pid_t pid, Allocator<ThreadCaptureImpl>& allocator) :
- captured_threads_(allocator), allocator_(allocator), pid_(pid) {
-}
+ThreadCaptureImpl::ThreadCaptureImpl(pid_t pid, Allocator<ThreadCaptureImpl>& allocator)
+ : captured_threads_(allocator), allocator_(allocator), pid_(pid) {}
bool ThreadCaptureImpl::ListThreads(TidList& tids) {
tids.clear();
@@ -115,11 +117,11 @@
}
struct linux_dirent64 {
- uint64_t d_ino;
- int64_t d_off;
- uint16_t d_reclen;
- char d_type;
- char d_name[];
+ uint64_t d_ino;
+ int64_t d_off;
+ uint16_t d_reclen;
+ char d_type;
+ char d_name[];
} __attribute((packed));
char dirent_buf[4096];
ssize_t nread;
@@ -209,7 +211,7 @@
bool ThreadCaptureImpl::PtraceThreadInfo(pid_t tid, ThreadInfo& thread_info) {
thread_info.tid = tid;
- const unsigned int max_num_regs = 128; // larger than number of registers on any device
+ const unsigned int max_num_regs = 128; // larger than number of registers on any device
uintptr_t regs[max_num_regs];
struct iovec iovec;
iovec.iov_base = ®s;
@@ -243,7 +245,7 @@
thread_info.stack = std::pair<uintptr_t, uintptr_t>(regs[sp], 0);
- return true;
+ return true;
}
int ThreadCaptureImpl::CaptureThread(pid_t tid) {
@@ -266,7 +268,7 @@
unsigned int resume_signal = 0;
- unsigned int signal = WSTOPSIG(status);
+ unsigned int signal = WSTOPSIG(status);
if ((status >> 16) == PTRACE_EVENT_STOP) {
switch (signal) {
case SIGSTOP:
@@ -307,7 +309,7 @@
bool ThreadCaptureImpl::ReleaseThreads() {
bool ret = true;
- for (auto it = captured_threads_.begin(); it != captured_threads_.end(); ) {
+ for (auto it = captured_threads_.begin(); it != captured_threads_.end();) {
if (ReleaseThread(it->first, it->second)) {
it = captured_threads_.erase(it);
} else {
@@ -361,3 +363,5 @@
void ThreadCapture::InjectTestFunc(std::function<void(pid_t)>&& f) {
impl_->InjectTestFunc(std::forward<std::function<void(pid_t)>>(f));
}
+
+} // namespace android
diff --git a/libmemunreachable/ThreadCapture.h b/libmemunreachable/ThreadCapture.h
index 1022cad..961cb60 100644
--- a/libmemunreachable/ThreadCapture.h
+++ b/libmemunreachable/ThreadCapture.h
@@ -21,6 +21,8 @@
#include "Allocator.h"
+namespace android {
+
struct ThreadInfo {
pid_t tid;
allocator::vector<uintptr_t> regs;
@@ -33,7 +35,7 @@
class ThreadCaptureImpl;
class ThreadCapture {
-public:
+ public:
ThreadCapture(pid_t pid, Allocator<ThreadCapture> allocator);
~ThreadCapture();
@@ -44,11 +46,13 @@
bool CapturedThreadInfo(ThreadInfoList& threads);
void InjectTestFunc(std::function<void(pid_t)>&& f);
-private:
+ private:
ThreadCapture(const ThreadCapture&) = delete;
void operator=(const ThreadCapture&) = delete;
Allocator<ThreadCaptureImpl>::unique_ptr impl_;
};
+} // namespace android
+
#endif
diff --git a/libmemunreachable/anon_vma_naming.h b/libmemunreachable/anon_vma_naming.h
index 1e4ade1..fb31e41 100644
--- a/libmemunreachable/anon_vma_naming.h
+++ b/libmemunreachable/anon_vma_naming.h
@@ -19,7 +19,7 @@
#include <sys/prctl.h>
-#define PR_SET_VMA 0x53564d41
-#define PR_SET_VMA_ANON_NAME 0
+#define PR_SET_VMA 0x53564d41
+#define PR_SET_VMA_ANON_NAME 0
-#endif // LIBMEMUNREACHABLE_ANON_VMA_NAMING_H_
+#endif // LIBMEMUNREACHABLE_ANON_VMA_NAMING_H_
diff --git a/libmemunreachable/bionic.h b/libmemunreachable/bionic.h
index 83d07a8..dd1ec79 100644
--- a/libmemunreachable/bionic.h
+++ b/libmemunreachable/bionic.h
@@ -17,9 +17,9 @@
#ifndef LIBMEMUNREACHABLE_BIONIC_H_
#define LIBMEMUNREACHABLE_BIONIC_H_
-#include <sys/cdefs.h>
#include <stdint.h>
#include <stdlib.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -27,9 +27,9 @@
extern void malloc_disable();
extern void malloc_enable();
extern int malloc_iterate(uintptr_t base, size_t size,
- void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
+ void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
extern ssize_t malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
__END_DECLS
-#endif // LIBMEMUNREACHABLE_BIONIC_H_
+#endif // LIBMEMUNREACHABLE_BIONIC_H_
diff --git a/libmemunreachable/include/memunreachable/memunreachable.h b/libmemunreachable/include/memunreachable/memunreachable.h
index 9b227fd..438fcaf 100644
--- a/libmemunreachable/include/memunreachable/memunreachable.h
+++ b/libmemunreachable/include/memunreachable/memunreachable.h
@@ -17,12 +17,15 @@
#ifndef LIBMEMUNREACHABLE_MEMUNREACHABLE_H_
#define LIBMEMUNREACHABLE_MEMUNREACHABLE_H_
+#include <string.h>
#include <sys/cdefs.h>
#ifdef __cplusplus
-#include <vector>
#include <string>
+#include <vector>
+
+namespace android {
struct Leak {
uintptr_t begin;
@@ -73,6 +76,8 @@
std::string GetUnreachableMemoryString(bool log_contents = false, size_t limit = 100);
+} // namespace android
+
#endif
__BEGIN_DECLS
@@ -83,4 +88,4 @@
__END_DECLS
-#endif // LIBMEMUNREACHABLE_MEMUNREACHABLE_H_
+#endif // LIBMEMUNREACHABLE_MEMUNREACHABLE_H_
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index 1725c53..44c5f85 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -26,13 +26,21 @@
#define MEM_ALOGE(...) async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
#define MEM_ALOGW(...) async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, ##__VA_ARGS__)
#define MEM_ALOGI(...) async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__)
-#define MEM_ALOGV(...) async_safe_format_log(ANDROID_LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGV_IMPL(...) async_safe_format_log(ANDROID_LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+
+#ifdef NDEBUG
+#define MEM_ALOGV(...) \
+ do { \
+ if (0) { \
+ MEM_ALOGV_IMPL(__VA_ARGS__); \
+ } \
+ } while (0)
+#else
+#define MEM_ALOGV(...) MEM_ALOGV_IMPL(__VA_ARGS__)
+#endif
#define MEM_LOG_ALWAYS_FATAL(...) async_safe_fatal(__VA_ARGS__)
-#define MEM_LOG_ALWAYS_FATAL_IF(cond, ...) \
- ((__predict_false(cond)) ? async_safe_fatal(__VA_ARGS__) : (void)0)
-
#else
#include <log/log.h>
@@ -43,8 +51,7 @@
#define MEM_ALOGI ALOGI
#define MEM_LOG_ALWAYS_FATAL LOG_ALWAYS_FATAL
-#define MEM_LOG_ALWAYS_FATAL_IF LOG_ALWAYS_FATAL_IF
#endif
-#endif // LIBMEMUNREACHABLE_LOG_H_
+#endif // LIBMEMUNREACHABLE_LOG_H_
diff --git a/libmemunreachable/tests/Allocator_test.cpp b/libmemunreachable/tests/Allocator_test.cpp
index 21c8218..8991a7b 100644
--- a/libmemunreachable/tests/Allocator_test.cpp
+++ b/libmemunreachable/tests/Allocator_test.cpp
@@ -16,44 +16,44 @@
#include <Allocator.h>
-#include <gtest/gtest.h>
#include <ScopedDisableMalloc.h>
+#include <gtest/gtest.h>
+namespace android {
std::function<void()> ScopedAlarm::func_;
class AllocatorTest : public testing::Test {
protected:
AllocatorTest() : heap(), disable_malloc_() {}
- virtual void SetUp() {
- heap_count = 0;
- }
+ virtual void SetUp() { heap_count = 0; }
virtual void TearDown() {
ASSERT_EQ(heap_count, 0);
ASSERT_TRUE(heap.empty());
ASSERT_FALSE(disable_malloc_.timed_out());
}
Heap heap;
+
private:
ScopedDisableMallocTimeout disable_malloc_;
};
TEST_F(AllocatorTest, simple) {
Allocator<char[100]> allocator(heap);
- void *ptr = allocator.allocate();
+ void* ptr = allocator.allocate();
ASSERT_TRUE(ptr != NULL);
allocator.deallocate(ptr);
}
TEST_F(AllocatorTest, multiple) {
Allocator<char[100]> allocator(heap);
- void *ptr1 = allocator.allocate();
+ void* ptr1 = allocator.allocate();
ASSERT_TRUE(ptr1 != NULL);
- void *ptr2 = allocator.allocate();
+ void* ptr2 = allocator.allocate();
ASSERT_TRUE(ptr2 != NULL);
ASSERT_NE(ptr1, ptr2);
allocator.deallocate(ptr1);
- void *ptr3 = allocator.allocate();
+ void* ptr3 = allocator.allocate();
ASSERT_EQ(ptr1, ptr3);
allocator.deallocate(ptr3);
allocator.deallocate(ptr2);
@@ -63,7 +63,7 @@
const int num = 4096;
const int size = 128;
Allocator<char[size]> allocator(heap);
- void *ptr[num];
+ void* ptr[num];
for (int i = 0; i < num; i++) {
ptr[i] = allocator.allocate();
memset(ptr[i], 0xaa, size);
@@ -87,7 +87,7 @@
TEST_F(AllocatorTest, large) {
const size_t size = 1024 * 1024;
Allocator<char[size]> allocator(heap);
- void *ptr = allocator.allocate();
+ void* ptr = allocator.allocate();
memset(ptr, 0xaa, size);
allocator.deallocate(ptr);
}
@@ -96,7 +96,7 @@
const int num = 128;
const int size = 1024 * 1024;
Allocator<char[size]> allocator(heap);
- void *ptr[num];
+ void* ptr[num];
for (int i = 0; i < num; i++) {
ptr[i] = allocator.allocate();
memset(ptr[i], 0xaa, size);
@@ -172,3 +172,5 @@
ASSERT_NE(ptr, nullptr);
}
+
+} // namespace android
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
index 4e6155b..c630049 100644
--- a/libmemunreachable/tests/DisableMalloc_test.cpp
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -19,11 +19,13 @@
#include <chrono>
#include <functional>
-#include <gtest/gtest.h>
#include <ScopedDisableMalloc.h>
+#include <gtest/gtest.h>
using namespace std::chrono_literals;
+namespace android {
+
class DisableMallocTest : public ::testing::Test {
protected:
void alarm(std::chrono::microseconds us) {
@@ -36,75 +38,83 @@
};
TEST_F(DisableMallocTest, reenable) {
- ASSERT_EXIT({
- alarm(100ms);
- void *ptr1 = malloc(128);
- ASSERT_NE(ptr1, nullptr);
- free(ptr1);
- {
- ScopedDisableMalloc disable_malloc;
- }
- void *ptr2 = malloc(128);
- ASSERT_NE(ptr2, nullptr);
- free(ptr2);
- _exit(1);
- }, ::testing::ExitedWithCode(1), "");
+ ASSERT_EXIT(
+ {
+ alarm(100ms);
+ void* ptr1 = malloc(128);
+ ASSERT_NE(ptr1, nullptr);
+ free(ptr1);
+ { ScopedDisableMalloc disable_malloc; }
+ void* ptr2 = malloc(128);
+ ASSERT_NE(ptr2, nullptr);
+ free(ptr2);
+ _exit(1);
+ },
+ ::testing::ExitedWithCode(1), "");
}
TEST_F(DisableMallocTest, deadlock_allocate) {
- ASSERT_DEATH({
- void *ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- free(ptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- void* ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- free(ptr);
- }
- }, "");
+ ASSERT_DEATH(
+ {
+ void* ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ free(ptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ void* ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ free(ptr);
+ }
+ },
+ "");
}
TEST_F(DisableMallocTest, deadlock_new) {
- ASSERT_DEATH({
- char* ptr = new(char);
- ASSERT_NE(ptr, nullptr);
- delete(ptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- char* ptr = new (std::nothrow)(char);
- ASSERT_NE(ptr, nullptr);
- delete(ptr);
- }
- }, "");
+ ASSERT_DEATH(
+ {
+ char* ptr = new (char);
+ ASSERT_NE(ptr, nullptr);
+ delete (ptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ char* ptr = new (std::nothrow)(char);
+ ASSERT_NE(ptr, nullptr);
+ delete (ptr);
+ }
+ },
+ "");
}
TEST_F(DisableMallocTest, deadlock_delete) {
- ASSERT_DEATH({
- char* ptr = new(char);
- ASSERT_NE(ptr, nullptr);
- {
- alarm(250ms);
- ScopedDisableMalloc disable_malloc;
- delete(ptr);
- // Force ptr usage or this code gets optimized away by the arm64 compiler.
- ASSERT_NE(ptr, nullptr);
- }
- }, "");
+ ASSERT_DEATH(
+ {
+ char* ptr = new (char);
+ ASSERT_NE(ptr, nullptr);
+ {
+ alarm(250ms);
+ ScopedDisableMalloc disable_malloc;
+ delete (ptr);
+ // Force ptr usage or this code gets optimized away by the arm64 compiler.
+ ASSERT_NE(ptr, nullptr);
+ }
+ },
+ "");
}
TEST_F(DisableMallocTest, deadlock_free) {
- ASSERT_DEATH({
- void *ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- free(ptr);
- }
- }, "");
+ ASSERT_DEATH(
+ {
+ void* ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ free(ptr);
+ }
+ },
+ "");
}
TEST_F(DisableMallocTest, deadlock_fork) {
@@ -113,6 +123,8 @@
alarm(100ms);
ScopedDisableMalloc disable_malloc;
fork();
- }
- }, "");
}
+}, "");
+}
+
+} // namespace android
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index 98e4aa1..84a0ec6 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -19,10 +19,12 @@
#include "HeapWalker.h"
-#include <gtest/gtest.h>
#include <ScopedDisableMalloc.h>
+#include <gtest/gtest.h>
#include "Allocator.h"
+namespace android {
+
class HeapWalkerTest : public ::testing::Test {
public:
HeapWalkerTest() : disable_malloc_(), heap_() {}
@@ -172,20 +174,20 @@
ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
EXPECT_EQ(2U, num_leaks);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
}
TEST_F(HeapWalkerTest, segv) {
const size_t page_size = sysconf(_SC_PAGE_SIZE);
- void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(buffer1, nullptr);
void* buffer2;
buffer2 = &buffer1;
HeapWalker heap_walker(heap_);
- heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
+ heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1) + page_size);
heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
ASSERT_EQ(true, heap_walker.DetectLeaks());
@@ -199,3 +201,5 @@
EXPECT_EQ(0U, leaked_bytes);
ASSERT_EQ(0U, leaked.size());
}
+
+} // namespace android
diff --git a/libmemunreachable/tests/HostMallocStub.cpp b/libmemunreachable/tests/HostMallocStub.cpp
index a7e3f07..0ef0487 100644
--- a/libmemunreachable/tests/HostMallocStub.cpp
+++ b/libmemunreachable/tests/HostMallocStub.cpp
@@ -16,8 +16,6 @@
#include "bionic.h"
-void malloc_disable() {
-}
+void malloc_disable() {}
-void malloc_enable() {
-}
+void malloc_enable() {}
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
index e85df5f..f5b3631 100644
--- a/libmemunreachable/tests/LeakFolding_test.cpp
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-#include "HeapWalker.h"
#include "LeakFolding.h"
+#include "HeapWalker.h"
-#include <gtest/gtest.h>
#include <ScopedDisableMalloc.h>
+#include <gtest/gtest.h>
#include "Allocator.h"
+namespace android {
+
class LeakFoldingTest : public ::testing::Test {
public:
LeakFoldingTest() : disable_malloc_(), heap_() {}
@@ -84,7 +86,7 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(2U, num_leaks);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
EXPECT_EQ(0U, leaked[0].referenced_count);
EXPECT_EQ(0U, leaked[0].referenced_size);
@@ -113,7 +115,7 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(2U, num_leaks);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(1U, leaked.size());
EXPECT_EQ(1U, leaked[0].referenced_count);
EXPECT_EQ(sizeof(uintptr_t), leaked[0].referenced_size);
@@ -144,10 +146,10 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(3U, num_leaks);
- EXPECT_EQ(3*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(3 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(1U, leaked.size());
EXPECT_EQ(2U, leaked[0].referenced_count);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked[0].referenced_size);
}
TEST_F(LeakFoldingTest, dominator_cycle) {
@@ -175,13 +177,13 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(3U, num_leaks);
- EXPECT_EQ(5*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(5 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
EXPECT_EQ(2U, leaked[0].referenced_count);
- EXPECT_EQ(3*sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(3 * sizeof(uintptr_t), leaked[0].referenced_size);
EXPECT_EQ(2U, leaked[1].referenced_count);
- EXPECT_EQ(3*sizeof(uintptr_t), leaked[1].referenced_size);
+ EXPECT_EQ(3 * sizeof(uintptr_t), leaked[1].referenced_size);
}
TEST_F(LeakFoldingTest, two_cycles) {
@@ -218,12 +220,12 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(6U, num_leaks);
- EXPECT_EQ(6*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(6 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
EXPECT_EQ(2U, leaked[0].referenced_count);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked[0].referenced_size);
EXPECT_EQ(2U, leaked[1].referenced_count);
- EXPECT_EQ(2*sizeof(uintptr_t), leaked[1].referenced_size);
+ EXPECT_EQ(2 * sizeof(uintptr_t), leaked[1].referenced_size);
}
TEST_F(LeakFoldingTest, two_dominator_cycles) {
@@ -254,7 +256,7 @@
ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
EXPECT_EQ(4U, num_leaks);
- EXPECT_EQ(4*sizeof(uintptr_t), leaked_bytes);
+ EXPECT_EQ(4 * sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(4U, leaked.size());
EXPECT_EQ(1U, leaked[0].referenced_count);
EXPECT_EQ(sizeof(uintptr_t), leaked[0].referenced_size);
@@ -272,13 +274,13 @@
HeapWalker heap_walker(heap_);
- for (size_t i = 0; i < n; i ++) {
+ for (size_t i = 0; i < n; i++) {
ASSERT_TRUE(heap_walker.Allocation(reinterpret_cast<uintptr_t>(&buffer[i]),
- reinterpret_cast<uintptr_t>(&buffer[i+1])));
+ reinterpret_cast<uintptr_t>(&buffer[i + 1])));
}
for (size_t i = 0; i < n - 1; i++) {
- buffer[i] = &buffer[i+1];
+ buffer[i] = &buffer[i + 1];
}
buffer[n - 1] = &buffer[0];
@@ -306,15 +308,15 @@
HeapWalker heap_walker(heap_);
for (size_t i = 0; i < n - 1; i++) {
- buffer[i] = &buffer[i+1];
+ buffer[i] = &buffer[i + 1];
}
buffer[n - 1] = &buffer[0];
buffer1[0] = &buffer[0];
- for (size_t i = 0; i < n; i ++) {
+ for (size_t i = 0; i < n; i++) {
ASSERT_TRUE(heap_walker.Allocation(reinterpret_cast<uintptr_t>(&buffer[i]),
- reinterpret_cast<uintptr_t>(&buffer[i+1])));
+ reinterpret_cast<uintptr_t>(&buffer[i + 1])));
}
ALLOCATION(heap_walker, buffer1);
@@ -425,3 +427,5 @@
EXPECT_EQ(3U, leaked[3].referenced_count);
EXPECT_EQ(6 * sizeof(uintptr_t), leaked[3].referenced_size);
}
+
+} // namespace android
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 71da365..ec89388 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -16,36 +16,32 @@
#include <fcntl.h>
#include <stdlib.h>
-#include <unistd.h>
#include <sys/prctl.h>
+#include <unistd.h>
#include <gtest/gtest.h>
#include <memunreachable/memunreachable.h>
+namespace android {
+
class HiddenPointer {
public:
- explicit HiddenPointer(size_t size = 256) {
- Set(malloc(size));
- }
- ~HiddenPointer() {
- Free();
- }
- void* Get() {
- return reinterpret_cast<void*>(~ptr_);
- }
+ explicit HiddenPointer(size_t size = 256) { Set(malloc(size)); }
+ ~HiddenPointer() { Free(); }
+ void* Get() { return reinterpret_cast<void*>(~ptr_); }
void Free() {
free(Get());
Set(nullptr);
}
+
private:
- void Set(void* ptr) {
- ptr_ = ~reinterpret_cast<uintptr_t>(ptr);
- }
+ void Set(void* ptr) { ptr_ = ~reinterpret_cast<uintptr_t>(ptr); }
volatile uintptr_t ptr_;
};
-static void Ref(void* ptr) {
+// Trick the compiler into thinking a value on the stack is still referenced.
+static void Ref(void** ptr) {
write(0, ptr, 0);
}
@@ -63,14 +59,14 @@
{
void* ptr = hidden_ptr.Get();
- Ref(ptr);
+ Ref(&ptr);
UnreachableMemoryInfo info;
ASSERT_TRUE(GetUnreachableMemory(info));
ASSERT_EQ(0U, info.leaks.size());
- Ref(ptr);
+ ptr = nullptr;
}
{
@@ -216,3 +212,5 @@
ASSERT_TRUE(LogUnreachableMemory(true, 100));
}
+
+} // namespace android
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 44aabd7..4fbf729 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -34,6 +34,8 @@
using namespace std::chrono_literals;
+namespace android {
+
class ThreadListTest : public ::testing::TestWithParam<int> {
public:
ThreadListTest() : stop_(false) {}
@@ -45,12 +47,10 @@
WaitForThreads();
}
- virtual void TearDown() {
- ASSERT_TRUE(heap.empty());
- }
+ virtual void TearDown() { ASSERT_TRUE(heap.empty()); }
protected:
- template<class Function>
+ template <class Function>
void StartThreads(unsigned int threads, Function&& func) {
threads_.reserve(threads);
tids_.reserve(threads);
@@ -68,14 +68,14 @@
{
std::unique_lock<std::mutex> lk(m_);
- cv_stop_.wait(lk, [&] {return stop_;});
+ cv_stop_.wait(lk, [&] { return stop_; });
}
});
}
{
std::unique_lock<std::mutex> lk(m_);
- cv_start_.wait(lk, [&]{ return tids_.size() == threads; });
+ cv_start_.wait(lk, [&] { return tids_.size() == threads; });
}
}
@@ -93,9 +93,7 @@
tids_.clear();
}
- std::vector<pid_t>& tids() {
- return tids_;
- }
+ std::vector<pid_t>& tids() { return tids_; }
Heap heap;
@@ -143,7 +141,7 @@
TEST_P(ThreadListTest, list_some) {
const unsigned int threads = GetParam() - 1;
- StartThreads(threads, [](){});
+ StartThreads(threads, []() {});
std::vector<pid_t> expected_tids = tids();
expected_tids.push_back(getpid());
@@ -176,10 +174,8 @@
public:
ThreadCaptureTest() {}
~ThreadCaptureTest() {}
- void Fork(std::function<void()>&& child_init,
- std::function<void()>&& child_cleanup,
- std::function<void(pid_t)>&& parent) {
-
+ void Fork(std::function<void()>&& child_init, std::function<void()>&& child_cleanup,
+ std::function<void(pid_t)>&& parent) {
ScopedPipe start_pipe;
ScopedPipe stop_pipe;
@@ -211,39 +207,40 @@
TEST_P(ThreadCaptureTest, capture_some) {
const unsigned int threads = GetParam();
- Fork([&](){
- // child init
- StartThreads(threads - 1, [](){});
- },
- [&](){
- // child cleanup
- StopThreads();
- },
- [&](pid_t child){
- // parent
- ASSERT_GT(child, 0);
+ Fork(
+ [&]() {
+ // child init
+ StartThreads(threads - 1, []() {});
+ },
+ [&]() {
+ // child cleanup
+ StopThreads();
+ },
+ [&](pid_t child) {
+ // parent
+ ASSERT_GT(child, 0);
- {
- ScopedDisableMallocTimeout disable_malloc;
+ {
+ ScopedDisableMallocTimeout disable_malloc;
- ThreadCapture thread_capture(child, heap);
- auto list_tids = allocator::vector<pid_t>(heap);
+ ThreadCapture thread_capture(child, heap);
+ auto list_tids = allocator::vector<pid_t>(heap);
- ASSERT_TRUE(thread_capture.ListThreads(list_tids));
- ASSERT_EQ(threads, list_tids.size());
+ ASSERT_TRUE(thread_capture.ListThreads(list_tids));
+ ASSERT_EQ(threads, list_tids.size());
- ASSERT_TRUE(thread_capture.CaptureThreads());
+ ASSERT_TRUE(thread_capture.CaptureThreads());
- auto thread_info = allocator::vector<ThreadInfo>(heap);
- ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info));
- ASSERT_EQ(threads, thread_info.size());
- ASSERT_TRUE(thread_capture.ReleaseThreads());
+ auto thread_info = allocator::vector<ThreadInfo>(heap);
+ ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info));
+ ASSERT_EQ(threads, thread_info.size());
+ ASSERT_TRUE(thread_capture.ReleaseThreads());
- if (!HasFailure()) {
- ASSERT_FALSE(disable_malloc.timed_out());
- }
-}
- });
+ if (!HasFailure()) {
+ ASSERT_FALSE(disable_malloc.timed_out());
+ }
+ }
+ });
}
INSTANTIATE_TEST_CASE_P(ThreadCaptureTest, ThreadCaptureTest, ::testing::Values(1, 2, 10, 1024));
@@ -262,7 +259,7 @@
ScopedDisableMallocTimeout disable_malloc;
ThreadCapture thread_capture(ret, heap);
- thread_capture.InjectTestFunc([&](pid_t tid){
+ thread_capture.InjectTestFunc([&](pid_t tid) {
syscall(SYS_tgkill, ret, tid, SIGKILL);
usleep(10000);
});
@@ -288,62 +285,65 @@
// For signal handler
static ScopedPipe* g_pipe;
- Fork([&](){
- // child init
- pipe.CloseReceiver();
+ Fork(
+ [&]() {
+ // child init
+ pipe.CloseReceiver();
- g_pipe = &pipe;
+ g_pipe = &pipe;
- struct sigaction act{};
- act.sa_handler = [](int){
- char buf = '+';
- write(g_pipe->Sender(), &buf, 1);
- g_pipe->CloseSender();
- };
- sigaction(sig, &act, NULL);
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, sig);
- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
- },
- [&](){
- // child cleanup
- g_pipe = nullptr;
- pipe.Close();
- },
- [&](pid_t child){
- // parent
- ASSERT_GT(child, 0);
- pipe.CloseSender();
+ struct sigaction act {};
+ act.sa_handler = [](int) {
+ char buf = '+';
+ write(g_pipe->Sender(), &buf, 1);
+ g_pipe->CloseSender();
+ };
+ sigaction(sig, &act, NULL);
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, sig);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+ },
+ [&]() {
+ // child cleanup
+ g_pipe = nullptr;
+ pipe.Close();
+ },
+ [&](pid_t child) {
+ // parent
+ ASSERT_GT(child, 0);
+ pipe.CloseSender();
- {
- ScopedDisableMallocTimeout disable_malloc;
+ {
+ ScopedDisableMallocTimeout disable_malloc;
- ThreadCapture thread_capture(child, heap);
- thread_capture.InjectTestFunc([&](pid_t tid){
- syscall(SYS_tgkill, child, tid, sig);
- usleep(10000);
+ ThreadCapture thread_capture(child, heap);
+ thread_capture.InjectTestFunc([&](pid_t tid) {
+ syscall(SYS_tgkill, child, tid, sig);
+ usleep(10000);
+ });
+ auto list_tids = allocator::vector<pid_t>(heap);
+
+ ASSERT_TRUE(thread_capture.ListThreads(list_tids));
+ ASSERT_EQ(1U, list_tids.size());
+
+ ASSERT_TRUE(thread_capture.CaptureThreads());
+
+ auto thread_info = allocator::vector<ThreadInfo>(heap);
+ ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info));
+ ASSERT_EQ(1U, thread_info.size());
+ ASSERT_TRUE(thread_capture.ReleaseThreads());
+
+ usleep(100000);
+ char buf;
+ ASSERT_EQ(1, TEMP_FAILURE_RETRY(read(pipe.Receiver(), &buf, 1)));
+ ASSERT_EQ(buf, '+');
+
+ if (!HasFailure()) {
+ ASSERT_FALSE(disable_malloc.timed_out());
+ }
+ }
});
- auto list_tids = allocator::vector<pid_t>(heap);
-
- ASSERT_TRUE(thread_capture.ListThreads(list_tids));
- ASSERT_EQ(1U, list_tids.size());
-
- ASSERT_TRUE(thread_capture.CaptureThreads());
-
- auto thread_info = allocator::vector<ThreadInfo>(heap);
- ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info));
- ASSERT_EQ(1U, thread_info.size());
- ASSERT_TRUE(thread_capture.ReleaseThreads());
-
- usleep(100000);
- char buf;
- ASSERT_EQ(1, TEMP_FAILURE_RETRY(read(pipe.Receiver(), &buf, 1)));
- ASSERT_EQ(buf, '+');
-
- if (!HasFailure()) {
- ASSERT_FALSE(disable_malloc.timed_out());
- }
- }
- });
}
+
+} // namespace android