Merge "use std::hash instead of hashing byte by byte"
diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT
index c40695a..29a6992 100644
--- a/adb/OVERVIEW.TXT
+++ b/adb/OVERVIEW.TXT
@@ -7,16 +7,16 @@
- keep track of all Android devices and emulators instances
connected to or running on a given host developer machine
-- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+- implement various control commands (e.g. "adb shell", "adb pull", etc.)
for the benefit of clients (command-line users, or helper programs like
- DDMS). These commands are what is called a 'service' in ADB.
+ DDMS). These commands are called 'services' in ADB.
As a whole, everything works through the following components:
1. The ADB server
This is a background process that runs on the host machine. Its purpose
- if to sense the USB ports to know when devices are attached/removed,
+ is to sense the USB ports to know when devices are attached/removed,
as well as when emulator instances start/stop.
It thus maintains a list of "connected devices" and assigns a 'state'
@@ -40,7 +40,7 @@
meaning that the ADB server detected a new device/emulator, but could not
connect to the adbd daemon.
- the BOOTLOADER and RECOVERY states correspond to alternate states of
+ The BOOTLOADER and RECOVERY states correspond to alternate states of
devices when they are in the bootloader or recovery mode.
3. The ADB command-line client
@@ -49,8 +49,7 @@
or a script. It first tries to locate the ADB server on the host machine,
and will start one automatically if none is found.
- then, the client sends its service requests to the ADB server. It doesn't
- need to know.
+ Then, the client sends its service requests to the ADB server.
Currently, a single 'adb' binary is used for both the server and client.
this makes distribution and starting the server easier.
@@ -61,13 +60,13 @@
There are essentially two kinds of services that a client can talk to.
Host Services:
- these services run within the ADB Server and thus do not need to
+ These services run within the ADB Server and thus do not need to
communicate with a device at all. A typical example is "adb devices"
which is used to return the list of currently known devices and their
- state. They are a few couple other services though.
+ states. They are a few other services though.
Local Services:
- these services either run within the adbd daemon, or are started by
+ These services either run within the adbd daemon, or are started by
it on the device. The ADB server is used to multiplex streams
between the client and the service running in adbd. In this case
its role is to initiate the connection, then of being a pass-through
@@ -109,7 +108,7 @@
Note that the connection is still alive after an OKAY, which allows the
client to make other requests. But in certain cases, an OKAY will even
- change the state of the connection.
+ change the state of the connection.
For example, the case of the 'host:transport:<serialnumber>' request,
where '<serialnumber>' is used to identify a given device/emulator; after
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
index 06d7804..4445a76 100644
--- a/adb/SYNC.TXT
+++ b/adb/SYNC.TXT
@@ -1,4 +1,4 @@
-This file tries to document file related requests a client can make
+This file tries to document file-related requests a client can make
to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
to understand what's going on here. See the SERVICES.TXT to learn more
about the other requests that are possible.
@@ -8,16 +8,16 @@
Requesting the sync service ("sync:") using the protocol as described in
SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
-differ from the regular adb protocol. The connection stays in sync mode until
+differs from the regular adb protocol. The connection stays in sync mode until
explicitly terminated (see below).
After the initial "sync:" command is sent the server must respond with either
-"OKAY" or "FAIL" as per usual.
+"OKAY" or "FAIL" as per usual.
In sync mode both the server and the client will frequently use eight-byte
-packets to communicate in this document called sync request and sync
-responses. The first four bytes is an id and specifies sync request is
-represented by four utf-8 characters. The last four bytes is a Little-Endian
+packets to communicate. In this document these are called sync requests and sync
+responses. The first four bytes are an id that specifies the sync request. It is
+represented by four utf-8 characters. The last four bytes are a Little-Endian
integer, with various uses. This number will be called "length" below. In fact
all binary integers are Little-Endian in the sync mode. Sync mode is
implicitly exited after each sync request, and normal adb communication
@@ -29,8 +29,8 @@
SEND - Send a file to device
STAT - Stat a file
-For all of the sync request above the must be followed by length number of
-bytes containing an utf-8 string with a remote filename.
+All of the sync requests above must be followed by "length": the number of
+bytes containing a utf-8 string with a remote filename.
LIST:
Lists files in the directory specified by the remote filename. The server will
@@ -45,7 +45,7 @@
6. length number of bytes containing an utf-8 string representing the file
name.
-When an sync response "DONE" is received the listing is done.
+When a sync response "DONE" is received the listing is done.
SEND:
The remote file name is split into two parts separated by the last
@@ -65,7 +65,7 @@
When the file is transferred a sync request "DONE" is sent, where length is set
to the last modified time for the file. The server responds to this last
-request (but not to chuck requests) with an "OKAY" sync response (length can
+request (but not to chunk requests) with an "OKAY" sync response (length can
be ignored).
@@ -73,9 +73,8 @@
Retrieves a file from device to a local file. The remote path is the path to
the file that will be returned. Just as for the SEND sync request the file
received is split up into chunks. The sync response id is "DATA" and length is
-the chuck size. After follows chunk size number of bytes. This is repeated
-until the file is transferred. Each chuck will not be larger than 64k.
+the chunk size. After follows chunk size number of bytes. This is repeated
+until the file is transferred. Each chunk will not be larger than 64k.
When the file is transferred a sync response "DONE" is retrieved where the
length can be ignored.
-
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index c6f3e66..9a87931 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -62,7 +62,7 @@
}
vfs_cap_data cap_data = {};
- cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
cap_data.data[0].permitted = (capabilities & 0xffffffff);
cap_data.data[0].inheritable = 0;
cap_data.data[1].permitted = (capabilities >> 32);
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index 49e0363..253d14a 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -93,9 +93,21 @@
/* Helper function to get A/B suffix, if any. If the device isn't
* using A/B the empty string is returned. Otherwise either "_a",
* "_b", ... is returned.
+ *
+ * Note that since sometime in O androidboot.slot_suffix is deprecated
+ * and androidboot.slot should be used instead. Since bootloaders may
+ * be out of sync with the OS, we check both and for extra safety
+ * prepend a leading underscore if there isn't one already.
*/
static std::string get_ab_suffix() {
- return android::base::GetProperty("ro.boot.slot_suffix", "");
+ std::string ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
+ if (ab_suffix == "") {
+ ab_suffix = android::base::GetProperty("ro.boot.slot", "");
+ }
+ if (ab_suffix.size() > 0 && ab_suffix[0] != '_') {
+ ab_suffix = std::string("_") + ab_suffix;
+ }
+ return ab_suffix;
}
/* Use AVB to turn verity on/off */
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0abb680..307be6d 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -31,6 +31,7 @@
// Include this before open/close/unlink are defined as macros below.
#include <android-base/errors.h>
+#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include <android-base/utf8.h>
@@ -38,21 +39,6 @@
#include "sysdeps/network.h"
#include "sysdeps/stat.h"
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (_rc == -1 && errno == EINTR); \
- _rc; })
-#endif
-
// Some printf-like functions are implemented in terms of
// android::base::StringAppendV, so they should use the same attribute for
// compile-time format string checking. On Windows, if the mingw version of
diff --git a/base/Android.bp b/base/Android.bp
index 7ff02a0..ad0edf4 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -129,6 +129,7 @@
},
windows: {
srcs: ["utf8_test.cpp"],
+ cflags: ["-Wno-unused-parameter"],
enabled: true,
},
},
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index adb041b..6f05d9b 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -192,6 +192,7 @@
#undef CHECK_WOULD_LOG_ENABLED
+#if !defined(_WIN32)
static std::string make_log_pattern(android::base::LogSeverity severity,
const char* message) {
static const char log_characters[] = "VDIWEFF";
@@ -203,6 +204,7 @@
"%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s",
log_char, basename(&holder[0]), message);
}
+#endif
static void CheckMessage(const CapturedStderr& cap,
android::base::LogSeverity severity, const char* expected) {
diff --git a/base/utf8.cpp b/base/utf8.cpp
index 5984fb0..adb46d0 100644
--- a/base/utf8.cpp
+++ b/base/utf8.cpp
@@ -195,7 +195,7 @@
return _wfopen(name_utf16.c_str(), mode_utf16.c_str());
}
-int mkdir(const char* name, mode_t mode) {
+int mkdir(const char* name, mode_t) {
std::wstring name_utf16;
if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
return -1;
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index c1d5430..79702a6 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -778,7 +778,12 @@
checkDebugBuild || return
duration_test ">90"
panic_msg="kernel_panic,sysrq"
- enterPstore || panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
+ enterPstore
+ if [ ${?} != 0 ]; then
+ echo " or functional bootloader" >&2
+ panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
+ pstore_ok=true
+ fi
echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 8c11289..63b36f4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -228,6 +228,16 @@
{"reboot,its_just_so_hard", 88}, // produced by boot_reason_test
{"reboot,Its Just So Hard", 89}, // produced by boot_reason_test
{"usb", 90},
+ {"charge", 91},
+ {"oem_tz_crash", 92},
+ {"uvlo", 93},
+ {"oem_ps_hold", 94},
+ {"abnormal_reset", 95},
+ {"oemerr_unknown", 96},
+ {"reboot_fastboot_mode", 97},
+ {"watchdog_apps_bite", 98},
+ {"xpu_err", 99},
+ {"power_on_usb", 100},
};
// Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index d6b6d58..bd202ff 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -429,7 +429,12 @@
abort_message = g_callbacks.get_abort_message();
}
- if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
+ // If sival_int is ~0, it means that the fallback handler has been called
+ // once before and this function is being called again to dump the stack
+ // of a specific thread. It is possible that the prctl call might return 1,
+ // then return 0 in subsequent calls, so check the sival_int to determine if
+ // the fallback handler should be called first.
+ if (info->si_value.sival_int == ~0 || prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
// This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely,
// you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
// ANR trace.
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index bc88002..b0b2337 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -23,7 +23,6 @@
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../adb \
$(LOCAL_PATH)/../mkbootimg \
- $(LOCAL_PATH)/../../extras/f2fs_utils \
LOCAL_SRC_FILES := \
bootimg_utils.cpp \
@@ -40,7 +39,7 @@
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid make_f2fs
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -67,14 +66,6 @@
libcutils \
libgtest_host \
-# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
-LOCAL_CFLAGS_linux := -DUSE_F2FS
-LOCAL_LDFLAGS_linux := -ldl -rdynamic -Wl,-rpath,.
-LOCAL_REQUIRED_MODULES_linux := libf2fs_fmt_host_dyn
-# The following libf2fs_* are from system/extras/f2fs_utils,
-# and do not use code in external/f2fs-tools.
-LOCAL_STATIC_LIBRARIES_linux += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
-
LOCAL_CXX_STL := libc++_static
# Don't add anything here, we don't want additional shared dependencies
@@ -87,9 +78,7 @@
my_dist_files := $(LOCAL_BUILT_MODULE)
my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
-ifeq ($(HOST_OS),linux)
-my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
-endif
+my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
ifdef HOST_CROSS_OS
# Archive fastboot.exe for win_sdk build.
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 40c18e0..6175f59 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -485,7 +485,7 @@
return bdata;
}
-static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, int64_t* sz) {
+static void* unzip_to_memory(ZipArchiveHandle zip, const char* entry_name, int64_t* sz) {
ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
@@ -495,7 +495,7 @@
*sz = zip_entry.uncompressed_length;
- fprintf(stderr, "extracting %s (%" PRId64 " MB)...\n", entry_name, *sz / 1024 / 1024);
+ fprintf(stderr, "extracting %s (%" PRId64 " MB) to RAM...\n", entry_name, *sz / 1024 / 1024);
uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
if (data == nullptr) die("failed to allocate %" PRId64 " bytes for '%s'", *sz, entry_name);
@@ -613,17 +613,20 @@
return -1;
}
- fprintf(stderr, "extracting %s (%" PRIu32 " MB)...\n", entry_name,
+ fprintf(stderr, "extracting %s (%" PRIu32 " MB) to disk...", entry_name,
zip_entry.uncompressed_length / 1024 / 1024);
+ double start = now();
int error = ExtractEntryToFile(zip, &zip_entry, fd);
if (error != 0) {
- die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
+ die("\nfailed to extract '%s': %s", entry_name, ErrorCodeString(error));
}
if (lseek(fd, 0, SEEK_SET) != 0) {
- die("lseek on extracted file '%s' failed: %s", entry_name, strerror(errno));
+ die("\nlseek on extracted file '%s' failed: %s", entry_name, strerror(errno));
}
+ fprintf(stderr, " took %.3fs\n", now() - start);
+
return fd.release();
}
@@ -1091,7 +1094,7 @@
static void do_update_signature(ZipArchiveHandle zip, const char* filename) {
int64_t sz;
- void* data = unzip_file(zip, filename, &sz);
+ void* data = unzip_to_memory(zip, filename, &sz);
if (data == nullptr) return;
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
@@ -1130,7 +1133,7 @@
}
int64_t sz;
- void* data = unzip_file(zip, "android-info.txt", &sz);
+ void* data = unzip_to_memory(zip, "android-info.txt", &sz);
if (data == nullptr) {
die("update package '%s' has no android-info.txt", filename);
}
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 2d77dd6..320cf7f 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,6 @@
#include "fs.h"
#include "fastboot.h"
-#include "make_f2fs.h"
#include <errno.h>
#include <fcntl.h>
@@ -23,13 +22,12 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-#include <sparse/sparse.h>
using android::base::StringPrintf;
using android::base::unique_fd;
#ifdef WIN32
-static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+static int exec_e2fs_cmd(const char* /*path*/, char* const argv[]) {
std::string cmd;
int i = 0;
while (argv[i] != nullptr) {
@@ -156,22 +154,41 @@
return 0;
}
-#ifdef USE_F2FS
static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned /* unused */, unsigned /* unused */)
{
+#ifndef WIN32
+ const std::string exec_dir = android::base::GetExecutableDirectory();
+ const std::string mkf2fs_path = exec_dir + "/make_f2fs";
+ std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
+
+ mkf2fs_args.push_back("-S");
+ std::string size_str = std::to_string(partSize);
+ mkf2fs_args.push_back(size_str.c_str());
+ mkf2fs_args.push_back("-f");
+ mkf2fs_args.push_back("-O");
+ mkf2fs_args.push_back("encrypt");
+ mkf2fs_args.push_back("-O");
+ mkf2fs_args.push_back("quota");
+ mkf2fs_args.push_back(fileName);
+ mkf2fs_args.push_back(nullptr);
+
+ int ret = exec_e2fs_cmd(mkf2fs_args[0], const_cast<char**>(mkf2fs_args.data()));
+ if (ret != 0) {
+ fprintf(stderr, "mkf2fs failed: %d\n", ret);
+ return -1;
+ }
+
if (!initial_dir.empty()) {
- fprintf(stderr, "Unable to set initial directory on F2FS filesystem: %s\n", strerror(errno));
- return -1;
+ fprintf(stderr, "sload.f2s not supported yet\n");
+ return 0;
}
- unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
- if (fd == -1) {
- fprintf(stderr, "Unable to open output file for F2FS filesystem: %s\n", strerror(errno));
- return -1;
- }
- return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
-}
+ return 0;
+#else
+ fprintf(stderr, "make_f2fs not supported on Windows\n");
+ return -1;
#endif
+}
static const struct fs_generator {
const char* fs_type; //must match what fastboot reports for partition type
@@ -182,9 +199,7 @@
} generators[] = {
{ "ext4", generate_ext4_image},
-#ifdef USE_F2FS
{ "f2fs", generate_f2fs_image},
-#endif
};
const struct fs_generator* fs_get_generator(const std::string& fs_type) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 33fd562..f604bcf 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,12 +21,19 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
-// if that parameter does not exist.
+// Returns "_a" or "_b" based on two possible values in kernel cmdline:
+// - androidboot.slot = a or b OR
+// - androidboot.slot_suffix = _a or _b
+// TODO: remove slot_suffix once it's deprecated.
std::string fs_mgr_get_slot_suffix() {
+ std::string slot;
std::string ab_suffix;
- fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
+ if (fs_mgr_get_boot_config("slot", &slot)) {
+ ab_suffix = "_" + slot;
+ } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) {
+ ab_suffix = "";
+ }
return ab_suffix;
}
@@ -40,7 +47,7 @@
char *tmp;
if (ab_suffix.empty()) {
ab_suffix = fs_mgr_get_slot_suffix();
- // Returns false as non A/B devices should not have MF_SLOTSELECT.
+ // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
if (ab_suffix.empty()) return false;
}
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
diff --git a/init/action.cpp b/init/action.cpp
index 2617d00..5fa6bec 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -379,10 +379,12 @@
return action_ ? action_->AddCommand(std::move(args), line) : Success();
}
-void ActionParser::EndSection() {
+Result<Success> ActionParser::EndSection() {
if (action_ && action_->NumCommands() > 0) {
action_manager_->AddAction(std::move(action_));
}
+
+ return Success();
}
} // namespace init
diff --git a/init/action.h b/init/action.h
index cdfc6a0..1bfc6c7 100644
--- a/init/action.h
+++ b/init/action.h
@@ -130,7 +130,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
ActionManager* action_manager_;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 950a551..f584021 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -65,6 +65,7 @@
#include "property_service.h"
#include "reboot.h"
#include "rlimit_parser.h"
+#include "selinux.h"
#include "service.h"
#include "subcontext.h"
#include "util.h"
@@ -641,8 +642,26 @@
return Success();
}
+static int MakeSymlink(const std::string& target, const std::string& linkpath) {
+ std::string secontext;
+ // Passing 0 for mode should work.
+ if (SelabelLookupFileContext(linkpath, 0, &secontext) && !secontext.empty()) {
+ setfscreatecon(secontext.c_str());
+ }
+
+ int rc = symlink(target.c_str(), linkpath.c_str());
+
+ if (!secontext.empty()) {
+ int save_errno = errno;
+ setfscreatecon(nullptr);
+ errno = save_errno;
+ }
+
+ return rc;
+}
+
static Result<Success> do_symlink(const BuiltinArguments& args) {
- if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
+ if (MakeSymlink(args[1], args[2]) < 0) {
// The symlink builtin is often used to create symlinks for older devices to be backwards
// compatible with new paths, therefore we skip reporting this error.
if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 642a364..50987db 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -194,5 +194,18 @@
return SetAmbientCaps(to_keep);
}
+bool DropInheritableCaps() {
+ ScopedCaps caps(cap_get_proc());
+ if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
+ PLOG(ERROR) << "cap_clear_flag(INHERITABLE) failed";
+ return false;
+ }
+ if (cap_set_proc(caps.get()) != 0) {
+ PLOG(ERROR) << "cap_set_proc() failed";
+ return false;
+ }
+ return true;
+}
+
} // namespace init
} // namespace android
diff --git a/init/capabilities.h b/init/capabilities.h
index ede85c3..fc80c98 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -35,6 +35,7 @@
bool CapAmbientSupported();
unsigned int GetLastValidCap();
bool SetCapsForExec(const CapSet& to_keep);
+bool DropInheritableCaps();
} // namespace init
} // namespace android
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 0f7e38f..6fa07e7 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -118,7 +118,10 @@
FirstStageMount::FirstStageMount()
: need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
if (!device_tree_fstab_) {
- LOG(ERROR) << "Failed to read fstab from device tree";
+ // The client of FirstStageMount should check the existence of fstab in device-tree
+ // in advance, without parsing it. Reaching here means there is a FATAL error when
+ // parsing the fstab. So stop here to expose the failure.
+ LOG(FATAL) << "Failed to read fstab from device tree";
return;
}
// Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 29a65ab..268873c 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -25,6 +25,7 @@
#include "import_parser.h"
#include "keyword_map.h"
#include "parser.h"
+#include "service.h"
#include "test_function_map.h"
#include "util.h"
@@ -34,12 +35,13 @@
using ActionManagerCommand = std::function<void(ActionManager&)>;
void TestInit(const std::string& init_script_file, const TestFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands) {
+ const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
ActionManager am;
Action::set_function_map(&test_function_map);
Parser parser;
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(service_list, nullptr));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
@@ -55,11 +57,11 @@
}
void TestInitText(const std::string& init_script, const TestFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands) {
+ const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFd(init_script, tf.fd));
- TestInit(tf.path, test_function_map, commands);
+ TestInit(tf.path, test_function_map, commands, service_list);
}
TEST(init, SimpleEventTrigger) {
@@ -76,7 +78,8 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInitText(init_script, test_function_map, commands);
+ ServiceList service_list;
+ TestInitText(init_script, test_function_map, commands, &service_list);
EXPECT_TRUE(expect_true);
}
@@ -104,7 +107,30 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInitText(init_script, test_function_map, commands);
+ ServiceList service_list;
+ TestInitText(init_script, test_function_map, commands, &service_list);
+}
+
+TEST(init, OverrideService) {
+ std::string init_script = R"init(
+service A something
+ class first
+
+service A something
+ class second
+ override
+
+)init";
+
+ ServiceList service_list;
+ TestInitText(init_script, TestFunctionMap(), {}, &service_list);
+ ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
+
+ auto service = service_list.begin()->get();
+ ASSERT_NE(nullptr, service);
+ EXPECT_EQ(std::set<std::string>({"second"}), service->classnames());
+ EXPECT_EQ("A", service->name());
+ EXPECT_TRUE(service->is_override());
}
TEST(init, EventTriggerOrderMultipleFiles) {
@@ -162,7 +188,9 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInit(start.path, test_function_map, commands);
+ ServiceList service_list;
+
+ TestInit(start.path, test_function_map, commands, &service_list);
EXPECT_EQ(6, num_executed);
}
diff --git a/init/parser.cpp b/init/parser.cpp
index 8a4e798..6ddb09f 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -50,12 +50,24 @@
state.nexttoken = 0;
SectionParser* section_parser = nullptr;
+ int section_start_line = -1;
std::vector<std::string> args;
+ auto end_section = [&] {
+ if (section_parser == nullptr) return;
+
+ if (auto result = section_parser->EndSection(); !result) {
+ LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
+ }
+
+ section_parser = nullptr;
+ section_start_line = -1;
+ };
+
for (;;) {
switch (next_token(&state)) {
case T_EOF:
- if (section_parser) section_parser->EndSection();
+ end_section();
return;
case T_NEWLINE:
state.line++;
@@ -65,18 +77,18 @@
// uevent.
for (const auto& [prefix, callback] : line_callbacks_) {
if (android::base::StartsWith(args[0], prefix.c_str())) {
- if (section_parser) section_parser->EndSection();
+ end_section();
if (auto result = callback(std::move(args)); !result) {
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
- section_parser = nullptr;
break;
}
}
if (section_parsers_.count(args[0])) {
- if (section_parser) section_parser->EndSection();
+ end_section();
section_parser = section_parsers_[args[0]].get();
+ section_start_line = state.line;
if (auto result =
section_parser->ParseSection(std::move(args), filename, state.line);
!result) {
diff --git a/init/parser.h b/init/parser.h
index 4ab24a4..110a468 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -26,24 +26,22 @@
// SectionParser is an interface that can parse a given 'section' in init.
//
-// You can implement up to 4 functions below, with ParseSection() being mandatory.
-// The first two function return bool with false indicating a failure and has a std::string* err
-// parameter into which an error string can be written. It will be reported along with the
-// filename and line number of where the error occurred.
+// You can implement up to 4 functions below, with ParseSection being mandatory. The first two
+// functions return Result<Success> indicating if they have an error. It will be reported along
+// with the filename and line number of where the error occurred.
//
-// 1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
-// int line, std::string* err)
+// 1) ParseSection
// This function is called when a section is first encountered.
//
-// 2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
+// 2) ParseLineSection
// This function is called on each subsequent line until the next section is encountered.
//
-// 3) bool EndSection()
+// 3) EndSection
// This function is called either when a new section is found or at the end of the file.
// It indicates that parsing of the current section is complete and any relevant objects should
// be committed.
//
-// 4) bool EndFile()
+// 4) EndFile
// This function is called at the end of the file.
// It indicates that the parsing has completed and any relevant objects should be committed.
@@ -56,7 +54,7 @@
virtual Result<Success> ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) = 0;
virtual Result<Success> ParseLineSection(std::vector<std::string>&&, int) { return Success(); };
- virtual void EndSection(){};
+ virtual Result<Success> EndSection() { return Success(); };
virtual void EndFile(){};
};
diff --git a/init/service.cpp b/init/service.cpp
index 12acfc6..331b859 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -291,6 +291,11 @@
if (!SetCapsForExec(capabilities_)) {
LOG(FATAL) << "cannot set capabilities for " << name_;
}
+ } else if (uid_) {
+ // Inheritable caps can be non-zero when running in a container.
+ if (!DropInheritableCaps()) {
+ LOG(FATAL) << "cannot drop inheritable caps for " << name_;
+ }
}
}
@@ -530,6 +535,11 @@
return Success();
}
+Result<Success> Service::ParseOverride(const std::vector<std::string>& args) {
+ override_ = true;
+ return Success();
+}
+
Result<Success> Service::ParseMemcgSwappiness(const std::vector<std::string>& args) {
if (!ParseInt(args[1], &swappiness_, 0)) {
return Error() << "swappiness value must be equal or greater than 0";
@@ -671,6 +681,7 @@
{"keycodes", {1, kMax, &Service::ParseKeycodes}},
{"oneshot", {0, 0, &Service::ParseOneshot}},
{"onrestart", {1, kMax, &Service::ParseOnrestart}},
+ {"override", {0, 0, &Service::ParseOverride}},
{"oom_score_adjust",
{1, 1, &Service::ParseOomScoreAdjust}},
{"memcg.swappiness",
@@ -1111,11 +1122,6 @@
return Error() << "invalid service name '" << name << "'";
}
- Service* old_service = service_list_->FindService(name);
- if (old_service) {
- return Error() << "ignored duplicate definition of service '" << name << "'";
- }
-
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
@@ -1135,10 +1141,23 @@
return service_ ? service_->ParseLine(std::move(args)) : Success();
}
-void ServiceParser::EndSection() {
+Result<Success> ServiceParser::EndSection() {
if (service_) {
+ Service* old_service = service_list_->FindService(service_->name());
+ if (old_service) {
+ if (!service_->is_override()) {
+ return Error() << "ignored duplicate definition of service '" << service_->name()
+ << "'";
+ }
+
+ service_list_->RemoveService(*old_service);
+ old_service = nullptr;
+ }
+
service_list_->AddService(std::move(service_));
}
+
+ return Success();
}
bool ServiceParser::IsValidName(const std::string& name) const {
diff --git a/init/service.h b/init/service.h
index 593f782..d46a413 100644
--- a/init/service.h
+++ b/init/service.h
@@ -111,6 +111,7 @@
const std::set<std::string>& interfaces() const { return interfaces_; }
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
+ bool is_override() const { return override_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
unsigned long start_order() const { return start_order_; }
const std::vector<std::string>& args() const { return args_; }
@@ -139,6 +140,7 @@
Result<Success> ParseOneshot(const std::vector<std::string>& args);
Result<Success> ParseOnrestart(const std::vector<std::string>& args);
Result<Success> ParseOomScoreAdjust(const std::vector<std::string>& args);
+ Result<Success> ParseOverride(const std::vector<std::string>& args);
Result<Success> ParseMemcgLimitInBytes(const std::vector<std::string>& args);
Result<Success> ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args);
Result<Success> ParseMemcgSwappiness(const std::vector<std::string>& args);
@@ -201,6 +203,8 @@
bool process_cgroup_empty_ = false;
+ bool override_ = false;
+
unsigned long start_order_;
std::vector<std::pair<int, rlimit>> rlimits_;
@@ -248,7 +252,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
bool IsValidName(const std::string& name) const;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 84feeee..068be6e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -23,7 +23,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/properties.h>
#include <android-base/strings.h>
#include <selinux/android.h>
@@ -32,7 +31,6 @@
#include "system/core/init/subcontext.pb.h"
#include "util.h"
-using android::base::GetBoolProperty;
using android::base::GetExecutablePath;
using android::base::Join;
using android::base::Socketpair;
@@ -262,13 +260,11 @@
static std::vector<Subcontext> subcontexts;
std::vector<Subcontext>* InitializeSubcontexts() {
- if (GetBoolProperty("ro.init.subcontexts_enabled", false)) {
- static const char* const paths_and_secontexts[][2] = {
- {"/vendor", kVendorContext.c_str()},
- };
- for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
- subcontexts.emplace_back(path_prefix, secontext);
- }
+ static const char* const paths_and_secontexts[][2] = {
+ {"/vendor", kVendorContext.c_str()},
+ };
+ for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+ subcontexts.emplace_back(path_prefix, secontext);
}
return &subcontexts;
}
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index cd7adb4..f74c878 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -132,8 +132,10 @@
return std::invoke(*parser, this, std::move(args));
}
-void SubsystemParser::EndSection() {
+Result<Success> SubsystemParser::EndSection() {
subsystems_->emplace_back(std::move(subsystem_));
+
+ return Success();
}
} // namespace init
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 18d1027..83684f3 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -32,7 +32,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
Result<Success> ParseDevName(std::vector<std::string>&& args);
diff --git a/init/util.cpp b/init/util.cpp
index a19a6f3..d80cb1e 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -178,9 +178,26 @@
return content;
}
+static int OpenFile(const std::string& path, int flags, mode_t mode) {
+ std::string secontext;
+ if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
+ setfscreatecon(secontext.c_str());
+ }
+
+ int rc = open(path.c_str(), flags, mode);
+
+ if (!secontext.empty()) {
+ int save_errno = errno;
+ setfscreatecon(nullptr);
+ errno = save_errno;
+ }
+
+ return rc;
+}
+
Result<Success> WriteFile(const std::string& path, const std::string& content) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(
- open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
+ OpenFile(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
if (fd == -1) {
return ErrnoError() << "open() failed";
}
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 25e5002..9ac0a0b 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -44,15 +44,15 @@
}
// Iterate through the maps and fill in the backtrace_map_t structure.
- for (auto& map_info : *stack_maps_) {
+ for (auto* map_info : *stack_maps_) {
backtrace_map_t map;
- map.start = map_info.start;
- map.end = map_info.end;
- map.offset = map_info.offset;
+ map.start = map_info->start;
+ map.end = map_info->end;
+ map.offset = map_info->offset;
// Set to -1 so that it is demand loaded.
map.load_bias = static_cast<uintptr_t>(-1);
- map.flags = map_info.flags;
- map.name = map_info.name;
+ map.flags = map_info->flags;
+ map.name = map_info->name;
maps_.push_back(map);
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 0a60ec4..9911e74 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -77,6 +77,7 @@
struct dump_thread_t {
thread_t thread;
+ BacktraceMap* map;
Backtrace* backtrace;
int32_t* now;
int32_t done;
@@ -632,7 +633,7 @@
}
// The status of the actual unwind will be checked elsewhere.
- dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid);
+ dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid, dump->map);
dump->backtrace->Unwind(0);
android_atomic_acquire_store(1, &dump->done);
@@ -640,8 +641,8 @@
return nullptr;
}
-TEST(libbacktrace, thread_multiple_dump) {
- // Dump NUM_THREADS simultaneously.
+static void MultipleThreadDumpTest(bool share_map) {
+ // Dump NUM_THREADS simultaneously using the same map.
std::vector<thread_t> runners(NUM_THREADS);
std::vector<dump_thread_t> dumpers(NUM_THREADS);
@@ -662,12 +663,17 @@
// Start all of the dumpers at once, they will spin until they are signalled
// to begin their dump run.
+ std::unique_ptr<BacktraceMap> map;
+ if (share_map) {
+ map.reset(BacktraceMap::Create(getpid()));
+ }
int32_t dump_now = 0;
for (size_t i = 0; i < NUM_THREADS; i++) {
dumpers[i].thread.tid = runners[i].tid;
dumpers[i].thread.state = 0;
dumpers[i].done = 0;
dumpers[i].now = &dump_now;
+ dumpers[i].map = map.get();
ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
}
@@ -689,47 +695,12 @@
}
}
-TEST(libbacktrace, thread_multiple_dump_same_thread) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- thread_t runner;
- runner.tid = 0;
- runner.state = 0;
- ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+TEST(libbacktrace, thread_multiple_dump) {
+ MultipleThreadDumpTest(false);
+}
- // Wait for tids to be set.
- ASSERT_TRUE(WaitForNonZero(&runner.state, 30));
-
- // Start all of the dumpers at once, they will spin until they are signalled
- // to begin their dump run.
- int32_t dump_now = 0;
- // Dump the same thread NUM_THREADS simultaneously.
- std::vector<dump_thread_t> dumpers(NUM_THREADS);
- for (size_t i = 0; i < NUM_THREADS; i++) {
- dumpers[i].thread.tid = runner.tid;
- dumpers[i].thread.state = 0;
- dumpers[i].done = 0;
- dumpers[i].now = &dump_now;
-
- ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
- }
-
- // Start all of the dumpers going at once.
- android_atomic_acquire_store(1, &dump_now);
-
- for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
-
- ASSERT_TRUE(dumpers[i].backtrace != nullptr);
- VerifyMaxDump(dumpers[i].backtrace);
-
- delete dumpers[i].backtrace;
- dumpers[i].backtrace = nullptr;
- }
-
- // Tell the runner thread to exit its infinite loop.
- android_atomic_acquire_store(0, &runner.state);
+TEST(libbacktrace, thread_multiple_dump_same_map) {
+ MultipleThreadDumpTest(true);
}
// This test is for UnwindMaps that should share the same map cursor when
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index faaad0c..9cba109 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -19,14 +19,14 @@
// which are also hard or even impossible to port to native Win32
libcutils_nonwindows_sources = [
"android_get_control_file.cpp",
- "fs.c",
- "multiuser.c",
- "socket_inaddr_any_server_unix.c",
- "socket_local_client_unix.c",
- "socket_local_server_unix.c",
- "socket_network_client_unix.c",
+ "fs.cpp",
+ "multiuser.cpp",
+ "socket_inaddr_any_server_unix.cpp",
+ "socket_local_client_unix.cpp",
+ "socket_local_server_unix.cpp",
+ "socket_network_client_unix.cpp",
"sockets_unix.cpp",
- "str_parms.c",
+ "str_parms.cpp",
]
cc_library_headers {
@@ -56,41 +56,37 @@
},
host_supported: true,
srcs: [
- "config_utils.c",
+ "config_utils.cpp",
"fs_config.cpp",
- "canned_fs_config.c",
- "hashmap.c",
- "iosched_policy.c",
- "load_file.c",
- "native_handle.c",
+ "canned_fs_config.cpp",
+ "hashmap.cpp",
+ "iosched_policy.cpp",
+ "load_file.cpp",
+ "native_handle.cpp",
"open_memstream.c",
- "record_stream.c",
+ "record_stream.cpp",
"sched_policy.cpp",
"sockets.cpp",
- "strdup16to8.c",
- "strdup8to16.c",
+ "strdup16to8.cpp",
+ "strdup8to16.cpp",
"strlcpy.c",
- "threads.c",
+ "threads.cpp",
],
target: {
- host: {
- srcs: ["dlmalloc_stubs.c"],
- },
linux_bionic: {
enabled: true,
- exclude_srcs: ["dlmalloc_stubs.c"],
},
not_windows: {
srcs: libcutils_nonwindows_sources + [
- "ashmem-host.c",
- "trace-host.c",
+ "ashmem-host.cpp",
+ "trace-host.cpp",
],
},
windows: {
srcs: [
- "socket_inaddr_any_server_windows.c",
- "socket_network_client_windows.c",
+ "socket_inaddr_any_server_windows.cpp",
+ "socket_network_client_windows.cpp",
"sockets_windows.cpp",
],
@@ -105,13 +101,13 @@
android: {
srcs: libcutils_nonwindows_sources + [
- "android_reboot.c",
- "ashmem-dev.c",
+ "android_reboot.cpp",
+ "ashmem-dev.cpp",
"klog.cpp",
- "partition_utils.c",
+ "partition_utils.cpp",
"properties.cpp",
- "qtaguid.c",
- "trace-dev.c",
+ "qtaguid.cpp",
+ "trace-dev.cpp",
"uevent.cpp",
],
},
diff --git a/libcutils/android_get_control_file.cpp b/libcutils/android_get_control_file.cpp
index 780d9f1..d8121f5 100644
--- a/libcutils/android_get_control_file.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -25,6 +25,9 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
+#include <cutils/android_get_control_file.h>
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -36,8 +39,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/android_get_control_file.h>
-
#include "android_get_control_env.h"
#ifndef TEMP_FAILURE_RETRY
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.cpp
similarity index 96%
rename from libcutils/android_reboot.c
rename to libcutils/android_reboot.cpp
index 996d89d..5e864d4 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.cpp
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <cutils/android_reboot.h>
+
#include <stdio.h>
#include <stdlib.h>
-#include <cutils/android_reboot.h>
#include <cutils/properties.h>
#define TAG "android_reboot"
@@ -26,7 +28,7 @@
const char* restart_cmd = NULL;
char* prop_value;
- switch (cmd) {
+ switch (static_cast<unsigned>(cmd)) {
case ANDROID_RB_RESTART: // deprecated
case ANDROID_RB_RESTART2:
restart_cmd = "reboot";
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.cpp
similarity index 94%
rename from libcutils/ashmem-dev.c
rename to libcutils/ashmem-dev.cpp
index 95f2259..15ace0e 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/ashmem.h>
+
/*
* Implementation of the user-space ashmem API for devices, which have our
* ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
@@ -31,8 +33,6 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
-
-#include <cutils/ashmem.h>
#include <log/log.h>
#define ASHMEM_DEVICE "/dev/ashmem"
@@ -192,7 +192,8 @@
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
- struct ashmem_pin pin = { offset, len };
+ // TODO: should LP64 reject too-large offset/len?
+ ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
int ret = __ashmem_is_ashmem(fd, 1);
if (ret < 0) {
@@ -204,7 +205,8 @@
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
- struct ashmem_pin pin = { offset, len };
+ // TODO: should LP64 reject too-large offset/len?
+ ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
int ret = __ashmem_is_ashmem(fd, 1);
if (ret < 0) {
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.cpp
similarity index 92%
rename from libcutils/ashmem-host.c
rename to libcutils/ashmem-host.cpp
index 1f9f753..d2c28f3 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/ashmem.h>
+
/*
* Implementation of the user-space ashmem API for the simulator, which lacks
* an ashmem-enabled kernel. See ashmem-dev.c for the real ashmem-based version.
@@ -31,7 +33,6 @@
#include <time.h>
#include <unistd.h>
-#include <cutils/ashmem.h>
#include <utils/Compat.h>
#ifndef __unused
@@ -40,12 +41,12 @@
int ashmem_create_region(const char *ignored __unused, size_t size)
{
- char template[PATH_MAX];
- snprintf(template, sizeof(template), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
- int fd = mkstemp(template);
+ char pattern[PATH_MAX];
+ snprintf(pattern, sizeof(pattern), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
+ int fd = mkstemp(pattern);
if (fd == -1) return -1;
- unlink(template);
+ unlink(pattern);
if (TEMP_FAILURE_RETRY(ftruncate(fd, size)) == -1) {
close(fd);
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.cpp
similarity index 99%
rename from libcutils/canned_fs_config.c
rename to libcutils/canned_fs_config.cpp
index 819a846..6b5763b 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <private/android_filesystem_config.h>
+#include <private/canned_fs_config.h>
+#include <private/fs_config.h>
+
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -22,10 +26,6 @@
#include <stdlib.h>
#include <string.h>
-#include <private/android_filesystem_config.h>
-#include <private/fs_config.h>
-#include <private/canned_fs_config.h>
-
typedef struct {
const char* path;
unsigned uid;
diff --git a/libcutils/config_utils.c b/libcutils/config_utils.cpp
similarity index 97%
rename from libcutils/config_utils.c
rename to libcutils/config_utils.cpp
index fc5ca78..a3af01a 100644
--- a/libcutils/config_utils.c
+++ b/libcutils/config_utils.cpp
@@ -14,20 +14,19 @@
* limitations under the License.
*/
+#include <cutils/config_utils.h>
+
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
-#include <cutils/config_utils.h>
#include <cutils/misc.h>
cnode* config_node(const char *name, const char *value)
{
- cnode *node;
-
- node = calloc(sizeof(cnode), 1);
+ cnode* node = static_cast<cnode*>(calloc(sizeof(cnode), 1));
if(node) {
node->name = name ? name : "";
node->value = value ? value : "";
@@ -311,9 +310,9 @@
void config_load_file(cnode *root, const char *fn)
{
- char *data;
- data = load_file(fn, 0);
+ char* data = static_cast<char*>(load_file(fn, nullptr));
config_load(root, data);
+ // TODO: deliberate leak :-/
}
void config_free(cnode *root)
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
deleted file mode 100644
index 2cff9dd..0000000
--- a/libcutils/dlmalloc_stubs.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "dlmalloc-stubs"
-
-#include "log/log.h"
-
-#define UNUSED __attribute__((__unused__))
-
-/*
- * Stubs for functions defined in bionic/libc/bionic/dlmalloc.c. These
- * are used in host builds, as the host libc will not contain these
- * functions.
- */
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*) UNUSED,
- void* arg UNUSED)
-{
- ALOGW("Called host unimplemented stub: dlmalloc_inspect_all");
-}
-
-int dlmalloc_trim(size_t unused UNUSED)
-{
- ALOGW("Called host unimplemented stub: dlmalloc_trim");
- return 0;
-}
diff --git a/libcutils/fs.c b/libcutils/fs.cpp
similarity index 93%
rename from libcutils/fs.c
rename to libcutils/fs.cpp
index b253b1c..ef85acc 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/fs.h>
+
#define LOG_TAG "cutils"
/* These defines are only needed because prebuilt headers are out of date */
@@ -32,7 +34,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/fs.h>
#include <log/log.h>
#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
@@ -40,6 +41,11 @@
static int fs_prepare_path_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
int allow_fixup, int prepare_as_dir) {
+ // TODO: fix the goto hell below.
+ int type_ok;
+ int owner_match;
+ int mode_match;
+
// Check if path needs to be created
struct stat sb;
int create_result = -1;
@@ -53,14 +59,14 @@
}
// Exists, verify status
- int type_ok = prepare_as_dir ? S_ISDIR(sb.st_mode) : S_ISREG(sb.st_mode);
+ type_ok = prepare_as_dir ? S_ISDIR(sb.st_mode) : S_ISREG(sb.st_mode);
if (!type_ok) {
ALOGE("Not a %s: %s", (prepare_as_dir ? "directory" : "regular file"), path);
return -1;
}
- int owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
- int mode_match = ((sb.st_mode & ALL_PERMS) == mode);
+ owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
+ mode_match = ((sb.st_mode & ALL_PERMS) == mode);
if (owner_match && mode_match) {
return 0;
} else if (allow_fixup) {
@@ -188,23 +194,20 @@
#ifndef __APPLE__
int fs_mkdirs(const char* path, mode_t mode) {
- int res = 0;
- int fd = 0;
- struct stat sb;
- char* buf = strdup(path);
-
- if (*buf != '/') {
- ALOGE("Relative paths are not allowed: %s", buf);
- res = -EINVAL;
- goto done;
+ if (*path != '/') {
+ ALOGE("Relative paths are not allowed: %s", path);
+ return -EINVAL;
}
- if ((fd = open("/", 0)) == -1) {
+ int fd = open("/", 0);
+ if (fd == -1) {
ALOGE("Failed to open(/): %s", strerror(errno));
- res = -errno;
- goto done;
+ return -errno;
}
+ struct stat sb;
+ int res = 0;
+ char* buf = strdup(path);
char* segment = buf + 1;
char* p = segment;
while (*p != '\0') {
@@ -266,7 +269,6 @@
done_close:
close(fd);
-done:
free(buf);
return res;
}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 7603ffc..f45472e 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <private/fs_config.h>
+
// This file is used to define the properties of the filesystem
// images generated by build tools (mkbootfs and mkyaffs2image) and
// by the device side of adb.
@@ -31,7 +33,6 @@
#include <log/log.h>
#include <private/android_filesystem_config.h>
-#include <private/fs_config.h>
#include <utils/Compat.h>
#ifndef O_BINARY
diff --git a/libcutils/hashmap.c b/libcutils/hashmap.cpp
similarity index 96%
rename from libcutils/hashmap.c
rename to libcutils/hashmap.cpp
index ede3b98..65b6ab1 100644
--- a/libcutils/hashmap.c
+++ b/libcutils/hashmap.cpp
@@ -15,6 +15,7 @@
*/
#include <cutils/hashmap.h>
+
#include <assert.h>
#include <errno.h>
#include <cutils/threads.h>
@@ -45,7 +46,7 @@
assert(hash != NULL);
assert(equals != NULL);
- Hashmap* map = malloc(sizeof(Hashmap));
+ Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
if (map == NULL) {
return NULL;
}
@@ -58,7 +59,7 @@
map->bucketCount <<= 1;
}
- map->buckets = calloc(map->bucketCount, sizeof(Entry*));
+ map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
if (map->buckets == NULL) {
free(map);
return NULL;
@@ -106,7 +107,7 @@
if (map->size > (map->bucketCount * 3 / 4)) {
// Start off with a 0.33 load factor.
size_t newBucketCount = map->bucketCount << 1;
- Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*));
+ Entry** newBuckets = static_cast<Entry**>(calloc(newBucketCount, sizeof(Entry*)));
if (newBuckets == NULL) {
// Abort expansion.
return;
@@ -171,7 +172,7 @@
}
static Entry* createEntry(void* key, int hash, void* value) {
- Entry* entry = malloc(sizeof(Entry));
+ Entry* entry = static_cast<Entry*>(malloc(sizeof(Entry)));
if (entry == NULL) {
return NULL;
}
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index a903adb..99030ed 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -17,6 +17,7 @@
#ifndef __CUTILS_ANDROID_REBOOT_H__
#define __CUTILS_ANDROID_REBOOT_H__
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libcutils/include/cutils/partition_utils.h b/libcutils/include/cutils/partition_utils.h
index 72ca80d..7518559 100644
--- a/libcutils/include/cutils/partition_utils.h
+++ b/libcutils/include/cutils/partition_utils.h
@@ -17,6 +17,8 @@
#ifndef __CUTILS_PARTITION_WIPED_H__
#define __CUTILS_PARTITION_WIPED_H__
+#include <sys/cdefs.h>
+
__BEGIN_DECLS
int partition_wiped(char *source);
diff --git a/libcutils/include/cutils/qtaguid.h b/libcutils/include/cutils/qtaguid.h
index 803fe0d..3f5e41f 100644
--- a/libcutils/include/cutils/qtaguid.h
+++ b/libcutils/include/cutils/qtaguid.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,18 +17,14 @@
#ifndef __CUTILS_QTAGUID_H
#define __CUTILS_QTAGUID_H
-#include <stdint.h>
#include <sys/types.h>
-#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
- * Set tags (and owning UIDs) for network sockets. The socket must be untagged
- * by calling qtaguid_untagSocket() before closing it, otherwise the qtaguid
- * module will keep a reference to it even after close.
+ * Set tags (and owning UIDs) for network sockets.
*/
extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid);
@@ -46,8 +42,8 @@
/*
* Delete all tag info that relates to the given tag an uid.
- * If the tag is 0, then ALL info about the uid is freeded.
- * The delete data also affects active tagged socketd, which are
+ * If the tag is 0, then ALL info about the uid is freed.
+ * The delete data also affects active tagged sockets, which are
* then untagged.
* The calling process can only operate on its own tags.
* Unless it is part of the happy AID_NET_BW_ACCT group.
diff --git a/libcutils/include/cutils/record_stream.h b/libcutils/include/cutils/record_stream.h
index bfac87a..bcfc80d 100644
--- a/libcutils/include/cutils/record_stream.h
+++ b/libcutils/include/cutils/record_stream.h
@@ -25,6 +25,7 @@
extern "C" {
#endif
+#include <stddef.h>
typedef struct RecordStream RecordStream;
diff --git a/libcutils/include/private/canned_fs_config.h b/libcutils/include/private/canned_fs_config.h
index 71e1537..135b91c 100644
--- a/libcutils/include/private/canned_fs_config.h
+++ b/libcutils/include/private/canned_fs_config.h
@@ -19,8 +19,12 @@
#include <inttypes.h>
+__BEGIN_DECLS
+
int load_canned_fs_config(const char* fn);
void canned_fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid,
unsigned* gid, unsigned* mode, uint64_t* capabilities);
+__END_DECLS
+
#endif
diff --git a/libcutils/include/private/fs_config.h b/libcutils/include/private/fs_config.h
index aab5042..8926491 100644
--- a/libcutils/include/private/fs_config.h
+++ b/libcutils/include/private/fs_config.h
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#include <sys/types.h>
#if defined(__BIONIC__)
#include <linux/capability.h>
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.cpp
similarity index 95%
rename from libcutils/iosched_policy.c
rename to libcutils/iosched_policy.cpp
index 13c2ceb..012c537 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#include <cutils/iosched_policy.h>
+
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -21,8 +23,6 @@
#include <string.h>
#include <unistd.h>
-#include <cutils/iosched_policy.h>
-
#if defined(__ANDROID__)
#define IOPRIO_WHO_PROCESS (1)
#define IOPRIO_CLASS_SHIFT (13)
@@ -49,7 +49,7 @@
return -1;
}
- *clazz = (rc >> IOPRIO_CLASS_SHIFT);
+ *clazz = static_cast<IoSchedClass>(rc >> IOPRIO_CLASS_SHIFT);
*ioprio = (rc & 0xff);
#else
*clazz = IoSchedClass_NONE;
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index d301276..6a9f4df 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/klog.h>
+
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -25,7 +27,6 @@
#include <unistd.h>
#include <cutils/android_get_control_file.h>
-#include <cutils/klog.h>
static int klog_level = KLOG_INFO_LEVEL;
diff --git a/libcutils/load_file.c b/libcutils/load_file.cpp
similarity index 97%
rename from libcutils/load_file.c
rename to libcutils/load_file.cpp
index 99f2965..346105c 100644
--- a/libcutils/load_file.c
+++ b/libcutils/load_file.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#include <cutils/misc.h>
+
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.cpp
similarity index 90%
rename from libcutils/multiuser.c
rename to libcutils/multiuser.cpp
index 61403f4..0fd3d0c 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.cpp
@@ -53,9 +53,11 @@
}
}
-gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id) {
+gid_t multiuser_get_shared_gid(userid_t, appid_t app_id) {
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
- return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_SHARED_GID_START);
+ return (app_id - AID_APP_START) + AID_SHARED_GID_START;
+ } else if (app_id >= AID_ROOT && app_id <= AID_APP_START) {
+ return app_id;
} else {
return -1;
}
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.cpp
similarity index 96%
rename from libcutils/native_handle.c
rename to libcutils/native_handle.cpp
index 95bbc41..66f7a3d 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.cpp
@@ -45,7 +45,7 @@
}
size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
- native_handle_t* h = malloc(mallocSize);
+ native_handle_t* h = static_cast<native_handle_t*>(malloc(mallocSize));
if (h) {
h->version = sizeof(native_handle_t);
h->numFds = numFds;
diff --git a/libcutils/partition_utils.c b/libcutils/partition_utils.cpp
similarity index 97%
rename from libcutils/partition_utils.c
rename to libcutils/partition_utils.cpp
index 823b162..6735d6c 100644
--- a/libcutils/partition_utils.c
+++ b/libcutils/partition_utils.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/partition_utils.h>
+
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mount.h> /* for BLKGETSIZE */
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 25ff1a3..5dbbeba 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/properties.h>
+
#define LOG_TAG "properties"
// #define LOG_NDEBUG 0
@@ -25,7 +27,6 @@
#include <string.h>
#include <unistd.h>
-#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <log/log.h>
diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp
new file mode 100644
index 0000000..b94d134
--- /dev/null
+++ b/libcutils/qtaguid.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/qtaguid.h>
+
+// #define LOG_NDEBUG 0
+
+#define LOG_TAG "qtaguid"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <log/log.h>
+
+class netdHandler {
+ public:
+ int (*netdTagSocket)(int, uint32_t, uid_t);
+ int (*netdUntagSocket)(int);
+ int (*netdSetCounterSet)(uint32_t, uid_t);
+ int (*netdDeleteTagData)(uint32_t, uid_t);
+};
+
+int dummyTagSocket(int, uint32_t, uid_t) {
+ return -EREMOTEIO;
+}
+
+int dummyUntagSocket(int) {
+ return -EREMOTEIO;
+}
+
+int dummySetCounterSet(uint32_t, uid_t) {
+ return -EREMOTEIO;
+}
+
+int dummyDeleteTagData(uint32_t, uid_t) {
+ return -EREMOTEIO;
+}
+
+netdHandler initHandler(void) {
+ netdHandler handler = {dummyTagSocket, dummyUntagSocket, dummySetCounterSet, dummyDeleteTagData};
+
+ void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW);
+ if (!netdClientHandle) {
+ ALOGE("Failed to open libnetd_client.so: %s", dlerror());
+ return handler;
+ }
+
+ handler.netdTagSocket = (int (*)(int, uint32_t, uid_t))dlsym(netdClientHandle, "tagSocket");
+ if (!handler.netdTagSocket) {
+ ALOGE("load netdTagSocket handler failed: %s", dlerror());
+ }
+
+ handler.netdUntagSocket = (int (*)(int))dlsym(netdClientHandle, "untagSocket");
+ if (!handler.netdUntagSocket) {
+ ALOGE("load netdUntagSocket handler failed: %s", dlerror());
+ }
+
+ handler.netdSetCounterSet = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "setCounterSet");
+ if (!handler.netdSetCounterSet) {
+ ALOGE("load netdSetCounterSet handler failed: %s", dlerror());
+ }
+
+ handler.netdDeleteTagData = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "deleteTagData");
+ if (!handler.netdDeleteTagData) {
+ ALOGE("load netdDeleteTagData handler failed: %s", dlerror());
+ }
+ return handler;
+}
+
+// The language guarantees that this object will be initialized in a thread-safe way.
+static netdHandler& getHandler() {
+ static netdHandler instance = initHandler();
+ return instance;
+}
+
+int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) {
+ // Check the socket fd passed to us is still valid before we load the netd
+ // client. Pass a already closed socket fd to netd client may let netd open
+ // the unix socket with the same fd number and pass it to server for
+ // tagging.
+ // TODO: move the check into netdTagSocket.
+ int res = fcntl(sockfd, F_GETFD);
+ if (res < 0) return res;
+
+ ALOGV("Tagging socket %d with tag %u for uid %d", sockfd, tag, uid);
+ return getHandler().netdTagSocket(sockfd, tag, uid);
+}
+
+int qtaguid_untagSocket(int sockfd) {
+ // Similiar to tag socket. We need a check before untag to make sure untag a closed socket fail
+ // as expected.
+ // TODO: move the check into netdTagSocket.
+ int res = fcntl(sockfd, F_GETFD);
+ if (res < 0) return res;
+
+ ALOGV("Untagging socket %d", sockfd);
+ return getHandler().netdUntagSocket(sockfd);
+}
+
+int qtaguid_setCounterSet(int counterSetNum, uid_t uid) {
+ ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid);
+ return getHandler().netdSetCounterSet(counterSetNum, uid);
+}
+
+int qtaguid_deleteTagData(int tag, uid_t uid) {
+ ALOGV("Deleting tag data with tag %u for uid %d", tag, uid);
+ return getHandler().netdDeleteTagData(tag, uid);
+}
diff --git a/libcutils/record_stream.c b/libcutils/record_stream.cpp
similarity index 99%
rename from libcutils/record_stream.c
rename to libcutils/record_stream.cpp
index 2bc4226..5a86b83 100644
--- a/libcutils/record_stream.c
+++ b/libcutils/record_stream.cpp
@@ -15,11 +15,12 @@
** limitations under the License.
*/
+#include <cutils/record_stream.h>
+
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
-#include <cutils/record_stream.h>
#include <string.h>
#include <stdint.h>
#if defined(_WIN32)
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index b00fa85..0e6d333 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#include <cutils/sched_policy.h>
+
#define LOG_TAG "SchedPolicy"
#include <errno.h>
@@ -24,7 +26,6 @@
#include <unistd.h>
#include <log/log.h>
-#include <cutils/sched_policy.h>
#define UNUSED __attribute__((__unused__))
diff --git a/libcutils/socket_inaddr_any_server_unix.c b/libcutils/socket_inaddr_any_server_unix.cpp
similarity index 99%
rename from libcutils/socket_inaddr_any_server_unix.c
rename to libcutils/socket_inaddr_any_server_unix.cpp
index 387258f..27c5333 100644
--- a/libcutils/socket_inaddr_any_server_unix.c
+++ b/libcutils/socket_inaddr_any_server_unix.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#include <cutils/sockets.h>
+
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
@@ -25,8 +27,6 @@
#include <sys/types.h>
#include <netinet/in.h>
-#include <cutils/sockets.h>
-
#define LISTEN_BACKLOG 4
/* open listen() port on any interface */
diff --git a/libcutils/socket_inaddr_any_server_windows.c b/libcutils/socket_inaddr_any_server_windows.cpp
similarity index 99%
rename from libcutils/socket_inaddr_any_server_windows.c
rename to libcutils/socket_inaddr_any_server_windows.cpp
index c15200a..1d73206 100644
--- a/libcutils/socket_inaddr_any_server_windows.c
+++ b/libcutils/socket_inaddr_any_server_windows.cpp
@@ -26,10 +26,10 @@
* SUCH DAMAGE.
*/
-#include <errno.h>
-
#include <cutils/sockets.h>
+#include <errno.h>
+
#define LISTEN_BACKLOG 4
extern bool initialize_windows_sockets();
diff --git a/libcutils/socket_local_client_unix.c b/libcutils/socket_local_client_unix.cpp
similarity index 99%
rename from libcutils/socket_local_client_unix.c
rename to libcutils/socket_local_client_unix.cpp
index 92fb9f1..68b2b0c 100644
--- a/libcutils/socket_local_client_unix.c
+++ b/libcutils/socket_local_client_unix.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
+#include <cutils/sockets.h>
+
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <cutils/sockets.h>
-
#if defined(_WIN32)
int socket_local_client(const char *name, int namespaceId, int type)
diff --git a/libcutils/socket_local_server_unix.c b/libcutils/socket_local_server_unix.cpp
similarity index 94%
rename from libcutils/socket_local_server_unix.c
rename to libcutils/socket_local_server_unix.cpp
index db9e1e0..855e5da 100644
--- a/libcutils/socket_local_server_unix.c
+++ b/libcutils/socket_local_server_unix.cpp
@@ -94,7 +94,7 @@
* Returns fd on success, -1 on fail
*/
-int socket_local_server(const char *name, int namespace, int type)
+int socket_local_server(const char *name, int namespaceId, int type)
{
int err;
int s;
@@ -102,7 +102,7 @@
s = socket(AF_LOCAL, type, 0);
if (s < 0) return -1;
- err = socket_local_server_bind(s, name, namespace);
+ err = socket_local_server_bind(s, name, namespaceId);
if (err < 0) {
close(s);
diff --git a/libcutils/socket_network_client_unix.c b/libcutils/socket_network_client_unix.cpp
similarity index 99%
rename from libcutils/socket_network_client_unix.c
rename to libcutils/socket_network_client_unix.cpp
index 1b87c49..be3c535 100644
--- a/libcutils/socket_network_client_unix.c
+++ b/libcutils/socket_network_client_unix.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#include <cutils/sockets.h>
+
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
@@ -27,8 +29,6 @@
#include <netinet/in.h>
#include <netdb.h>
-#include <cutils/sockets.h>
-
static int toggle_O_NONBLOCK(int s) {
int flags = fcntl(s, F_GETFL);
if (flags == -1 || fcntl(s, F_SETFL, flags ^ O_NONBLOCK) == -1) {
diff --git a/libcutils/socket_network_client_windows.c b/libcutils/socket_network_client_windows.cpp
similarity index 100%
rename from libcutils/socket_network_client_windows.c
rename to libcutils/socket_network_client_windows.cpp
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index e91f358..2849aa8 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/sockets.h>
+
#define LOG_TAG "socket-unix"
#include <stdio.h>
@@ -26,7 +28,6 @@
#include <unistd.h>
#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
#include <log/log.h>
#include "android_get_control_env.h"
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index 3064c70..df14712 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -37,7 +37,7 @@
// Both adb (1) and Chrome (2) purposefully avoid WSACleanup() with no issues.
// (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp
// (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc
-extern "C" bool initialize_windows_sockets() {
+bool initialize_windows_sockets() {
// There's no harm in calling WSAStartup() multiple times but no benefit
// either, we may as well skip it after the first.
static bool init_success = false;
@@ -85,6 +85,6 @@
return -1;
}
-int android_get_control_socket(const char* name) {
+int android_get_control_socket(const char*) {
return -1;
}
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.cpp
similarity index 90%
rename from libcutils/str_parms.c
rename to libcutils/str_parms.cpp
index 8dafded..139d62f 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/str_parms.h>
+
#define LOG_TAG "str_params"
//#define LOG_NDEBUG 0
@@ -26,7 +28,6 @@
#include <cutils/hashmap.h>
#include <cutils/memory.h>
-#include <cutils/str_parms.h>
#include <log/log.h>
#define UNUSED __attribute__((unused))
@@ -62,30 +63,24 @@
static int str_hash_fn(void *str)
{
uint32_t hash = 5381;
- char *p;
- for (p = str; p && *p; p++)
+ for (char* p = static_cast<char*>(str); p && *p; p++)
hash = ((hash << 5) + hash) + *p;
return (int)hash;
}
struct str_parms *str_parms_create(void)
{
- struct str_parms *str_parms;
+ str_parms* s = static_cast<str_parms*>(calloc(1, sizeof(str_parms)));
+ if (!s) return NULL;
- str_parms = calloc(1, sizeof(struct str_parms));
- if (!str_parms)
+ s->map = hashmapCreate(5, str_hash_fn, str_eq);
+ if (!s->map) {
+ free(s);
return NULL;
+ }
- str_parms->map = hashmapCreate(5, str_hash_fn, str_eq);
- if (!str_parms->map)
- goto err;
-
- return str_parms;
-
-err:
- free(str_parms);
- return NULL;
+ return s;
}
struct remove_ctxt {
@@ -95,7 +90,7 @@
static bool remove_pair(void *key, void *value, void *context)
{
- struct remove_ctxt *ctxt = context;
+ remove_ctxt* ctxt = static_cast<remove_ctxt*>(context);
bool should_continue;
/*
@@ -109,7 +104,7 @@
if (!ctxt->key) {
should_continue = true;
goto do_remove;
- } else if (!strcmp(ctxt->key, key)) {
+ } else if (!strcmp(ctxt->key, static_cast<const char*>(key))) {
should_continue = false;
goto do_remove;
}
@@ -292,9 +287,8 @@
int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
int len)
{
- char *value;
-
- value = hashmapGet(str_parms->map, (void *)key);
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)key));
if (value)
return strlcpy(val, value, len);
@@ -303,10 +297,10 @@
int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
{
- char *value;
char *end;
- value = hashmapGet(str_parms->map, (void *)key);
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)key));
if (!value)
return -ENOENT;
@@ -321,10 +315,10 @@
float *val)
{
float out;
- char *value;
char *end;
- value = hashmapGet(str_parms->map, (void *)key);
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)(key)));
if (!value)
return -ENOENT;
@@ -338,7 +332,7 @@
static bool combine_strings(void *key, void *value, void *context)
{
- char **old_str = context;
+ char** old_str = static_cast<char**>(context);
char *new_str;
int ret;
diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.cpp
similarity index 97%
rename from libcutils/strdup16to8.c
rename to libcutils/strdup16to8.cpp
index 4dc987e..d89181e 100644
--- a/libcutils/strdup16to8.c
+++ b/libcutils/strdup16to8.cpp
@@ -15,10 +15,10 @@
** limitations under the License.
*/
-#include <limits.h> /* for SIZE_MAX */
-
#include <cutils/jstring.h>
+
#include <assert.h>
+#include <limits.h> /* for SIZE_MAX */
#include <stdlib.h>
@@ -145,14 +145,11 @@
*/
char * strndup16to8 (const char16_t* s, size_t n)
{
- char* ret;
- size_t len;
-
if (s == NULL) {
return NULL;
}
- len = strnlen16to8(s, n);
+ size_t len = strnlen16to8(s, n);
/* We are paranoid, and we check for SIZE_MAX-1
* too since it is an overflow value for our
@@ -161,7 +158,7 @@
if (len >= SIZE_MAX-1)
return NULL;
- ret = malloc(len + 1);
+ char* ret = static_cast<char*>(malloc(len + 1));
if (ret == NULL)
return NULL;
diff --git a/libcutils/strdup8to16.c b/libcutils/strdup8to16.cpp
similarity index 98%
rename from libcutils/strdup8to16.c
rename to libcutils/strdup8to16.cpp
index c23cf8b..d1e51b9 100644
--- a/libcutils/strdup8to16.c
+++ b/libcutils/strdup8to16.cpp
@@ -16,9 +16,10 @@
*/
#include <cutils/jstring.h>
+
#include <assert.h>
-#include <stdlib.h>
#include <limits.h>
+#include <stdlib.h>
/* See http://www.unicode.org/reports/tr22/ for discussion
* on invalid sequences
@@ -116,7 +117,7 @@
int i;
/* Mask for leader byte for lengths 1, 2, 3, and 4 respectively*/
- static const char leaderMask[4] = {0xff, 0x1f, 0x0f, 0x07};
+ static const unsigned char leaderMask[4] = {0xff, 0x1f, 0x0f, 0x07};
/* Bytes that start with bits "10" are not leading characters. */
if (((**pUtf8Ptr) & 0xc0) == 0x80) {
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index 2f9d854..4b0fd13 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -57,7 +57,10 @@
EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
EXPECT_EQ(20000U, multiuser_get_cache_gid(0, 10000));
EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 1000));
EXPECT_EQ(1020000U, multiuser_get_cache_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 50000));
}
TEST(MultiuserTest, TestExt) {
@@ -77,9 +80,12 @@
}
TEST(MultiuserTest, TestShared) {
- EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 0));
- EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(0U, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(1000U, multiuser_get_shared_gid(0, 1000));
EXPECT_EQ(50000U, multiuser_get_shared_gid(0, 10000));
EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
- EXPECT_EQ(1050000U, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(0U, multiuser_get_shared_gid(10, 0));
+ EXPECT_EQ(1000U, multiuser_get_shared_gid(10, 1000));
+ EXPECT_EQ(50000U, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(10, 50000));
}
diff --git a/libcutils/tests/trace-dev_test.cpp b/libcutils/tests/trace-dev_test.cpp
index edf981b..f8d4f00 100644
--- a/libcutils/tests/trace-dev_test.cpp
+++ b/libcutils/tests/trace-dev_test.cpp
@@ -25,7 +25,7 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-#include "../trace-dev.c"
+#include "../trace-dev.cpp"
class TraceDevTest : public ::testing::Test {
protected:
diff --git a/libcutils/threads.c b/libcutils/threads.cpp
similarity index 96%
rename from libcutils/threads.c
rename to libcutils/threads.cpp
index 4bae39e..a7e6b2d 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.cpp
@@ -14,7 +14,7 @@
** limitations under the License.
*/
-#include "cutils/threads.h"
+#include <cutils/threads.h>
// For gettid.
#if defined(__APPLE__)
@@ -84,7 +84,7 @@
void thread_store_set( thread_store_t* store,
void* value,
- thread_store_destruct_t destroy )
+ thread_store_destruct_t /*destroy*/ )
{
/* XXX: can't use destructor on thread exit */
if (!store->lock_init) {
diff --git a/libcutils/trace-container.c b/libcutils/trace-container.cpp
similarity index 99%
rename from libcutils/trace-container.c
rename to libcutils/trace-container.cpp
index 03e91b1..d981f8f 100644
--- a/libcutils/trace-container.c
+++ b/libcutils/trace-container.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/trace.h>
+
#include "trace-dev.inc"
#include <cutils/sockets.h>
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.cpp
similarity index 98%
rename from libcutils/trace-dev.c
rename to libcutils/trace-dev.cpp
index 4468e83..4da8215 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <cutils/trace.h>
+
#include "trace-dev.inc"
static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.cpp
similarity index 100%
rename from libcutils/trace-host.c
rename to libcutils/trace-host.cpp
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index d01708d..3813e6e 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -95,6 +95,8 @@
size_t len);
int __android_log_bswrite(int32_t tag, const char* payload);
+int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len);
+
#define android_bWriteLog(tag, payload, len) \
__android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
index 7bfa277..c44f5a2 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -31,8 +31,9 @@
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_CRASH = 4,
- LOG_ID_SECURITY = 5,
- LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+ LOG_ID_STATS = 5,
+ LOG_ID_SECURITY = 6,
+ LOG_ID_KERNEL = 7, /* place last, third-parties can not use it */
LOG_ID_MAX
} log_id_t;
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 59ea5ef..a59cb87 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -301,7 +301,7 @@
const char* msg;
ssize_t len;
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
+ if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
return -EINVAL;
}
@@ -326,7 +326,9 @@
}
return (id == LOG_ID_EVENTS)
? __android_log_bwrite(context->tag, msg, len)
- : __android_log_security_bwrite(context->tag, msg, len);
+ : ((id == LOG_ID_STATS)
+ ? __android_log_stats_bwrite(context->tag, msg, len)
+ : __android_log_security_bwrite(context->tag, msg, len));
}
LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index a5a83e0..479bbfe 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -22,12 +22,13 @@
/* In the future, we would like to make this list extensible */
static const char* LOG_NAME[LOG_ID_MAX] = {
- /* clang-format off */
+ /* clang-format off */
[LOG_ID_MAIN] = "main",
[LOG_ID_RADIO] = "radio",
[LOG_ID_EVENTS] = "events",
[LOG_ID_SYSTEM] = "system",
[LOG_ID_CRASH] = "crash",
+ [LOG_ID_STATS] = "stats",
[LOG_ID_SECURITY] = "security",
[LOG_ID_KERNEL] = "kernel",
/* clang-format on */
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 84feb20..589ce84 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -546,6 +546,19 @@
return write_to_log(LOG_ID_EVENTS, vec, 2);
}
+LIBLOG_ABI_PUBLIC int __android_log_stats_bwrite(int32_t tag,
+ const void* payload,
+ size_t len) {
+ struct iovec vec[2];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
+
+ return write_to_log(LOG_ID_STATS, vec, 2);
+}
+
LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
const void* payload,
size_t len) {
diff --git a/libqtaguid/Android.bp b/libqtaguid/Android.bp
new file mode 100644
index 0000000..de632ca
--- /dev/null
+++ b/libqtaguid/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+ name: "libqtaguid_headers",
+ vendor_available: false,
+ host_supported: false,
+ export_include_dirs: ["include"],
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+}
+
+cc_library {
+ name: "libqtaguid",
+ vendor_available: false,
+ host_supported: false,
+ target: {
+ android: {
+ srcs: [
+ "qtaguid.c",
+ ],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ },
+ },
+
+ shared_libs: ["liblog"],
+ header_libs: [
+ "libqtaguid_headers",
+ ],
+ export_header_lib_headers: ["libqtaguid_headers"],
+ local_include_dirs: ["include"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+}
diff --git a/libqtaguid/include/qtaguid/qtaguid.h b/libqtaguid/include/qtaguid/qtaguid.h
new file mode 100644
index 0000000..72285e5
--- /dev/null
+++ b/libqtaguid/include/qtaguid/qtaguid.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LEGACY_QTAGUID_H
+#define __LEGACY_QTAGUID_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Set tags (and owning UIDs) for network sockets. The socket must be untagged
+ * by calling qtaguid_untagSocket() before closing it, otherwise the qtaguid
+ * module will keep a reference to it even after close.
+ */
+extern int legacy_tagSocket(int sockfd, int tag, uid_t uid);
+
+/*
+ * Untag a network socket before closing.
+ */
+extern int legacy_untagSocket(int sockfd);
+
+/*
+ * For the given uid, switch counter sets.
+ * The kernel only keeps a limited number of sets.
+ * 2 for now.
+ */
+extern int legacy_setCounterSet(int counterSetNum, uid_t uid);
+
+/*
+ * Delete all tag info that relates to the given tag an uid.
+ * If the tag is 0, then ALL info about the uid is freeded.
+ * The delete data also affects active tagged socketd, which are
+ * then untagged.
+ * The calling process can only operate on its own tags.
+ * Unless it is part of the happy AID_NET_BW_ACCT group.
+ * In which case it can clobber everything.
+ */
+extern int legacy_deleteTagData(int tag, uid_t uid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LEGACY_QTAGUID_H */
diff --git a/libcutils/qtaguid.c b/libqtaguid/qtaguid.c
similarity index 72%
rename from libcutils/qtaguid.c
rename to libqtaguid/qtaguid.c
index 22b8325..cd38bad 100644
--- a/libcutils/qtaguid.c
+++ b/libqtaguid/qtaguid.c
@@ -27,12 +27,10 @@
#include <unistd.h>
#include <log/log.h>
-#include <cutils/qtaguid.h>
+#include <qtaguid/qtaguid.h>
static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
static const int CTRL_MAX_INPUT_LEN = 128;
-static const char *GLOBAL_PACIFIER_PARAM = "/sys/module/xt_qtaguid/parameters/passive";
-static const char *TAG_PACIFIER_PARAM = "/sys/module/xt_qtaguid/parameters/tag_tracking_passive";
/*
* One per proccess.
@@ -46,7 +44,7 @@
pthread_once_t resTrackInitDone = PTHREAD_ONCE_INIT;
/* Only call once per process. */
-void qtaguid_resTrack(void) {
+void legacy_resTrack(void) {
resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC));
}
@@ -55,7 +53,7 @@
* 0 on success.
* -errno on failure.
*/
-static int write_ctrl(const char *cmd) {
+static int write_ctrl(const char* cmd) {
int fd, res, savedErrno;
ALOGV("write_ctrl(%s)", cmd);
@@ -79,28 +77,12 @@
return -savedErrno;
}
-static int write_param(const char *param_path, const char *value) {
- int param_fd;
- int res;
-
- param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY | O_CLOEXEC));
- if (param_fd < 0) {
- return -errno;
- }
- res = TEMP_FAILURE_RETRY(write(param_fd, value, strlen(value)));
- if (res < 0) {
- return -errno;
- }
- close(param_fd);
- return 0;
-}
-
-int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) {
+int legacy_tagSocket(int sockfd, int tag, uid_t uid) {
char lineBuf[CTRL_MAX_INPUT_LEN];
int res;
uint64_t kTag = ((uint64_t)tag << 32);
- pthread_once(&resTrackInitDone, qtaguid_resTrack);
+ pthread_once(&resTrackInitDone, legacy_resTrack);
snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid);
@@ -108,14 +90,14 @@
res = write_ctrl(lineBuf);
if (res < 0) {
- ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d",
- sockfd, kTag, tag, uid, res);
+ ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d", sockfd, kTag,
+ tag, uid, res);
}
return res;
}
-int qtaguid_untagSocket(int sockfd) {
+int legacy_untagSocket(int sockfd) {
char lineBuf[CTRL_MAX_INPUT_LEN];
int res;
@@ -130,7 +112,7 @@
return res;
}
-int qtaguid_setCounterSet(int counterSetNum, uid_t uid) {
+int legacy_setCounterSet(int counterSetNum, uid_t uid) {
char lineBuf[CTRL_MAX_INPUT_LEN];
int res;
@@ -141,34 +123,21 @@
return res;
}
-int qtaguid_deleteTagData(int tag, uid_t uid) {
+int legacy_deleteTagData(int tag, uid_t uid) {
char lineBuf[CTRL_MAX_INPUT_LEN];
int cnt = 0, res = 0;
uint64_t kTag = (uint64_t)tag << 32;
ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid);
- pthread_once(&resTrackInitDone, qtaguid_resTrack);
+ pthread_once(&resTrackInitDone, legacy_resTrack);
snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid);
res = write_ctrl(lineBuf);
if (res < 0) {
ALOGI("Deleting tag data with tag %" PRIx64 "/%d for uid %d failed with cnt=%d errno=%d",
- kTag, tag, uid, cnt, errno);
+ kTag, tag, uid, cnt, errno);
}
return res;
}
-
-int qtaguid_setPacifier(int on) {
- const char *value;
-
- value = on ? "Y" : "N";
- if (write_param(GLOBAL_PACIFIER_PARAM, value) < 0) {
- return -errno;
- }
- if (write_param(TAG_PACIFIER_PARAM, value) < 0) {
- return -errno;
- }
- return 0;
-}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 00b1ee2..7f92904 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -501,6 +501,8 @@
asprintf(&mParams[0], "INTERFACE=%s", ifname);
asprintf(&mParams[1], "LIFETIME=%u", lifetime);
mParams[2] = buf;
+ } else if (opthdr->nd_opt_type == ND_OPT_DNSSL) {
+ // TODO: support DNSSL.
} else {
SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
return false;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 40364fe..75aa427 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -130,6 +130,7 @@
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
+ "tests/UnwindOfflineTest.cpp",
"tests/UnwindTest.cpp",
"tests/UnwinderTest.cpp",
],
@@ -153,6 +154,8 @@
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
+ "tests/files/offline/straddle_arm32/*",
+ "tests/files/offline/straddle_arm64/*",
],
}
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 561d23a..2589c89 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -40,7 +40,7 @@
uint64_t AdjustPcFromFde(uint64_t pc) override {
// The eh_frame uses relative pcs.
- return pc + this->memory_.cur_offset();
+ return pc + this->memory_.cur_offset() - 4;
}
};
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index edf7ac2..48e33ee 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -18,6 +18,7 @@
#include <string.h>
#include <memory>
+#include <mutex>
#include <string>
#define LOG_TAG "unwind"
@@ -87,6 +88,7 @@
}
bool Elf::GetSoname(std::string* name) {
+ std::lock_guard<std::mutex> guard(lock_);
return valid_ && interface_->GetSoname(name);
}
@@ -95,14 +97,15 @@
}
bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
+ std::lock_guard<std::mutex> guard(lock_);
return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
(gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
addr, load_bias_, name, func_offset)));
}
// The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
- bool* finished) {
+bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
+ Memory* process_memory, bool* finished) {
if (!valid_) {
return false;
}
@@ -114,14 +117,16 @@
}
// Adjust the load bias to get the real relative pc.
- if (rel_pc < load_bias_) {
+ if (adjusted_rel_pc < load_bias_) {
return false;
}
- rel_pc -= load_bias_;
+ adjusted_rel_pc -= load_bias_;
- return interface_->Step(rel_pc, regs, process_memory, finished) ||
+ // Lock during the step which can update information in the object.
+ std::lock_guard<std::mutex> guard(lock_);
+ return interface_->Step(adjusted_rel_pc, regs, process_memory, finished) ||
(gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
+ gnu_debugdata_interface_->Step(adjusted_rel_pc, regs, process_memory, finished));
}
bool Elf::IsValidElf(Memory* memory) {
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 140d05a..5417659 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <string>
#include <unwindstack/Elf.h>
@@ -105,6 +106,9 @@
}
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
+ // Make sure no other thread is trying to add the elf to this map.
+ std::lock_guard<std::mutex> guard(mutex_);
+
if (elf) {
return elf;
}
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 5e1c0a2..56370c1 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -44,7 +44,7 @@
size_t last = maps_.size();
while (first < last) {
size_t index = (first + last) / 2;
- MapInfo* cur = &maps_[index];
+ MapInfo* cur = maps_[index];
if (pc >= cur->start && pc < cur->end) {
return cur;
} else if (pc < cur->start) {
@@ -57,22 +57,22 @@
}
// Assumes that line does not end in '\n'.
-static bool InternalParseLine(const char* line, MapInfo* map_info) {
+static MapInfo* InternalParseLine(const char* line) {
// Do not use a sscanf implementation since it is not performant.
// Example linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
char* str;
const char* old_str = line;
- map_info->start = strtoul(old_str, &str, 16);
+ uint64_t start = strtoull(old_str, &str, 16);
if (old_str == str || *str++ != '-') {
- return false;
+ return nullptr;
}
old_str = str;
- map_info->end = strtoul(old_str, &str, 16);
+ uint64_t end = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
- return false;
+ return nullptr;
}
while (std::isspace(*str)) {
@@ -81,82 +81,81 @@
// Parse permissions data.
if (*str == '\0') {
- return false;
+ return nullptr;
}
- map_info->flags = 0;
+ uint16_t flags = 0;
if (*str == 'r') {
- map_info->flags |= PROT_READ;
+ flags |= PROT_READ;
} else if (*str != '-') {
- return false;
+ return nullptr;
}
str++;
if (*str == 'w') {
- map_info->flags |= PROT_WRITE;
+ flags |= PROT_WRITE;
} else if (*str != '-') {
- return false;
+ return nullptr;
}
str++;
if (*str == 'x') {
- map_info->flags |= PROT_EXEC;
+ flags |= PROT_EXEC;
} else if (*str != '-') {
- return false;
+ return nullptr;
}
str++;
if (*str != 'p' && *str != 's') {
- return false;
+ return nullptr;
}
str++;
if (!std::isspace(*str++)) {
- return false;
+ return nullptr;
}
old_str = str;
- map_info->offset = strtoul(old_str, &str, 16);
+ uint64_t offset = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str)) {
- return false;
+ return nullptr;
}
// Ignore the 00:00 values.
old_str = str;
- (void)strtoul(old_str, &str, 16);
+ (void)strtoull(old_str, &str, 16);
if (old_str == str || *str++ != ':') {
- return false;
+ return nullptr;
}
if (std::isspace(*str)) {
- return false;
+ return nullptr;
}
// Skip the inode.
old_str = str;
- (void)strtoul(str, &str, 16);
+ (void)strtoull(str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
- return false;
+ return nullptr;
}
// Skip decimal digit.
old_str = str;
- (void)strtoul(old_str, &str, 10);
+ (void)strtoull(old_str, &str, 10);
if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
- return false;
+ return nullptr;
}
while (std::isspace(*str)) {
str++;
}
if (*str == '\0') {
- map_info->name = str;
- return true;
+ return new MapInfo(start, end, offset, flags, "");
}
// Save the name data.
- map_info->name = str;
+ std::string name(str);
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
- if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
- map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
+ flags |= MAPS_FLAGS_DEVICE_MAP;
}
- return true;
+ return new MapInfo(start, end, offset, flags, name);
}
bool Maps::Parse() {
@@ -187,8 +186,8 @@
}
*newline = '\0';
- MapInfo map_info;
- if (!InternalParseLine(line, &map_info)) {
+ MapInfo* map_info = InternalParseLine(line);
+ if (map_info == nullptr) {
return_value = false;
break;
}
@@ -205,8 +204,7 @@
Maps::~Maps() {
for (auto& map : maps_) {
- delete map.elf;
- map.elf = nullptr;
+ delete map;
}
}
@@ -222,8 +220,8 @@
end_of_line++;
}
- MapInfo map_info;
- if (!InternalParseLine(line.c_str(), &map_info)) {
+ MapInfo* map_info = InternalParseLine(line.c_str());
+ if (map_info == nullptr) {
return false;
}
maps_.push_back(map_info);
@@ -252,24 +250,27 @@
std::vector<char> name;
while (true) {
- MapInfo map_info;
- ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
+ uint64_t start;
+ ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &start, sizeof(start)));
if (bytes == 0) {
break;
}
- if (bytes == -1 || bytes != sizeof(map_info.start)) {
+ if (bytes == -1 || bytes != sizeof(start)) {
return false;
}
- bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
- if (bytes == -1 || bytes != sizeof(map_info.end)) {
+ uint64_t end;
+ bytes = TEMP_FAILURE_RETRY(read(fd, &end, sizeof(end)));
+ if (bytes == -1 || bytes != sizeof(end)) {
return false;
}
- bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
- if (bytes == -1 || bytes != sizeof(map_info.offset)) {
+ uint64_t offset;
+ bytes = TEMP_FAILURE_RETRY(read(fd, &offset, sizeof(offset)));
+ if (bytes == -1 || bytes != sizeof(offset)) {
return false;
}
- bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
- if (bytes == -1 || bytes != sizeof(map_info.flags)) {
+ uint16_t flags;
+ bytes = TEMP_FAILURE_RETRY(read(fd, &flags, sizeof(flags)));
+ if (bytes == -1 || bytes != sizeof(flags)) {
return false;
}
uint16_t len;
@@ -283,9 +284,10 @@
if (bytes == -1 || bytes != len) {
return false;
}
- map_info.name = std::string(name.data(), len);
+ maps_.push_back(new MapInfo(start, end, offset, flags, std::string(name.data(), len)));
+ } else {
+ maps_.push_back(new MapInfo(start, end, offset, flags, ""));
}
- maps_.push_back(map_info);
}
return true;
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 2e46a11..3092a62 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -32,27 +32,20 @@
namespace unwindstack {
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) {
+void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
FrameData* frame = &frames_.at(frame_num);
frame->num = frame_num;
- frame->pc = regs_->pc();
frame->sp = regs_->sp();
- frame->rel_pc = rel_pc;
+ frame->rel_pc = adjusted_rel_pc;
if (map_info == nullptr) {
+ frame->pc = regs_->pc();
return;
}
- if (adjust_pc) {
- // Don't adjust the first frame pc.
- frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
-
- // Adjust the original pc.
- frame->pc -= rel_pc - frame->rel_pc;
- }
-
+ frame->pc = map_info->start + adjusted_rel_pc;
frame->map_name = map_info->name;
frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
@@ -92,21 +85,29 @@
MapInfo* map_info = maps_->Find(regs_->pc());
uint64_t rel_pc;
+ uint64_t adjusted_rel_pc;
Elf* elf;
if (map_info == nullptr) {
rel_pc = regs_->pc();
+ adjusted_rel_pc = rel_pc;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
}
elf = map_info->GetElf(process_memory_, true);
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
+ if (adjust_pc) {
+ adjusted_rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
+ } else {
+ adjusted_rel_pc = rel_pc;
+ }
}
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
- FillInFrame(map_info, elf, rel_pc, adjust_pc);
+ FillInFrame(map_info, elf, adjusted_rel_pc);
+
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
}
@@ -133,7 +134,8 @@
in_device_map = true;
} else {
bool finished;
- stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
+ stepped = elf->Step(rel_pc, adjusted_rel_pc, map_info->elf_offset, regs_,
+ process_memory_.get(), &finished);
if (stepped && finished) {
break;
}
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 294d742..da2ddc0 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -20,6 +20,7 @@
#include <stddef.h>
#include <memory>
+#include <mutex>
#include <string>
#include <unwindstack/ElfInterface.h>
@@ -50,8 +51,8 @@
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
- bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
- bool* finished);
+ bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
+ Memory* process_memory, bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
@@ -80,6 +81,8 @@
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
uint8_t class_type_;
+ // Protect calls that can modify internal state of the interface object.
+ std::mutex lock_;
std::unique_ptr<Memory> gnu_debugdata_memory_;
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index f108766..e54b348 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -19,34 +19,48 @@
#include <stdint.h>
+#include <mutex>
#include <string>
+#include <unwindstack/Elf.h>
+
namespace unwindstack {
// Forward declarations.
-class Elf;
class Memory;
struct MapInfo {
- uint64_t start;
- uint64_t end;
- uint64_t offset;
- uint16_t flags;
+ MapInfo() = default;
+ MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
+ MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
+ : start(start), end(end), offset(offset), flags(flags), name(name) {}
+ ~MapInfo() { delete elf; }
+
+ uint64_t start = 0;
+ uint64_t end = 0;
+ uint64_t offset = 0;
+ uint16_t flags = 0;
std::string name;
Elf* elf = nullptr;
// This value is only non-zero if the offset is non-zero but there is
// no elf signature found at that offset. This indicates that the
// entire file is represented by the Memory object returned by CreateMemory,
// instead of a portion of the file.
- uint64_t elf_offset;
+ uint64_t elf_offset = 0;
// This function guarantees it will never return nullptr.
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
private:
+ MapInfo(const MapInfo&) = delete;
+ void operator=(const MapInfo&) = delete;
+
Memory* GetFileMemory();
Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
+
+ // Protect the creation of the elf object.
+ std::mutex mutex_;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 22122a9..34fef7f 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -42,11 +42,11 @@
virtual const std::string GetMapsFile() const { return ""; }
- typedef std::vector<MapInfo>::iterator iterator;
+ typedef std::vector<MapInfo*>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
- typedef std::vector<MapInfo>::const_iterator const_iterator;
+ typedef std::vector<MapInfo*>::const_iterator const_iterator;
const_iterator begin() const { return maps_.begin(); }
const_iterator end() const { return maps_.end(); }
@@ -54,11 +54,11 @@
MapInfo* Get(size_t index) {
if (index >= maps_.size()) return nullptr;
- return &maps_[index];
+ return maps_[index];
}
protected:
- std::vector<MapInfo> maps_;
+ std::vector<MapInfo*> maps_;
};
class RemoteMaps : public Maps {
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index d1461d8..c59e081 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -33,7 +33,7 @@
#if defined(__arm__)
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
void* reg_data = regs->RawData();
asm volatile(
".align 2\n"
@@ -57,7 +57,7 @@
#elif defined(__aarch64__)
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
void* reg_data = regs->RawData();
asm volatile(
"1:\n"
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 37a76b2..b64d460 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -70,7 +70,7 @@
static std::string FormatFrame(const FrameData& frame, bool bits32);
private:
- void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc);
+ void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc);
size_t max_frames_;
Maps* maps_;
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 53ee719..3a629f8 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -109,23 +109,23 @@
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x660cU, info.start);
- EXPECT_EQ(0x680cU, info.end);
+ EXPECT_EQ(0x6608U, info.start);
+ EXPECT_EQ(0x6808U, info.end);
this->eh_frame_->TestGetFdeInfo(1, &info);
EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x770cU, info.start);
- EXPECT_EQ(0x7a0cU, info.end);
+ EXPECT_EQ(0x7708U, info.start);
+ EXPECT_EQ(0x7a08U, info.end);
this->eh_frame_->TestGetFdeInfo(2, &info);
EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x890cU, info.start);
- EXPECT_EQ(0x8d0cU, info.end);
+ EXPECT_EQ(0x8908U, info.start);
+ EXPECT_EQ(0x8d08U, info.end);
this->eh_frame_->TestGetFdeInfo(3, &info);
EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a0cU, info.start);
- EXPECT_EQ(0x9f0cU, info.end);
+ EXPECT_EQ(0x9a08U, info.start);
+ EXPECT_EQ(0x9f08U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
@@ -193,23 +193,23 @@
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x661cU, info.start);
- EXPECT_EQ(0x681cU, info.end);
+ EXPECT_EQ(0x6618U, info.start);
+ EXPECT_EQ(0x6818U, info.end);
this->eh_frame_->TestGetFdeInfo(1, &info);
EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x771cU, info.start);
- EXPECT_EQ(0x7a1cU, info.end);
+ EXPECT_EQ(0x7718U, info.start);
+ EXPECT_EQ(0x7a18U, info.end);
this->eh_frame_->TestGetFdeInfo(2, &info);
EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x891cU, info.start);
- EXPECT_EQ(0x8d1cU, info.end);
+ EXPECT_EQ(0x8918U, info.start);
+ EXPECT_EQ(0x8d18U, info.end);
this->eh_frame_->TestGetFdeInfo(3, &info);
EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a1cU, info.start);
- EXPECT_EQ(0x9f1cU, info.end);
+ EXPECT_EQ(0x9a18U, info.start);
+ EXPECT_EQ(0x9f18U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
@@ -261,8 +261,8 @@
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x660aU, info.start);
- EXPECT_EQ(0x680aU, info.end);
+ EXPECT_EQ(0x6606U, info.start);
+ EXPECT_EQ(0x6806U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
@@ -304,8 +304,8 @@
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x660aU, info.start);
- EXPECT_EQ(0x680aU, info.end);
+ EXPECT_EQ(0x6606U, info.start);
+ EXPECT_EQ(0x6806U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
@@ -384,8 +384,8 @@
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x1d00cU, fde->pc_start);
- EXPECT_EQ(0x1d10cU, fde->pc_end);
+ EXPECT_EQ(0x1d008U, fde->pc_start);
+ EXPECT_EQ(0x1d108U, fde->pc_end);
EXPECT_EQ(0xf000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
@@ -428,8 +428,8 @@
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0xd01cU, fde->pc_start);
- EXPECT_EQ(0xd31cU, fde->pc_end);
+ EXPECT_EQ(0xd018U, fde->pc_start);
+ EXPECT_EQ(0xd318U, fde->pc_end);
EXPECT_EQ(0x6000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 1028ab9..64b325b 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -345,8 +345,8 @@
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x1d00cU, fde->pc_start);
- EXPECT_EQ(0x1d10cU, fde->pc_end);
+ EXPECT_EQ(0x1d008U, fde->pc_start);
+ EXPECT_EQ(0x1d108U, fde->pc_end);
EXPECT_EQ(0xf000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
@@ -387,8 +387,8 @@
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0xd01cU, fde->pc_start);
- EXPECT_EQ(0xd31cU, fde->pc_end);
+ EXPECT_EQ(0xd018U, fde->pc_start);
+ EXPECT_EQ(0xd318U, fde->pc_end);
EXPECT_EQ(0x6000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 4e48fa1..afd113d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -132,7 +132,7 @@
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
bool finished;
- ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
+ ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
@@ -273,7 +273,7 @@
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
- MapInfo map_info{.start = 0x1000, .end = 0x2000};
+ MapInfo map_info(0x1000, 0x2000);
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
@@ -306,7 +306,7 @@
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
bool finished;
- ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, ®s, &process_memory, &finished));
EXPECT_FALSE(finished);
EXPECT_EQ(15U, regs.pc());
EXPECT_EQ(13U, regs.sp());
@@ -339,7 +339,7 @@
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, ®s, &process_memory, &finished));
}
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
@@ -355,12 +355,12 @@
// Invalid relative pc given load_bias.
bool finished;
- ASSERT_FALSE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_FALSE(elf.Step(0x1004, 0x1000, 0x2000, ®s, &process_memory, &finished));
EXPECT_CALL(*interface, Step(0x3300, ®s, &process_memory, &finished))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x7300, 0x2000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, ®s, &process_memory, &finished));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
index 069386b..69163ac 100644
--- a/libunwindstack/tests/ElfTestUtils.cpp
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -47,7 +47,7 @@
ehdr->e_ehsize = sizeof(Ehdr);
}
-static std::string GetTestFileDirectory() {
+std::string TestGetFileDirectory() {
std::string exec(testing::internal::GetArgvs()[0]);
auto const value = exec.find_last_of('/');
if (value == std::string::npos) {
@@ -102,7 +102,7 @@
offset = symtab_offset + 0x100;
if (init_gnu_debugdata) {
// Read in the compressed elf data and copy it in.
- name = GetTestFileDirectory();
+ name = TestGetFileDirectory();
if (elf_class == ELFCLASS32) {
name += "elf32.xz";
} else {
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
index 6ef00e1..62cd59a 100644
--- a/libunwindstack/tests/ElfTestUtils.h
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -18,6 +18,7 @@
#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
#include <functional>
+#include <string>
namespace unwindstack {
@@ -30,6 +31,8 @@
void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
TestCopyFuncType copy_func);
+std::string TestGetFileDirectory();
+
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index d2aad49..bdcb652 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -94,7 +94,7 @@
TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
TEST_F(MapInfoCreateMemoryTest, end_le_start) {
- MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
+ MapInfo info(0x100, 0x100, 0, 0, elf_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
@@ -112,7 +112,7 @@
// Verify that if the offset is non-zero but there is no elf at the offset,
// that the full file is used.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
- MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
+ MapInfo info(0x100, 0x200, 0x100, 0, elf_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
@@ -133,7 +133,7 @@
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
- MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
+ MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
@@ -156,7 +156,7 @@
// embedded elf is bigger than the initial map, the new object is larger
// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path};
+ MapInfo info(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
@@ -172,7 +172,7 @@
}
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path};
+ MapInfo info(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 0b70d13..9973794 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -23,7 +23,9 @@
#include <sys/types.h>
#include <unistd.h>
+#include <atomic>
#include <memory>
+#include <thread>
#include <vector>
#include <android-base/file.h>
@@ -67,52 +69,52 @@
};
TEST_F(MapInfoGetElfTest, invalid) {
- MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
// The map is empty, but this should still create an invalid elf object.
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, valid32) {
- MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x3000, 0x4000, 0, PROT_READ, "");
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
}
TEST_F(MapInfoGetElfTest, valid64) {
- MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x8000, 0x9000, 0, PROT_READ, "");
Elf64_Ehdr ehdr;
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
- MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x4000, 0x8000, 0, PROT_READ, "");
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x4000 + offset, ptr, size);
});
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -120,15 +122,15 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
- MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x6000, 0x8000, 0, PROT_READ, "");
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x6000 + offset, ptr, size);
});
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -136,15 +138,15 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
- MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x2000, 0x3000, 0, PROT_READ, "");
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x2000 + offset, ptr, size);
});
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, true);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -152,15 +154,15 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
- MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+ MapInfo info(0x5000, 0x8000, 0, PROT_READ, "");
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(0x5000 + offset, ptr, size);
});
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
- ASSERT_TRUE(elf.get() != nullptr);
+ Elf* elf = info.GetElf(process_memory_, true);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -168,32 +170,36 @@
}
TEST_F(MapInfoGetElfTest, end_le_start) {
- MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path};
+ MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path);
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
+ delete info.elf;
info.elf = nullptr;
info.end = 0xfff;
- elf.reset(info.GetElf(process_memory_, false));
+ elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
+ delete info.elf;
info.elf = nullptr;
info.end = 0x2000;
- elf.reset(info.GetElf(process_memory_, false));
+ elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
}
// Verify that if the offset is non-zero but there is no elf at the offset,
// that the full file is used.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
- MapInfo info{
- .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path};
+ MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x1000);
memset(buffer.data(), 0, buffer.size());
@@ -202,7 +208,8 @@
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
ASSERT_EQ(0x100U, info.elf_offset);
@@ -221,8 +228,7 @@
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
- MapInfo info{
- .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path};
+ MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
@@ -231,7 +237,8 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -251,8 +258,7 @@
// embedded elf is bigger than the initial map, the new object is larger
// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- MapInfo info{
- .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+ MapInfo info(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
@@ -264,7 +270,8 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -279,8 +286,7 @@
}
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- MapInfo info{
- .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+ MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
std::vector<uint8_t> buffer(0x4000);
memset(buffer.data(), 0, buffer.size());
@@ -292,7 +298,8 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -307,7 +314,7 @@
}
TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
- MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""};
+ MapInfo info(0x9000, 0xa000, 0x1000, 0, "");
// Create valid elf data in process memory only.
Elf64_Ehdr ehdr;
@@ -317,21 +324,19 @@
ehdr.e_shnum = 4;
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
+ delete info.elf;
info.elf = nullptr;
info.flags = PROT_READ;
- elf.reset(info.GetElf(process_memory_, false));
+ elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
}
TEST_F(MapInfoGetElfTest, check_device_maps) {
- MapInfo info{.start = 0x7000,
- .end = 0x8000,
- .offset = 0x1000,
- .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP,
- .name = "/dev/something"};
+ MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
// Create valid elf data in process memory for this to verify that only
// the name is causing invalid elf data.
@@ -342,20 +347,68 @@
ehdr.e_shnum = 4;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ Elf* elf = info.GetElf(process_memory_, false);
+ ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
+ delete info.elf;
info.elf = nullptr;
info.name = "";
- elf.reset(info.GetElf(process_memory_, false));
+ elf = info.GetElf(process_memory_, false);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
+ delete info.elf;
info.elf = nullptr;
info.flags = PROT_READ;
- elf.reset(info.GetElf(process_memory_, false));
+ elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
}
+TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
+ static constexpr size_t kNumConcurrentThreads = 100;
+
+ Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
+ ehdr.e_shoff = 0x2000;
+ ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+ ehdr.e_shnum = 4;
+ memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
+
+ Elf* elf_in_threads[kNumConcurrentThreads];
+ std::vector<std::thread*> threads;
+
+ std::atomic_bool wait;
+ wait = true;
+ // Create all of the threads and have them do the GetElf at the same time
+ // to make it likely that a race will occur.
+ MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, "");
+ for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+ std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
+ while (wait)
+ ;
+ Elf* elf = info.GetElf(process_memory_, false);
+ elf_in_threads[i] = elf;
+ });
+ threads.push_back(thread);
+ }
+ ASSERT_TRUE(info.elf == nullptr);
+
+ // Set them all going and wait for the threads to finish.
+ wait = false;
+ for (auto thread : threads) {
+ thread->join();
+ delete thread;
+ }
+
+ // Now verify that all of the elf files are exactly the same and valid.
+ Elf* elf = info.elf;
+ ASSERT_TRUE(elf != nullptr);
+ EXPECT_TRUE(elf->valid());
+ for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+ EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
+ }
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 2d15a4e..8dc884f 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -35,7 +35,12 @@
ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
MapInfo* element = maps.Get(0);
ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
- *info = *element;
+ info->start = element->start;
+ info->end = element->end;
+ info->offset = element->offset;
+ info->flags = element->flags;
+ info->name = element->name;
+ info->elf_offset = element->elf_offset;
}
}
@@ -139,38 +144,48 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(5U, maps.Total());
- auto it = maps.begin();
- ASSERT_EQ(PROT_NONE, it->flags);
- ASSERT_EQ(0x1000U, it->start);
- ASSERT_EQ(0x2000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(PROT_READ, it->flags);
- ASSERT_EQ(0x2000U, it->start);
- ASSERT_EQ(0x3000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(PROT_WRITE, it->flags);
- ASSERT_EQ(0x3000U, it->start);
- ASSERT_EQ(0x4000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(PROT_EXEC, it->flags);
- ASSERT_EQ(0x4000U, it->start);
- ASSERT_EQ(0x5000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, it->flags);
- ASSERT_EQ(0x5000U, it->start);
- ASSERT_EQ(0x6000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(it, maps.end());
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(PROT_NONE, info->flags);
+ EXPECT_EQ(0x1000U, info->start);
+ EXPECT_EQ(0x2000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ("", info->name);
+
+ info = maps.Get(1);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(PROT_READ, info->flags);
+ EXPECT_EQ(0x2000U, info->start);
+ EXPECT_EQ(0x3000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ("", info->name);
+
+ info = maps.Get(2);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(PROT_WRITE, info->flags);
+ EXPECT_EQ(0x3000U, info->start);
+ EXPECT_EQ(0x4000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ("", info->name);
+
+ info = maps.Get(3);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(PROT_EXEC, info->flags);
+ EXPECT_EQ(0x4000U, info->start);
+ EXPECT_EQ(0x5000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ("", info->name);
+
+ info = maps.Get(4);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+ EXPECT_EQ(0x5000U, info->start);
+ EXPECT_EQ(0x6000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ("", info->name);
+
+ ASSERT_TRUE(maps.Get(5) == nullptr);
}
TEST(MapsTest, parse_name) {
@@ -181,26 +196,32 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto it = maps.begin();
- ASSERT_EQ("", it->name);
- ASSERT_EQ(0x7b29b000U, it->start);
- ASSERT_EQ(0x7b29e000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
- ++it;
- ASSERT_EQ("/system/lib/fake.so", it->name);
- ASSERT_EQ(0x7b29e000U, it->start);
- ASSERT_EQ(0x7b29f000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
- ++it;
- ASSERT_EQ("", it->name);
- ASSERT_EQ(0x7b29f000U, it->start);
- ASSERT_EQ(0x7b2a0000U, it->end);
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
- ++it;
- ASSERT_EQ(it, maps.end());
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ("", info->name);
+ EXPECT_EQ(0x7b29b000U, info->start);
+ EXPECT_EQ(0x7b29e000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+ info = maps.Get(1);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ("/system/lib/fake.so", info->name);
+ EXPECT_EQ(0x7b29e000U, info->start);
+ EXPECT_EQ(0x7b29f000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+ info = maps.Get(2);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ("", info->name);
+ EXPECT_EQ(0x7b29f000U, info->start);
+ EXPECT_EQ(0x7b2a0000U, info->end);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+ ASSERT_TRUE(maps.Get(3) == nullptr);
}
TEST(MapsTest, parse_offset) {
@@ -210,20 +231,60 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(2U, maps.Total());
- auto it = maps.begin();
- ASSERT_EQ(0U, it->offset);
- ASSERT_EQ(0xa000U, it->start);
- ASSERT_EQ(0xe000U, it->end);
- ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
- ASSERT_EQ("/system/lib/fake.so", it->name);
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0U, info->offset);
+ EXPECT_EQ(0xa000U, info->start);
+ EXPECT_EQ(0xe000U, info->end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+ EXPECT_EQ("/system/lib/fake.so", info->name);
+
+ info = maps.Get(1);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0xa12345U, info->offset);
+ EXPECT_EQ(0xe000U, info->start);
+ EXPECT_EQ(0xf000U, info->end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+ EXPECT_EQ("/system/lib/fake.so", info->name);
+
+ ASSERT_TRUE(maps.Get(2) == nullptr);
+}
+
+TEST(MapsTest, iterate) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(2U, maps.Total());
+
+ Maps::iterator it = maps.begin();
+ EXPECT_EQ(0xa000U, (*it)->start);
+ EXPECT_EQ(0xe000U, (*it)->end);
++it;
- ASSERT_EQ(0xa12345U, it->offset);
- ASSERT_EQ(0xe000U, it->start);
- ASSERT_EQ(0xf000U, it->end);
- ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
- ASSERT_EQ("/system/lib/fake.so", it->name);
+ EXPECT_EQ(0xe000U, (*it)->start);
+ EXPECT_EQ(0xf000U, (*it)->end);
++it;
- ASSERT_EQ(maps.end(), it);
+ EXPECT_EQ(maps.end(), it);
+}
+
+TEST(MapsTest, const_iterate) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(2U, maps.Total());
+
+ Maps::const_iterator it = maps.begin();
+ EXPECT_EQ(0xa000U, (*it)->start);
+ EXPECT_EQ(0xe000U, (*it)->end);
+ ++it;
+ EXPECT_EQ(0xe000U, (*it)->start);
+ EXPECT_EQ(0xf000U, (*it)->end);
+ ++it;
+ EXPECT_EQ(maps.end(), it);
}
TEST(MapsTest, device) {
@@ -235,18 +296,23 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(4U, maps.Total());
- auto it = maps.begin();
- ASSERT_TRUE(it->flags & 0x8000);
- ASSERT_EQ("/dev/", it->name);
- ++it;
- ASSERT_TRUE(it->flags & 0x8000);
- ASSERT_EQ("/dev/does_not_exist", it->name);
- ++it;
- ASSERT_FALSE(it->flags & 0x8000);
- ASSERT_EQ("/dev/ashmem/does_not_exist", it->name);
- ++it;
- ASSERT_FALSE(it->flags & 0x8000);
- ASSERT_EQ("/devsomething/does_not_exist", it->name);
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_TRUE(info->flags & 0x8000);
+ EXPECT_EQ("/dev/", info->name);
+
+ info = maps.Get(1);
+ EXPECT_TRUE(info->flags & 0x8000);
+ EXPECT_EQ("/dev/does_not_exist", info->name);
+
+ info = maps.Get(2);
+ EXPECT_FALSE(info->flags & 0x8000);
+ EXPECT_EQ("/dev/ashmem/does_not_exist", info->name);
+
+ info = maps.Get(3);
+ EXPECT_FALSE(info->flags & 0x8000);
+ EXPECT_EQ("/devsomething/does_not_exist", info->name);
}
TEST(MapsTest, file_smoke) {
@@ -263,26 +329,32 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto it = maps.begin();
- ASSERT_EQ(0x7b29b000U, it->start);
- ASSERT_EQ(0x7b29e000U, it->end);
- ASSERT_EQ(0xa0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("/fake.so", it->name);
- ++it;
- ASSERT_EQ(0x7b2b0000U, it->start);
- ASSERT_EQ(0x7b2e0000U, it->end);
- ASSERT_EQ(0xb0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("/fake2.so", it->name);
- ++it;
- ASSERT_EQ(0x7b2e0000U, it->start);
- ASSERT_EQ(0x7b2f0000U, it->end);
- ASSERT_EQ(0xc0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("/fake3.so", it->name);
- ++it;
- ASSERT_EQ(it, maps.end());
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b29b000U, info->start);
+ EXPECT_EQ(0x7b29e000U, info->end);
+ EXPECT_EQ(0xa0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("/fake.so", info->name);
+
+ info = maps.Get(1);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b2b0000U, info->start);
+ EXPECT_EQ(0x7b2e0000U, info->end);
+ EXPECT_EQ(0xb0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("/fake2.so", info->name);
+
+ info = maps.Get(2);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b2e0000U, info->start);
+ EXPECT_EQ(0x7b2f0000U, info->end);
+ EXPECT_EQ(0xc0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("/fake3.so", info->name);
+
+ ASSERT_TRUE(maps.Get(3) == nullptr);
}
TEST(MapsTest, file_no_map_name) {
@@ -299,26 +371,32 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
- auto it = maps.begin();
- ASSERT_EQ(0x7b29b000U, it->start);
- ASSERT_EQ(0x7b29e000U, it->end);
- ASSERT_EQ(0xa0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(0x7b2b0000U, it->start);
- ASSERT_EQ(0x7b2e0000U, it->end);
- ASSERT_EQ(0xb0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("/fake2.so", it->name);
- ++it;
- ASSERT_EQ(0x7b2e0000U, it->start);
- ASSERT_EQ(0x7b2f0000U, it->end);
- ASSERT_EQ(0xc0000000U, it->offset);
- ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
- ASSERT_EQ("", it->name);
- ++it;
- ASSERT_EQ(it, maps.end());
+
+ MapInfo* info = maps.Get(0);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b29b000U, info->start);
+ EXPECT_EQ(0x7b29e000U, info->end);
+ EXPECT_EQ(0xa0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("", info->name);
+
+ info = maps.Get(1);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b2b0000U, info->start);
+ EXPECT_EQ(0x7b2e0000U, info->end);
+ EXPECT_EQ(0xb0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("/fake2.so", info->name);
+
+ info = maps.Get(2);
+ ASSERT_TRUE(info != nullptr);
+ EXPECT_EQ(0x7b2e0000U, info->start);
+ EXPECT_EQ(0x7b2f0000U, info->end);
+ EXPECT_EQ(0xc0000000U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+ EXPECT_EQ("", info->name);
+
+ ASSERT_TRUE(maps.Get(3) == nullptr);
}
// Verify that a file that crosses a buffer is parsed correctly.
@@ -435,10 +513,10 @@
ASSERT_EQ(5000U, maps.Total());
for (size_t i = 0; i < 5000; i++) {
MapInfo* info = maps.Get(i);
- ASSERT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
- ASSERT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
+ EXPECT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
+ EXPECT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
std::string name = "/fake" + std::to_string(i) + ".so";
- ASSERT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
+ EXPECT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
}
}
@@ -452,52 +530,52 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(5U, maps.Total());
- ASSERT_TRUE(maps.Find(0x500) == nullptr);
- ASSERT_TRUE(maps.Find(0x2000) == nullptr);
- ASSERT_TRUE(maps.Find(0x5010) == nullptr);
- ASSERT_TRUE(maps.Find(0x9a00) == nullptr);
- ASSERT_TRUE(maps.Find(0xf000) == nullptr);
- ASSERT_TRUE(maps.Find(0xf010) == nullptr);
+ EXPECT_TRUE(maps.Find(0x500) == nullptr);
+ EXPECT_TRUE(maps.Find(0x2000) == nullptr);
+ EXPECT_TRUE(maps.Find(0x5010) == nullptr);
+ EXPECT_TRUE(maps.Find(0x9a00) == nullptr);
+ EXPECT_TRUE(maps.Find(0xf000) == nullptr);
+ EXPECT_TRUE(maps.Find(0xf010) == nullptr);
MapInfo* info = maps.Find(0x1000);
ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(0x1000U, info->start);
- ASSERT_EQ(0x2000U, info->end);
- ASSERT_EQ(0x10U, info->offset);
- ASSERT_EQ(PROT_READ, info->flags);
- ASSERT_EQ("/system/lib/fake1.so", info->name);
+ EXPECT_EQ(0x1000U, info->start);
+ EXPECT_EQ(0x2000U, info->end);
+ EXPECT_EQ(0x10U, info->offset);
+ EXPECT_EQ(PROT_READ, info->flags);
+ EXPECT_EQ("/system/lib/fake1.so", info->name);
info = maps.Find(0x3020);
ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(0x3000U, info->start);
- ASSERT_EQ(0x4000U, info->end);
- ASSERT_EQ(0x20U, info->offset);
- ASSERT_EQ(PROT_WRITE, info->flags);
- ASSERT_EQ("/system/lib/fake2.so", info->name);
+ EXPECT_EQ(0x3000U, info->start);
+ EXPECT_EQ(0x4000U, info->end);
+ EXPECT_EQ(0x20U, info->offset);
+ EXPECT_EQ(PROT_WRITE, info->flags);
+ EXPECT_EQ("/system/lib/fake2.so", info->name);
info = maps.Find(0x6020);
ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(0x6000U, info->start);
- ASSERT_EQ(0x8000U, info->end);
- ASSERT_EQ(0x30U, info->offset);
- ASSERT_EQ(PROT_EXEC, info->flags);
- ASSERT_EQ("/system/lib/fake3.so", info->name);
+ EXPECT_EQ(0x6000U, info->start);
+ EXPECT_EQ(0x8000U, info->end);
+ EXPECT_EQ(0x30U, info->offset);
+ EXPECT_EQ(PROT_EXEC, info->flags);
+ EXPECT_EQ("/system/lib/fake3.so", info->name);
info = maps.Find(0xafff);
ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(0xa000U, info->start);
- ASSERT_EQ(0xb000U, info->end);
- ASSERT_EQ(0x40U, info->offset);
- ASSERT_EQ(PROT_READ | PROT_WRITE, info->flags);
- ASSERT_EQ("/system/lib/fake4.so", info->name);
+ EXPECT_EQ(0xa000U, info->start);
+ EXPECT_EQ(0xb000U, info->end);
+ EXPECT_EQ(0x40U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+ EXPECT_EQ("/system/lib/fake4.so", info->name);
info = maps.Find(0xe500);
ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(0xe000U, info->start);
- ASSERT_EQ(0xf000U, info->end);
- ASSERT_EQ(0x50U, info->offset);
- ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
- ASSERT_EQ("/system/lib/fake5.so", info->name);
+ EXPECT_EQ(0xe000U, info->start);
+ EXPECT_EQ(0xf000U, info->end);
+ EXPECT_EQ(0x50U, info->offset);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+ EXPECT_EQ("/system/lib/fake5.so", info->name);
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 2a02669..3320f77 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -147,28 +147,29 @@
}
TEST_F(RegsTest, elf_invalid) {
- Elf invalid_elf(new MemoryFake);
RegsArm regs_arm;
RegsArm64 regs_arm64;
RegsX86 regs_x86;
RegsX86_64 regs_x86_64;
- MapInfo map_info{.start = 0x1000, .end = 0x2000};
+ MapInfo map_info(0x1000, 0x2000);
+ Elf* invalid_elf = new Elf(new MemoryFake);
+ map_info.elf = invalid_elf;
regs_arm.set_pc(0x1500);
- ASSERT_EQ(0x500U, invalid_elf.GetRelPc(regs_arm.pc(), &map_info));
- ASSERT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, &invalid_elf));
+ EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
+ EXPECT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, invalid_elf));
regs_arm64.set_pc(0x1600);
- ASSERT_EQ(0x600U, invalid_elf.GetRelPc(regs_arm64.pc(), &map_info));
- ASSERT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, &invalid_elf));
+ EXPECT_EQ(0x600U, invalid_elf->GetRelPc(regs_arm64.pc(), &map_info));
+ EXPECT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, invalid_elf));
regs_x86.set_pc(0x1700);
- ASSERT_EQ(0x700U, invalid_elf.GetRelPc(regs_x86.pc(), &map_info));
- ASSERT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, &invalid_elf));
+ EXPECT_EQ(0x700U, invalid_elf->GetRelPc(regs_x86.pc(), &map_info));
+ EXPECT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, invalid_elf));
regs_x86_64.set_pc(0x1800);
- ASSERT_EQ(0x800U, invalid_elf.GetRelPc(regs_x86_64.pc(), &map_info));
- ASSERT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, &invalid_elf));
+ EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
+ EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
}
TEST_F(RegsTest, arm_set_from_raw) {
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
new file mode 100644
index 0000000..d24abe4
--- /dev/null
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
+
+#include "Machine.h"
+
+#include "ElfTestUtils.h"
+
+namespace unwindstack {
+
+static std::string DumpFrames(Unwinder& unwinder) {
+ std::string str;
+ for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+ str += unwinder.FormatFrame(i) + "\n";
+ }
+ return str;
+}
+
+TEST(UnwindOfflineTest, pc_straddle_arm32) {
+ std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
+
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+ FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ RegsArm regs;
+ uint64_t reg_value;
+ ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
+ regs[ARM_REG_PC] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
+ regs[ARM_REG_SP] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
+ regs[ARM_REG_LR] = reg_value;
+ regs.SetFromRaw();
+ fclose(fp);
+
+ fp = fopen((dir + "maps.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ // The file is guaranteed to be less than 4096 bytes.
+ std::vector<char> buffer(4096);
+ ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+ fclose(fp);
+
+ BufferMaps maps(buffer.data());
+ ASSERT_TRUE(maps.Parse());
+
+ ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
+
+ std::shared_ptr<Memory> process_memory(memory);
+
+ char* cwd = getcwd(nullptr, 0);
+ ASSERT_EQ(0, chdir(dir.c_str()));
+ Unwinder unwinder(128, &maps, ®s, process_memory);
+ unwinder.Unwind();
+ ASSERT_EQ(0, chdir(cwd));
+ free(cwd);
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0001a9f8 libc.so (abort+63)\n"
+ " #01 pc 00006a1b libbase.so (_ZN7android4base14DefaultAborterEPKc+6)\n"
+ " #02 pc 00007441 libbase.so (_ZN7android4base10LogMessageD2Ev+748)\n"
+ " #03 pc 00015149 /does/not/exist/libhidlbase.so\n",
+ frame_info);
+}
+
+TEST(UnwindOfflineTest, pc_straddle_arm64) {
+ std::string dir(TestGetFileDirectory() + "offline/straddle_arm64/");
+
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+ FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ RegsArm64 regs;
+ uint64_t reg_value;
+ ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_PC] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_SP] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_LR] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_R29] = reg_value;
+ regs.SetFromRaw();
+ fclose(fp);
+
+ fp = fopen((dir + "maps.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ // The file is guaranteed to be less than 4096 bytes.
+ std::vector<char> buffer(4096);
+ ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+ fclose(fp);
+
+ BufferMaps maps(buffer.data());
+ ASSERT_TRUE(maps.Parse());
+
+ ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
+
+ std::shared_ptr<Memory> process_memory(memory);
+
+ char* cwd = getcwd(nullptr, 0);
+ ASSERT_EQ(0, chdir(dir.c_str()));
+ Unwinder unwinder(128, &maps, ®s, process_memory);
+ unwinder.Unwind();
+ ASSERT_EQ(0, chdir(cwd));
+ free(cwd);
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000000000429fd8 libunwindstack_test (SignalInnerFunction+24)\n"
+ " #01 pc 000000000042a078 libunwindstack_test (SignalMiddleFunction+8)\n"
+ " #02 pc 000000000042a08c libunwindstack_test (SignalOuterFunction+8)\n"
+ " #03 pc 000000000042d8fc libunwindstack_test "
+ "(_ZN11unwindstackL19RemoteThroughSignalEij+20)\n"
+ " #04 pc 000000000042d8d8 libunwindstack_test "
+ "(_ZN11unwindstack37UnwindTest_remote_through_signal_Test8TestBodyEv+32)\n"
+ " #05 pc 0000000000455d70 libunwindstack_test (_ZN7testing4Test3RunEv+392)\n",
+ frame_info);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 9f9ca8b..66c8ba6 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -311,4 +311,39 @@
RemoteThroughSignal(SIGSEGV, SA_SIGINFO);
}
+// Verify that using the same map while unwinding multiple threads at the
+// same time doesn't cause problems.
+TEST_F(UnwindTest, multiple_threads_unwind_same_map) {
+ static constexpr size_t kNumConcurrentThreads = 100;
+
+ LocalMaps maps;
+ ASSERT_TRUE(maps.Parse());
+ auto process_memory(Memory::CreateProcessMemory(getpid()));
+
+ std::vector<std::thread*> threads;
+
+ std::atomic_bool wait;
+ wait = true;
+ size_t frames[kNumConcurrentThreads];
+ for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+ std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
+ while (wait)
+ ;
+ std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+ RegsGetLocal(regs.get());
+
+ Unwinder unwinder(512, &maps, regs.get(), process_memory);
+ unwinder.Unwind();
+ frames[i] = unwinder.NumFrames();
+ ASSERT_LE(3U, frames[i]) << "Failed for thread " << i;
+ });
+ threads.push_back(thread);
+ }
+ wait = false;
+ for (auto thread : threads) {
+ thread->join();
+ delete thread;
+ }
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 869d118..098459e 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -45,82 +45,51 @@
void FakeClear() { maps_.clear(); }
- void FakeAddMapInfo(const MapInfo& map_info) { maps_.push_back(map_info); }
+ void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); }
};
class UnwinderTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
maps_.FakeClear();
- MapInfo info;
- info.name = "/system/fake/libc.so";
- info.start = 0x1000;
- info.end = 0x8000;
- info.offset = 0;
- info.flags = PROT_READ | PROT_WRITE;
+ MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
ElfFake* elf = new ElfFake(nullptr);
- info.elf = elf;
+ info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- info.elf_offset = 0;
maps_.FakeAddMapInfo(info);
- info.name = "[stack]";
- info.start = 0x10000;
- info.end = 0x12000;
- info.flags = PROT_READ | PROT_WRITE;
- info.elf = nullptr;
+ info = new MapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
maps_.FakeAddMapInfo(info);
- info.name = "/dev/fake_device";
- info.start = 0x13000;
- info.end = 0x15000;
- info.flags = PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP;
- info.elf = nullptr;
+ info = new MapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+ "/dev/fake_device");
maps_.FakeAddMapInfo(info);
- info.name = "/system/fake/libunwind.so";
- info.start = 0x20000;
- info.end = 0x22000;
- info.flags = PROT_READ | PROT_WRITE;
+ info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
elf = new ElfFake(nullptr);
- info.elf = elf;
+ info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
- info.name = "/fake/libanother.so";
- info.start = 0x23000;
- info.end = 0x24000;
- info.flags = PROT_READ | PROT_WRITE;
+ info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
elf = new ElfFake(nullptr);
- info.elf = elf;
+ info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
- info.name = "/fake/compressed.so";
- info.start = 0x33000;
- info.end = 0x34000;
- info.flags = PROT_READ | PROT_WRITE;
+ info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
elf = new ElfFake(nullptr);
- info.elf = elf;
+ info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
- info.name = "/fake/fake.apk";
- info.start = 0x43000;
- info.end = 0x44000;
- info.offset = 0x1d000;
- info.flags = PROT_READ | PROT_WRITE;
+ info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
elf = new ElfFake(nullptr);
- info.elf = elf;
+ info->elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
- info.name = "/fake/fake.oat";
- info.start = 0x53000;
- info.end = 0x54000;
- info.offset = 0;
- info.flags = PROT_READ | PROT_WRITE;
- info.elf = nullptr;
+ info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
maps_.FakeAddMapInfo(info);
}
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libbase.so b/libunwindstack/tests/files/offline/straddle_arm32/libbase.so
new file mode 100644
index 0000000..d1f16ee
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libc.so b/libunwindstack/tests/files/offline/straddle_arm32/libc.so
new file mode 100644
index 0000000..4dc19ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/maps.txt b/libunwindstack/tests/files/offline/straddle_arm32/maps.txt
new file mode 100644
index 0000000..8c26479
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/maps.txt
@@ -0,0 +1,4 @@
+f2d9a000-f2da7fff r-xp 00000000 00:00 0 libbase.so
+f3002000-f3005fff rw-p 00000000 00:00 0 [stack:25941]
+f31d0000-f326bfff r-xp 00000000 00:00 0 libc.so
+f3352000-f336bfff r-xp 00000000 00:00 0 /does/not/exist/libhidlbase.so
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/regs.txt b/libunwindstack/tests/files/offline/straddle_arm32/regs.txt
new file mode 100644
index 0000000..3baedf3
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/regs.txt
@@ -0,0 +1,3 @@
+pc: f31ea9f8
+sp: e9c866f8
+lr: f31f179f
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/stack.data b/libunwindstack/tests/files/offline/straddle_arm32/stack.data
new file mode 100644
index 0000000..83aeb4a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
new file mode 100644
index 0000000..092fc3a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/maps.txt b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
new file mode 100644
index 0000000..bdf29b5
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
@@ -0,0 +1,2 @@
+00000064d05ab000-00000064d0a6cfff r-xp 00000000 00:00 0 libunwindstack_test
+0000007fe0d64000-0000007fe0d84fff rw-p 00000000 00:00 0 [stack]
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/regs.txt b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
new file mode 100644
index 0000000..ff8a936
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
@@ -0,0 +1,4 @@
+pc: 00000064d09d4fd8
+sp: 0000007fe0d84040
+lr: 00000064d09d507c
+x29: 0000007fe0d84070
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/stack.data b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
new file mode 100644
index 0000000..824d0e2
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 77f3bb2..a00b2ee 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -102,12 +103,12 @@
}
}
-int GetElfInfo(const char* file) {
+int GetElfInfo(const char* file, uint64_t offset) {
// Send all log messages to stdout.
log_to_stdout(true);
MemoryFileAtOffset* memory = new MemoryFileAtOffset;
- if (!memory->Init(file, 0)) {
+ if (!memory->Init(file, offset)) {
// Initializatation failed.
printf("Failed to init\n");
return 1;
@@ -164,8 +165,12 @@
} // namespace unwindstack
int main(int argc, char** argv) {
- if (argc != 2) {
- printf("Need to pass the name of an elf file to the program.\n");
+ if (argc != 2 && argc != 3) {
+ printf("Usage: unwind_info ELF_FILE [OFFSET]\n");
+ printf(" ELF_FILE\n");
+ printf(" The path to an elf file.\n");
+ printf(" OFFSET\n");
+ printf(" Use the offset into the ELF file as the beginning of the elf.\n");
return 1;
}
@@ -179,5 +184,15 @@
return 1;
}
- return unwindstack::GetElfInfo(argv[1]);
+ uint64_t offset = 0;
+ if (argc == 3) {
+ char* end;
+ offset = strtoull(argv[2], &end, 16);
+ if (*end != '\0') {
+ printf("Malformed OFFSET value: %s\n", argv[2]);
+ return 1;
+ }
+ }
+
+ return unwindstack::GetElfInfo(argv[1], offset);
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 4bd2a98..6b50f0c 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -136,9 +136,12 @@
cflags: ["-Wno-unused-parameter"],
},
- // Under MinGW, ctype.h doesn't need multi-byte support
windows: {
- cflags: ["-DMB_CUR_MAX=1"],
+ cflags: [
+ // Under MinGW, ctype.h doesn't need multi-byte support
+ "-DMB_CUR_MAX=1",
+ "-Wno-unused-private-field",
+ ],
enabled: true,
},
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 6317c32..7d7f0e2 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -348,7 +348,7 @@
mState = (void*) hMutex;
}
-Mutex::Mutex(const char* name)
+Mutex::Mutex(const char* /*name*/)
{
// XXX: name not used for now
HANDLE hMutex;
@@ -359,7 +359,7 @@
mState = (void*) hMutex;
}
-Mutex::Mutex(int type, const char* name)
+Mutex::Mutex(int /*type*/, const char* /*name*/)
{
// XXX: type and name not used for now
HANDLE hMutex;
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index cb3d338..15ed19f 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -35,9 +35,7 @@
// ---------------------------------------------------------------------------
-class SharedBuffer;
class String8;
-class TextOutput;
//! This is a string holding UTF-16 characters.
class String16
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 1f3e5d8..0225c6b 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -31,7 +31,6 @@
namespace android {
class String16;
-class TextOutput;
//! This is a string holding UTF-8 characters. Does not allow the value more
// than 0x10FFFF, which is not valid unicode codepoint.
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index d95fd05..da28dfa 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -44,8 +44,8 @@
static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
#endif
-void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
#if !defined(_WIN32)
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
pthread_mutex_lock(&gSyspropMutex);
if (gSyspropList == NULL) {
gSyspropList = new Vector<sysprop_change_callback_info>();
@@ -65,8 +65,10 @@
gSyspropList->add(info);
}
pthread_mutex_unlock(&gSyspropMutex);
-#endif
}
+#else
+void add_sysprop_change_callback(sysprop_change_callback, int) {}
+#endif
#if defined(__ANDROID__)
void (*get_report_sysprop_change_func())() {
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
index d06cafc..bc5620b 100644
--- a/libvndksupport/linker.c
+++ b/libvndksupport/linker.c
@@ -21,7 +21,8 @@
#define LOG_TAG "vndksupport"
#include <log/log.h>
-extern struct android_namespace_t* android_get_exported_namespace(const char*);
+__attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
+__attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
static const char* namespace_name = NULL;
@@ -31,7 +32,9 @@
if (vendor_namespace == NULL) {
int name_idx = 0;
while (namespace_names[name_idx] != NULL) {
- vendor_namespace = android_get_exported_namespace(namespace_names[name_idx]);
+ if (android_get_exported_namespace != NULL) {
+ vendor_namespace = android_get_exported_namespace(namespace_names[name_idx]);
+ }
if (vendor_namespace != NULL) {
namespace_name = namespace_names[name_idx];
break;
@@ -48,7 +51,10 @@
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = vendor_namespace,
};
- void* handle = android_dlopen_ext(name, flag, &dlextinfo);
+ void* handle = NULL;
+ if (android_dlopen_ext != NULL) {
+ handle = android_dlopen_ext(name, flag, &dlextinfo);
+ }
if (!handle) {
ALOGE("Could not load %s from %s namespace: %s.", name, namespace_name, dlerror());
}
diff --git a/logcat/Android.bp b/logcat/Android.bp
index 729c8ff..afc7a01 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -67,6 +67,7 @@
name: "logpersist.start",
srcs: ["logpersist"],
init_rc: ["logcatd.rc"],
+ required: ["logcatd"],
symlinks: ["logpersist.stop", "logpersist.cat"],
strip: {
none: true,
diff --git a/logcat/event.logtags b/logcat/event.logtags
index efcc817..0983676 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -140,5 +140,8 @@
1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
+# for events that go to stats log buffer
+1937006964 stats_log (atom_id|1|5),(data|4)
+
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index a2aa486..ff85f54 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1126,8 +1126,9 @@
}
if (found) continue;
- bool binary =
- !strcmp(name, "events") || !strcmp(name, "security");
+ bool binary = !strcmp(name, "events") ||
+ !strcmp(name, "security") ||
+ !strcmp(name, "stats");
log_device_t* d = new log_device_t(name, binary);
if (dev) {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index f75036d..aa970d6 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -247,7 +247,7 @@
else # if _enforce_vndk_at_runtime is not true
LOCAL_MODULE := ld.config.txt
-ifeq ($(PRODUCT_FULL_TREBLE)|$(SANITIZE_TARGET),true|)
+ifeq ($(PRODUCT_TREBLE_LINKER_NAMESPACES)|$(SANITIZE_TARGET),true|)
LOCAL_SRC_FILES := etc/ld.config.txt
else
LOCAL_SRC_FILES := etc/ld.config.legacy.txt
@@ -257,3 +257,45 @@
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
endif
+
+#######################################
+# llndk.libraries.txt
+include $(CLEAR_VARS)
+LOCAL_MODULE := llndk.libraries.txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
+llndk_dep = $(intermediates)/$(llndk_md5).dep
+$(llndk_dep):
+ $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES)
+$(LOCAL_BUILT_MODULE): $(llndk_dep)
+ @echo "Generate: $@"
+ @mkdir -p $(dir $@)
+ $(hide) echo -n > $@
+ $(hide) $(foreach lib,$(PRIVATE_LLNDK_LIBRARIES), \
+ echo $(lib).so >> $@;)
+
+#######################################
+# vndksp.libraries.txt
+include $(CLEAR_VARS)
+LOCAL_MODULE := vndksp.libraries.txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
+vndksp_dep = $(intermediates)/$(vndksp_md5).dep
+$(vndksp_dep):
+ $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES)
+$(LOCAL_BUILT_MODULE): $(vndksp_dep)
+ @echo "Generate: $@"
+ @mkdir -p $(dir $@)
+ $(hide) echo -n > $@
+ $(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
+ echo $(lib).so >> $@;)
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index e741a34..a6bed8d 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -4,7 +4,7 @@
#
# Don't change the order here. The first pattern that matches with the
-# absolution path of an executable is selected.
+# absolute path of an executable is selected.
dir.system = /system/bin/
dir.system = /system/xbin/
dir.vendor = /vendor/bin/
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 96eb6f3..11b8383 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -409,6 +409,7 @@
mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
+ mkdir /data/misc/carrierid 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/textclassifier 0771 system system
mkdir /data/misc/vpn 0770 system vpn
@@ -430,7 +431,10 @@
mkdir /data/misc/vold 0700 root root
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
+ mkdir /data/misc/update_engine_log 02750 root log
mkdir /data/misc/trace 0700 root root
+ # create location to store surface and window trace files
+ mkdir /data/misc/wmtrace 0700 system system
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
@@ -480,6 +484,10 @@
mkdir /data/anr 0775 system system
+ # NFC: create data/nfc for nv storage
+ mkdir /data/nfc 0770 nfc nfc
+ mkdir /data/nfc/param 0770 nfc nfc
+
# Create all remaining /data root dirs so that they are made through init
# and get proper encryption policy installed
mkdir /data/backup 0700 system system
@@ -725,6 +733,8 @@
# Give writes to anyone for the trace folder on debug builds.
# The folder is used to store method traces.
chmod 0773 /data/misc/trace
+ # Give reads to anyone for the window trace folder on debug builds.
+ chmod 0775 /data/misc/wmtrace
start console
service flash_recovery /system/bin/install-recovery.sh
diff --git a/trusty/keymaster/trusty_keymaster_ipc.cpp b/trusty/keymaster/trusty_keymaster_ipc.cpp
index fbd0eb3..686e7ae 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/trusty_keymaster_ipc.cpp
@@ -55,6 +55,11 @@
size_t msg_size = in_size + sizeof(struct keymaster_message);
struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
+ if (!msg) {
+ ALOGE("failed to allocate msg buffer\n");
+ return -EINVAL;
+ }
+
msg->cmd = cmd;
memcpy(msg->payload, in, in_size);