Merge "Use void instead of no parameters in 2 function declarations."
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a4c2160..344fa9a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -85,12 +85,13 @@
fprintf(stderr, "Usage: %s [options]\n", cmd);
fprintf(stderr,
"options include:\n"
- " -h, --help Show this help\n"
- " -l, --log Log all metrics to logstorage\n"
- " -p, --print Dump the boot event records to the console\n"
- " -r, --record Record the timestamp of a named boot event\n"
- " --value Optional value to associate with the boot event\n"
- " --record_boot_reason Record the reason why the device booted\n"
+ " -h, --help Show this help\n"
+ " -l, --log Log all metrics to logstorage\n"
+ " -p, --print Dump the boot event records to the console\n"
+ " -r, --record Record the timestamp of a named boot event\n"
+ " --value Optional value to associate with the boot event\n"
+ " --record_boot_complete Record metrics related to the time for the device boot\n"
+ " --record_boot_reason Record the reason why the device booted\n"
" --record_time_since_factory_reset Record the time since the device was reset\n");
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8c19a81..cc81074 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,6 +32,7 @@
#include <unistd.h>
#include <memory>
+#include <thread>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -87,34 +88,22 @@
FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
};
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-static time_t gettime(void)
-{
- struct timespec ts;
- int ret;
+// TODO: switch to inotify()
+bool fs_mgr_wait_for_file(const std::string& filename,
+ const std::chrono::milliseconds relative_timeout) {
+ auto start_time = std::chrono::steady_clock::now();
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- PERROR << "clock_gettime(CLOCK_MONOTONIC) failed";
- return 0;
+ while (true) {
+ if (!access(filename.c_str(), F_OK) || errno != ENOENT) {
+ return true;
+ }
+
+ std::this_thread::sleep_for(50ms);
+
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ if (time_elapsed > relative_timeout) return false;
}
-
- return ts.tv_sec;
-}
-
-static int wait_for_file(const char *filename, int timeout)
-{
- struct stat info;
- time_t timeout_time = gettime() + timeout;
- int ret = -1;
-
- while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
- usleep(10000);
-
- return ret;
}
static void log_fs_stat(const char* blk_device, int fs_stat)
@@ -457,6 +446,16 @@
return rc;
}
+// Orange state means the device is unlocked, see the following link for details.
+// https://source.android.com/security/verifiedboot/verified-boot#device_state
+bool fs_mgr_is_device_unlocked() {
+ std::string verified_boot_state;
+ if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
+ return verified_boot_state == "orange";
+ }
+ return false;
+}
+
/*
* __mount(): wrapper around the mount() system call which also
* sets the underlying block device to read-only if the mount is read-only.
@@ -476,10 +475,11 @@
if ((info.st_mode & S_IFMT) == S_IFLNK)
unlink(target);
mkdir(target, 0755);
+ errno = 0;
ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
save_errno = errno;
- LINFO << __FUNCTION__ << "(source=" << source << ",target="
- << target << ",type=" << rec->fs_type << ")=" << ret;
+ PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
+ << ",type=" << rec->fs_type << ")=" << ret;
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
@@ -744,19 +744,6 @@
}
}
-// TODO: add ueventd notifiers if they don't exist.
-// This is just doing a wait_for_device for maximum of 1s
-int fs_mgr_test_access(const char *device) {
- int tries = 25;
- while (tries--) {
- if (!access(device, F_OK) || errno != ENOENT) {
- return 0;
- }
- usleep(40 * 1000);
- }
- return -1;
-}
-
bool is_device_secure() {
int ret = -1;
char value[PROP_VALUE_MAX];
@@ -827,8 +814,10 @@
}
}
- if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
- wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+ if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
+ !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
+ LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
+ continue;
}
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
@@ -1031,8 +1020,9 @@
}
/* First check the filesystem if requested */
- if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
- wait_for_file(n_blk_device, WAIT_TIMEOUT);
+ if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
+ LERROR << "Skipping mounting '" << n_blk_device << "'";
+ continue;
}
int fs_stat = 0;
@@ -1205,8 +1195,11 @@
fclose(zram_fp);
}
- if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
- wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+ if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
+ !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
+ LERROR << "Skipping mkswap for '" << fstab->recs[i].blk_device << "'";
+ ret = -1;
+ continue;
}
/* Initialize the swap area */
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 2c99aa7..7824cfa 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -397,7 +397,7 @@
fstab_entry->blk_device = strdup(verity_blk_name.c_str());
// Makes sure we've set everything up properly.
- if (wait_for_verity_dev && fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+ if (wait_for_verity_dev && !fs_mgr_wait_for_file(verity_blk_name, 1s)) {
return false;
}
@@ -473,16 +473,6 @@
return true;
}
-// Orange state means the device is unlocked, see the following link for details.
-// https://source.android.com/security/verifiedboot/verified-boot#device_state
-static inline bool IsDeviceUnlocked() {
- std::string verified_boot_state;
- if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
- return verified_boot_state == "orange";
- }
- return false;
-}
-
FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
FsManagerAvbOps avb_ops(fstab);
return DoOpen(&avb_ops);
@@ -498,7 +488,7 @@
}
FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
- bool is_device_unlocked = IsDeviceUnlocked();
+ bool is_device_unlocked = fs_mgr_is_device_unlocked();
FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
if (!avb_handle) {
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index ba1262f..43879fe 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -142,10 +142,8 @@
}
std::string path = iter->second;
- // Ensures the device path (a symlink created by init) is ready to
- // access. fs_mgr_test_access() will test a few iterations if the
- // path doesn't exist yet.
- if (fs_mgr_test_access(path.c_str()) < 0) {
+ // Ensures the device path (a symlink created by init) is ready to access.
+ if (!fs_mgr_wait_for_file(path, 1s)) {
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index c985462..5ea6e98 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -17,8 +17,12 @@
#ifndef __CORE_FS_MGR_PRIV_H
#define __CORE_FS_MGR_PRIV_H
+#include <chrono>
+#include <string>
+
#include <android-base/logging.h>
-#include <fs_mgr.h>
+
+#include "fs_mgr.h"
#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
@@ -43,8 +47,6 @@
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
-#define WAIT_TIMEOUT 20
-
/* fstab has the following format:
*
* Any line starting with a # is a comment and ignored
@@ -110,9 +112,13 @@
#define DM_BUF_SIZE 4096
+using namespace std::chrono_literals;
+
int fs_mgr_set_blk_ro(const char *blockdev);
-int fs_mgr_test_access(const char *device);
+bool fs_mgr_wait_for_file(const std::string& filename,
+ const std::chrono::milliseconds relative_timeout);
bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_is_device_unlocked();
bool is_dt_compatible();
bool is_device_secure();
int load_verity_state(struct fstab_rec* fstab, int* mode);
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 8fa9370..5de0903 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -782,8 +782,8 @@
if (fec_verity_get_metadata(f, &verity) < 0) {
PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
// Allow verity disabled when the device is unlocked without metadata
- if ("0" == android::base::GetProperty("ro.boot.flash.locked", "")) {
- retval = FS_MGR_SETUP_VERITY_DISABLED;
+ if (fs_mgr_is_device_unlocked()) {
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
LWARNING << "Allow invalid metadata when the device is unlocked";
}
goto out;
@@ -929,7 +929,7 @@
}
// make sure we've set everything up properly
- if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
+ if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
goto out;
}
diff --git a/include/ziparchive b/include/ziparchive
deleted file mode 120000
index d8fa424..0000000
--- a/include/ziparchive
+++ /dev/null
@@ -1 +0,0 @@
-../libziparchive/include/ziparchive
\ No newline at end of file
diff --git a/init/README.md b/init/README.md
index 72b6c6b..422fdad 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,14 @@
> Sets the child's /proc/self/oom\_score\_adj to the specified value,
which must range from -1000 to 1000.
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+ the service is killed during shutdown process by using SIGTERM and SIGKILL.
+ The service with shutdown_behavior of "critical" is not killed during shutdown
+ until shutdown times out. When shutdown times out, even services tagged with
+ "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+ is not running when shut down starts, it will be started.
+
Triggers
--------
diff --git a/init/action.cpp b/init/action.cpp
index 6900391..4a3ab48 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -326,6 +326,13 @@
}
}
+void ActionManager::ClearQueue() {
+ // We are shutting down so don't claim the oneshot builtin actions back
+ current_executing_actions_ = {};
+ event_queue_ = {};
+ current_command_ = 0;
+}
+
bool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line, std::string* err) {
std::vector<std::string> triggers(args.begin() + 1, args.end());
diff --git a/init/action.h b/init/action.h
index 5cb50a7..ad15f3f 100644
--- a/init/action.h
+++ b/init/action.h
@@ -104,6 +104,7 @@
void ExecuteOneCommand();
bool HasMoreCommands() const;
void DumpState() const;
+ void ClearQueue();
private:
ActionManager(ActionManager const&) = delete;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 00ffbc3..75a8f19 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -119,7 +119,7 @@
LOG(ERROR) << "failed to set bootloader message: " << err;
return -1;
}
- DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
+ property_set("sys.powerctl", "reboot,recovery");
return 0;
}
diff --git a/init/devices.cpp b/init/devices.cpp
index 215d2ea..13cf991 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -219,7 +219,7 @@
return {0600, 0, 0};
}
-void DeviceHandler::MakeDevice(const std::string& path, int block, int major, int minor,
+void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const {
auto[mode, uid, gid] = GetDevicePermissions(path, links);
mode |= (block ? S_IFBLK : S_IFCHR);
@@ -279,45 +279,6 @@
}
}
-std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
- std::string parent_device;
- if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
-
- // skip path to the parent driver
- std::string path = uevent.path.substr(parent_device.length());
-
- if (!StartsWith(path, "/usb")) return {};
-
- // skip root hub name and device. use device interface
- // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
- // then extract what comes between the 3rd and 4th slash
- // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
-
- std::string::size_type start = 0;
- start = path.find('/', start + 1);
- if (start == std::string::npos) return {};
-
- start = path.find('/', start + 1);
- if (start == std::string::npos) return {};
-
- auto end = path.find('/', start + 1);
- if (end == std::string::npos) return {};
-
- start++; // Skip the first '/'
-
- auto length = end - start;
- if (length == 0) return {};
-
- auto name_string = path.substr(start, length);
-
- std::vector<std::string> links;
- links.emplace_back("/dev/usb/" + uevent.subsystem + name_string);
-
- mkdir("/dev/usb", 0755);
-
- return links;
-}
-
// replaces any unacceptable characters with '_', the
// length of the resulting string is equal to the input string
void SanitizePartitionName(std::string* string) {
@@ -385,7 +346,7 @@
return links;
}
-void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, int block,
+void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
int major, int minor, const std::vector<std::string>& links) const {
if (action == "add") {
MakeDevice(devpath, block, major, minor, links);
@@ -411,31 +372,26 @@
}
}
-void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
- // if it's not a /dev device, nothing to do
- if (uevent.major < 0 || uevent.minor < 0) return;
-
- const char* base = "/dev/block/";
- make_dir(base, 0755, sehandle_);
-
- std::string name = Basename(uevent.path);
- std::string devpath = base + name;
-
- std::vector<std::string> links;
- if (StartsWith(uevent.path, "/devices")) {
- links = GetBlockDeviceSymlinks(uevent);
+void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
+ if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
+ FixupSysPermissions(uevent.path, uevent.subsystem);
}
- HandleDevice(uevent.action, devpath, 1, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleGenericDeviceEvent(const Uevent& uevent) const {
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
std::string devpath;
+ std::vector<std::string> links;
+ bool block = false;
- if (StartsWith(uevent.subsystem, "usb")) {
+ if (uevent.subsystem == "block") {
+ block = true;
+ devpath = "/dev/block/" + Basename(uevent.path);
+
+ if (StartsWith(uevent.path, "/devices")) {
+ links = GetBlockDeviceSymlinks(uevent);
+ }
+ } else if (StartsWith(uevent.subsystem, "usb")) {
if (uevent.subsystem == "usb") {
if (!uevent.device_name.empty()) {
devpath = "/dev/" + uevent.device_name;
@@ -461,21 +417,7 @@
mkdir_recursive(Dirname(devpath), 0755, sehandle_);
- auto links = GetCharacterDeviceSymlinks(uevent);
-
- HandleDevice(uevent.action, devpath, 0, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
- if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
- FixupSysPermissions(uevent.path, uevent.subsystem);
- }
-
- if (uevent.subsystem == "block") {
- HandleBlockDeviceEvent(uevent);
- } else {
- HandleGenericDeviceEvent(uevent);
- }
+ HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
}
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
diff --git a/init/devices.h b/init/devices.h
index 5105ad7..c64f5fb 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -115,16 +115,12 @@
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const;
- void MakeDevice(const std::string& path, int block, int major, int minor,
+ void MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const;
- std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
- void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
+ void HandleDevice(const std::string& action, const std::string& devpath, bool block, int major,
int minor, const std::vector<std::string>& links) const;
void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
- void HandleBlockDeviceEvent(const Uevent& uevent) const;
- void HandleGenericDeviceEvent(const Uevent& uevent) const;
-
std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_;
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 57d8e0f..ac4ab9b 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
class DeviceHandlerTester {
public:
void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
- const std::vector<std::string> expected_links, bool block) {
+ const std::vector<std::string> expected_links) {
TemporaryDir fake_sys_root;
device_handler_.sysfs_mount_point_ = fake_sys_root.path;
@@ -44,11 +44,7 @@
mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
std::vector<std::string> result;
- if (block) {
- result = device_handler_.GetBlockDeviceSymlinks(uevent);
- } else {
- result = device_handler_.GetCharacterDeviceSymlinks(uevent);
- }
+ result = device_handler_.GetBlockDeviceSymlinks(uevent);
auto expected_size = expected_links.size();
ASSERT_EQ(expected_size, result.size());
@@ -64,95 +60,6 @@
DeviceHandler device_handler_;
};
-TEST(device_handler, get_character_device_symlinks_success) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/name/tty2-1:1.0",
- .subsystem = "tty",
- };
- std::vector<std::string> expected_result{"/dev/usb/ttyname"};
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_pdev_match) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/device/name/tty2-1:1.0", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_nothing_after_platform_device) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_found) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/bad/bad/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_roothub) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_device) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_slash) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/name", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_name) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device//", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
TEST(device_handler, get_block_device_symlinks_success_platform) {
// These are actual paths from bullhead
const char* platform_device = "/devices/soc.0/f9824900.sdhci";
@@ -164,7 +71,7 @@
std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition) {
@@ -182,7 +89,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_num) {
@@ -198,7 +105,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_name) {
@@ -214,7 +121,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_pci) {
@@ -225,7 +132,7 @@
std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_pci_bad_format) {
@@ -236,7 +143,7 @@
std::vector<std::string> expected_result{};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_vbd) {
@@ -247,7 +154,7 @@
std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_vbd_bad_format) {
@@ -258,7 +165,7 @@
std::vector<std::string> expected_result{};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_no_matches) {
@@ -271,7 +178,7 @@
std::vector<std::string> expected_result;
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, sanitize_null) {
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 8cd5cc5..860b30b 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -110,31 +110,16 @@
if (uevent.subsystem != "firmware" || uevent.action != "add") return;
// Loading the firmware in a child means we can do that in parallel...
- // We double fork instead of waiting for these processes.
- pid_t pid = fork();
+ auto pid = fork();
if (pid == -1) {
PLOG(ERROR) << "could not fork to process firmware event for " << uevent.firmware;
- return;
}
-
if (pid == 0) {
- pid = fork();
- if (pid == -1) {
- PLOG(ERROR) << "could not fork a sceond time to process firmware event for "
- << uevent.firmware;
- _exit(EXIT_FAILURE);
- }
- if (pid == 0) {
- Timer t;
- ProcessFirmwareEvent(uevent);
- LOG(INFO) << "loading " << uevent.path << " took " << t;
- _exit(EXIT_SUCCESS);
- }
-
+ Timer t;
+ ProcessFirmwareEvent(uevent);
+ LOG(INFO) << "loading " << uevent.path << " took " << t;
_exit(EXIT_SUCCESS);
}
-
- waitpid(pid, nullptr, 0);
}
} // namespace init
diff --git a/init/init.cpp b/init/init.cpp
index 0562dad..d23e1a3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -94,6 +94,7 @@
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
static std::string wait_prop_value;
+static bool shutting_down;
void DumpState() {
ServiceManager::GetInstance().DumpState();
@@ -158,21 +159,31 @@
return true;
}
+void ResetWaitForProp() {
+ wait_prop_name.clear();
+ wait_prop_value.clear();
+ waiting_for_prop.reset();
+}
+
void property_changed(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
- if (name == "sys.powerctl") HandlePowerctlMessage(value);
+ // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
+ // commands to be executed.
+ if (name == "sys.powerctl") {
+ if (HandlePowerctlMessage(value)) {
+ shutting_down = true;
+ }
+ }
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
if (waiting_for_prop) {
if (wait_prop_name == name && wait_prop_value == value) {
- wait_prop_name.clear();
- wait_prop_value.clear();
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
- waiting_for_prop.reset();
+ ResetWaitForProp();
}
}
}
@@ -1135,7 +1146,7 @@
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
- restart_processes();
+ if (!shutting_down) restart_processes();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0) {
diff --git a/init/init.h b/init/init.h
index 479b771..aaab523 100644
--- a/init/init.h
+++ b/init/init.h
@@ -44,6 +44,8 @@
void DumpState();
+void ResetWaitForProp();
+
} // namespace init
} // namespace android
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index e10c3b2..be57f8b 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -171,10 +171,13 @@
};
uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
if (!found) {
+ LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+ Timer t;
uevent_listener_.Poll(dm_callback, 10s);
+ LOG(INFO) << "Wait for device-mapper returned after " << t;
}
if (!found) {
- LOG(ERROR) << "device-mapper device not found";
+ LOG(ERROR) << "device-mapper device not found after polling timeout";
return false;
}
}
@@ -185,11 +188,16 @@
// UeventCallback() will remove found partitions from required_devices_partition_names_.
// So if it isn't empty here, it means some partitions are not found.
if (!required_devices_partition_names_.empty()) {
+ LOG(INFO) << __PRETTY_FUNCTION__
+ << ": partition(s) not found in /sys, waiting for their uevent(s): "
+ << android::base::Join(required_devices_partition_names_, ", ");
+ Timer t;
uevent_listener_.Poll(uevent_callback, 10s);
+ LOG(INFO) << "Wait for partitions returned after " << t;
}
if (!required_devices_partition_names_.empty()) {
- LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
+ LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
<< android::base::Join(required_devices_partition_names_, ", ");
return false;
}
@@ -241,10 +249,13 @@
uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
if (!found) {
+ LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+ Timer t;
uevent_listener_.Poll(verity_callback, 10s);
+ LOG(INFO) << "wait for dm-verity device returned after " << t;
}
if (!found) {
- LOG(ERROR) << "dm-verity device not found";
+ LOG(ERROR) << "dm-verity device not found after polling timeout";
return false;
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 34c98a7..38d603a 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -49,6 +49,7 @@
#include <private/android_filesystem_config.h>
#include "capabilities.h"
+#include "init.h"
#include "property_service.h"
#include "service.h"
@@ -364,13 +365,15 @@
// keep debugging tools until non critical ones are all gone.
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
- const std::set<std::string> to_starts{"watchdogd", "vold", "ueventd"};
+ const std::set<std::string> to_starts{"watchdogd"};
ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
if (kill_after_apps.count(s->name())) {
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
s->Start();
s->SetShutdownCritical();
+ } else if (s->IsShutdownCritical()) {
+ s->Start(); // start shutdown critical service if not started
}
});
@@ -490,6 +493,9 @@
}
} else if (command == "thermal-shutdown") { // no additional parameter allowed
cmd = ANDROID_RB_THERMOFF;
+ // Do not queue "shutdown" trigger since we want to shutdown immediately
+ DoReboot(cmd, command, reboot_target, run_fsck);
+ return true;
} else {
command_invalid = true;
}
@@ -498,7 +504,26 @@
return false;
}
- DoReboot(cmd, command, reboot_target, run_fsck);
+ LOG(INFO) << "Clear action queue and start shutdown trigger";
+ ActionManager::GetInstance().ClearQueue();
+ // Queue shutdown trigger first
+ ActionManager::GetInstance().QueueEventTrigger("shutdown");
+ // Queue built-in shutdown_done
+ auto shutdown_handler = [cmd, command, reboot_target,
+ run_fsck](const std::vector<std::string>&) {
+ DoReboot(cmd, command, reboot_target, run_fsck);
+ return 0;
+ };
+ ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
+
+ // Skip wait for prop if it is in progress
+ ResetWaitForProp();
+
+ // Skip wait for exec if it is in progress
+ if (ServiceManager::GetInstance().IsWaitingForExec()) {
+ ServiceManager::GetInstance().ClearExecWait();
+ }
+
return true;
}
diff --git a/init/service.cpp b/init/service.cpp
index f2e5d22..6b36526 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <processgroup/processgroup.h>
@@ -47,6 +48,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::Join;
+using android::base::make_scope_guard;
using android::base::ParseInt;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -499,6 +501,14 @@
return true;
}
+bool Service::ParseShutdown(const std::vector<std::string>& args, std::string* err) {
+ if (args[1] == "critical") {
+ flags_ |= SVC_SHUTDOWN_CRITICAL;
+ return true;
+ }
+ return false;
+}
+
template <typename T>
bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
@@ -602,6 +612,7 @@
{"namespace", {1, 2, &Service::ParseNamespace}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
+ {"shutdown", {1, 1, &Service::ParseShutdown}},
{"socket", {3, 6, &Service::ParseSocket}},
{"file", {2, 2, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
@@ -1088,14 +1099,24 @@
}
bool ServiceManager::ReapOneProcess() {
- int status;
- pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
- if (pid == 0) {
+ siginfo_t siginfo = {};
+ // This returns a zombie pid or informs us that there are no zombies left to be reaped.
+ // It does NOT reap the pid; that is done below.
+ if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
+ PLOG(ERROR) << "waitid failed";
return false;
- } else if (pid == -1) {
- PLOG(ERROR) << "waitpid failed";
- return false;
- } else if (PropertyChildReap(pid)) {
+ }
+
+ auto pid = siginfo.si_pid;
+ if (pid == 0) return false;
+
+ // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
+ // whenever the function returns from this point forward.
+ // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
+ // want the pid to remain valid throughout that (and potentially future) usages.
+ auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
+
+ if (PropertyChildReap(pid)) {
return true;
}
@@ -1112,14 +1133,11 @@
name = StringPrintf("Untracked pid %d", pid);
}
+ auto status = siginfo.si_status;
if (WIFEXITED(status)) {
LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
} else if (WIFSIGNALED(status)) {
LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
- } else if (WIFSTOPPED(status)) {
- LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status) << wait_string;
- } else {
- LOG(INFO) << name << " state changed" << wait_string;
}
if (!svc) {
@@ -1143,6 +1161,15 @@
}
}
+void ServiceManager::ClearExecWait() {
+ // Clear EXEC flag if there is one pending
+ // And clear the wait flag
+ for (const auto& s : services_) {
+ s->UnSetExec();
+ }
+ exec_waiter_.reset();
+}
+
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line, std::string* err) {
if (args.size() < 3) {
diff --git a/init/service.h b/init/service.h
index 3c7dc74..40b4745 100644
--- a/init/service.h
+++ b/init/service.h
@@ -89,6 +89,7 @@
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+ void UnSetExec() { flags_ &= ~SVC_EXEC; }
const std::string& name() const { return name_; }
const std::set<std::string>& classnames() const { return classnames_; }
@@ -137,6 +138,7 @@
bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+ bool ParseShutdown(const std::vector<std::string>& args, std::string* err);
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
bool ParseFile(const std::vector<std::string>& args, std::string* err);
bool ParseUser(const std::vector<std::string>& args, std::string* err);
@@ -186,7 +188,7 @@
};
class ServiceManager {
-public:
+ public:
static ServiceManager& GetInstance();
// Exposed for testing
@@ -208,8 +210,9 @@
void ReapAnyOutstandingChildren();
void RemoveService(const Service& svc);
void DumpState() const;
+ void ClearExecWait();
-private:
+ private:
// Cleans up a child process that exited.
// Returns true iff a children was cleaned up.
bool ReapOneProcess();
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 81a0572..a713beb 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -268,6 +268,13 @@
cold_boot.Run();
}
+ // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
+ signal(SIGCHLD, SIG_IGN);
+ // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
+ // for SIGCHLD above.
+ while (waitpid(-1, nullptr, WNOHANG) > 0) {
+ }
+
uevent_listener.Poll([&device_handler](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
device_handler.HandleDeviceEvent(uevent);
diff --git a/init/util.cpp b/init/util.cpp
index 4b1894f..479179e 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -370,6 +370,7 @@
void panic() {
LOG(ERROR) << "panic: rebooting to bootloader";
+ // Do not queue "shutdown" trigger since we want to shutdown immediately
DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
}
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index a643a29..e02aaf2 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -161,6 +161,7 @@
shared_libs = [
"libbase",
"libunwind",
+ "libziparchive",
],
}
diff --git a/libmemunreachable/tests/AndroidTest.xml b/libmemunreachable/tests/AndroidTest.xml
new file mode 100644
index 0000000..604c0ec
--- /dev/null
+++ b/libmemunreachable/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for memunreachable_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="memunreachable_test->/data/local/tmp/memunreachable_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="memunreachable_test" />
+ </test>
+</configuration>
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 377b7dd..1cea4cd 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -1,4 +1,11 @@
+cc_library_headers {
+ name: "libnativebridge-dummy-headers",
+
+ host_supported: true,
+ export_include_dirs=["include"],
+}
+
cc_library {
name: "libnativebridge",
@@ -7,6 +14,8 @@
shared_libs: ["liblog"],
clang: true,
+ export_include_dirs=["include"],
+
cflags: [
"-Werror",
"-Wall",
@@ -23,4 +32,4 @@
},
}
-subdirs = ["tests"]
\ No newline at end of file
+subdirs = ["tests"]
diff --git a/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h
similarity index 100%
rename from include/nativebridge/native_bridge.h
rename to libnativebridge/include/nativebridge/native_bridge.h
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index efd3978..e31dae0 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -23,6 +23,7 @@
"-Wextra",
"-Werror",
],
+ header_libs: ["libnativebridge-dummy-headers"],
cppflags: ["-fvisibility=protected"],
target: {
android: {
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9b8248e..f5d4e1c 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -43,6 +43,9 @@
using namespace std::chrono_literals;
+// Uncomment line below use memory cgroups for keeping track of (forked) PIDs
+// #define USE_MEMCG 1
+
#define MEM_CGROUP_PATH "/dev/memcg/apps"
#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
#define ACCT_CGROUP_PATH "/acct"
@@ -88,6 +91,7 @@
};
static const char* getCgroupRootPath() {
+#ifdef USE_MEMCG
static const char* cgroup_root_path = NULL;
std::call_once(init_path_flag, [&]() {
// Check if mem cgroup is mounted, only then check for write-access to avoid
@@ -96,6 +100,9 @@
ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
});
return cgroup_root_path;
+#else
+ return ACCT_CGROUP_PATH;
+#endif
}
static int convertUidToPath(char *path, size_t size, uid_t uid)
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8776db7..03a9a54 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -98,14 +98,18 @@
"tests/ElfInterfaceArmTest.cpp",
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",
+ "tests/ElfTestUtils.cpp",
"tests/LogFake.cpp",
- "tests/MapInfoTest.cpp",
+ "tests/MapInfoCreateMemoryTest.cpp",
+ "tests/MapInfoGetElfTest.cpp",
"tests/MapsTest.cpp",
+ "tests/MemoryBuffer.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
+ "tests/MemoryTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
],
@@ -144,8 +148,8 @@
],
data: [
- "tests/elf32.xz",
- "tests/elf64.xz",
+ "tests/files/elf32.xz",
+ "tests/files/elf64.xz",
],
}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 051f700..d7b483d 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -73,13 +73,15 @@
return new MemoryRange(memory, start, end);
}
-Elf* MapInfo::GetElf(pid_t pid, bool) {
+Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) {
if (elf) {
return elf;
}
elf = new Elf(CreateMemory(pid));
- elf->Init();
+ if (elf->Init() && init_gnu_debugdata) {
+ elf->InitGnuDebugdata();
+ }
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
return elf;
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 22cade2..bf0823b 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -24,6 +24,7 @@
#include "Elf.h"
+#include "ElfTestUtils.h"
#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
@@ -36,36 +37,16 @@
memory_ = new MemoryFake;
}
- template <typename Ehdr>
- void InitEhdr(Ehdr* ehdr) {
- memset(ehdr, 0, sizeof(Ehdr));
- memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
- ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
- ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
-
- ehdr->e_type = ET_DYN;
- ehdr->e_version = EV_CURRENT;
- }
-
- void InitElf32(uint32_t machine) {
+ void InitElf32(uint32_t machine_type) {
Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type);
- InitEhdr<Elf32_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS32;
-
- ehdr.e_machine = machine;
- ehdr.e_entry = 0;
ehdr.e_phoff = 0x100;
- ehdr.e_shoff = 0;
- ehdr.e_flags = 0;
ehdr.e_ehsize = sizeof(ehdr);
ehdr.e_phentsize = sizeof(Elf32_Phdr);
ehdr.e_phnum = 1;
ehdr.e_shentsize = sizeof(Elf32_Shdr);
- ehdr.e_shnum = 0;
- ehdr.e_shstrndx = 0;
- if (machine == EM_ARM) {
+ if (machine_type == EM_ARM) {
ehdr.e_flags = 0x5000200;
ehdr.e_phnum = 2;
}
@@ -74,16 +55,13 @@
Elf32_Phdr phdr;
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_LOAD;
- phdr.p_offset = 0;
- phdr.p_vaddr = 0;
- phdr.p_paddr = 0;
phdr.p_filesz = 0x10000;
phdr.p_memsz = 0x10000;
phdr.p_flags = PF_R | PF_X;
phdr.p_align = 0x1000;
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
- if (machine == EM_ARM) {
+ if (machine_type == EM_ARM) {
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_ARM_EXIDX;
phdr.p_offset = 0x30000;
@@ -97,31 +75,21 @@
}
}
- void InitElf64(uint32_t machine) {
+ void InitElf64(uint32_t machine_type) {
Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type);
- InitEhdr<Elf64_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS64;
-
- ehdr.e_machine = machine;
- ehdr.e_entry = 0;
ehdr.e_phoff = 0x100;
- ehdr.e_shoff = 0;
ehdr.e_flags = 0x5000200;
ehdr.e_ehsize = sizeof(ehdr);
ehdr.e_phentsize = sizeof(Elf64_Phdr);
ehdr.e_phnum = 1;
ehdr.e_shentsize = sizeof(Elf64_Shdr);
- ehdr.e_shnum = 0;
- ehdr.e_shstrndx = 0;
memory_->SetMemory(0, &ehdr, sizeof(ehdr));
Elf64_Phdr phdr;
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_LOAD;
- phdr.p_offset = 0;
- phdr.p_vaddr = 0;
- phdr.p_paddr = 0;
phdr.p_filesz = 0x10000;
phdr.p_memsz = 0x10000;
phdr.p_flags = PF_R | PF_X;
@@ -129,12 +97,6 @@
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
}
- template <typename Ehdr, typename Shdr>
- void GnuDebugdataInitFail(Ehdr* ehdr);
-
- template <typename Ehdr, typename Shdr>
- void GnuDebugdataInit(Ehdr* ehdr);
-
MemoryFake* memory_;
};
@@ -214,153 +176,64 @@
ASSERT_TRUE(elf.interface() != nullptr);
}
-template <typename Ehdr, typename Shdr>
-void ElfTest::GnuDebugdataInitFail(Ehdr* ehdr) {
+TEST_F(ElfTest, gnu_debugdata_init_fail32) {
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(offset, ptr, size);
+ });
+
Elf elf(memory_);
-
- uint64_t offset = 0x2000;
-
- ehdr->e_shoff = offset;
- ehdr->e_shnum = 3;
- ehdr->e_shentsize = sizeof(Shdr);
- ehdr->e_shstrndx = 2;
- memory_->SetMemory(0, ehdr, sizeof(*ehdr));
-
- Shdr shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NULL;
- memory_->SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr->e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0x100;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_->SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr->e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x200000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_->SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr->e_shentsize;
-
- memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
-
ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
- EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
- EXPECT_EQ(0x800U, elf.interface()->gnu_debugdata_size());
-
- elf.InitGnuDebugdata();
-}
-
-TEST_F(ElfTest, gnu_debugdata_init_fail32) {
- Elf32_Ehdr ehdr;
- InitEhdr<Elf32_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS32;
- ehdr.e_machine = EM_ARM;
-
- GnuDebugdataInitFail<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
+ EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
}
TEST_F(ElfTest, gnu_debugdata_init_fail64) {
- Elf64_Ehdr ehdr;
- InitEhdr<Elf64_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS64;
- ehdr.e_machine = EM_AARCH64;
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(offset, ptr, size);
+ });
- GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
-}
-
-template <typename Ehdr, typename Shdr>
-void ElfTest::GnuDebugdataInit(Ehdr* ehdr) {
Elf elf(memory_);
-
- uint64_t offset = 0x2000;
-
- ehdr->e_shoff = offset;
- ehdr->e_shnum = 3;
- ehdr->e_shentsize = sizeof(Shdr);
- ehdr->e_shstrndx = 2;
- memory_->SetMemory(0, ehdr, sizeof(*ehdr));
-
- Shdr shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NULL;
- memory_->SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr->e_shentsize;
-
- uint64_t gnu_offset = offset;
- offset += ehdr->e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x200000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_->SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr->e_shentsize;
-
- memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
-
- // Read in the compressed elf data and put it in our fake memory.
- std::string name("tests/");
- if (sizeof(Ehdr) == sizeof(Elf32_Ehdr)) {
- name += "elf32.xz";
- } else {
- name += "elf64.xz";
- }
- int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
- ASSERT_NE(-1, fd) << "Cannot open " + name;
- // Assumes the file is less than 1024 bytes.
- std::vector<uint8_t> buf(1024);
- ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
- ASSERT_GT(bytes, 0);
- // Make sure the file isn't too big.
- ASSERT_NE(static_cast<size_t>(bytes), buf.size())
- << "File " + name + " is too big, increase buffer size.";
- close(fd);
- buf.resize(bytes);
- memory_->SetMemory(0x5000, buf);
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0x100;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_size = bytes;
- memory_->SetMemory(gnu_offset, &shdr, sizeof(shdr));
-
ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
- EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
+}
+
+TEST_F(ElfTest, gnu_debugdata_init32) {
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(offset, ptr, size);
+ });
+
+ Elf elf(memory_);
+ ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.interface() != nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
elf.InitGnuDebugdata();
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
-TEST_F(ElfTest, gnu_debugdata_init32) {
- Elf32_Ehdr ehdr;
- InitEhdr<Elf32_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS32;
- ehdr.e_machine = EM_ARM;
-
- GnuDebugdataInit<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
-}
-
TEST_F(ElfTest, gnu_debugdata_init64) {
- Elf64_Ehdr ehdr;
- InitEhdr<Elf64_Ehdr>(&ehdr);
- ehdr.e_ident[EI_CLASS] = ELFCLASS64;
- ehdr.e_machine = EM_AARCH64;
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(offset, ptr, size);
+ });
- GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
+ Elf elf(memory_);
+ ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.interface() != nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
+
+ elf.InitGnuDebugdata();
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
new file mode 100644
index 0000000..8755f16
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "ElfTestUtils.h"
+
+template <typename Ehdr>
+void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
+ memset(ehdr, 0, sizeof(Ehdr));
+ memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
+ ehdr->e_ident[EI_CLASS] = elf_class;
+ ehdr->e_type = ET_DYN;
+ ehdr->e_machine = machine_type;
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof(Ehdr);
+}
+
+template <typename Ehdr, typename Shdr>
+void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata,
+ TestCopyFuncType copy_func) {
+ Ehdr ehdr;
+
+ TestInitEhdr(&ehdr, elf_class, machine);
+
+ uint64_t offset = sizeof(Ehdr);
+ ehdr.e_shoff = offset;
+ ehdr.e_shnum = 3;
+ ehdr.e_shentsize = sizeof(Shdr);
+ ehdr.e_shstrndx = 2;
+ copy_func(0, &ehdr, sizeof(ehdr));
+
+ Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_NULL;
+ copy_func(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ // Skip this header, it will contain the gnu_debugdata information.
+ uint64_t gnu_offset = offset;
+ offset += ehdr.e_shentsize;
+
+ uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_name = 1;
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_offset = symtab_offset;
+ shdr.sh_size = 0x100;
+ copy_func(offset, &shdr, sizeof(shdr));
+
+ char value = '\0';
+ uint64_t symname_offset = symtab_offset;
+ copy_func(symname_offset, &value, 1);
+ symname_offset++;
+ std::string name(".shstrtab");
+ copy_func(symname_offset, name.c_str(), name.size() + 1);
+ symname_offset += name.size() + 1;
+ name = ".gnu_debugdata";
+ copy_func(symname_offset, name.c_str(), name.size() + 1);
+
+ ssize_t bytes = 0x100;
+ offset = symtab_offset + 0x100;
+ if (init_gnu_debugdata) {
+ // Read in the compressed elf data and copy it in.
+ name = "tests/files/";
+ if (elf_class == ELFCLASS32) {
+ name += "elf32.xz";
+ } else {
+ name += "elf64.xz";
+ }
+ int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
+ ASSERT_NE(-1, fd) << "Cannot open " + name;
+ // Assumes the file is less than 1024 bytes.
+ std::vector<uint8_t> buf(1024);
+ bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
+ ASSERT_GT(bytes, 0);
+ // Make sure the file isn't too big.
+ ASSERT_NE(static_cast<size_t>(bytes), buf.size())
+ << "File " + name + " is too big, increase buffer size.";
+ close(fd);
+ buf.resize(bytes);
+ copy_func(offset, buf.data(), buf.size());
+ }
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_name = symname_offset - symtab_offset;
+ shdr.sh_addr = offset;
+ shdr.sh_offset = offset;
+ shdr.sh_size = bytes;
+ copy_func(gnu_offset, &shdr, sizeof(shdr));
+}
+
+template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t);
+template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t);
+
+template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool,
+ TestCopyFuncType);
+template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
+ TestCopyFuncType);
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
new file mode 100644
index 0000000..4fd3bbc
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+
+#include <functional>
+
+typedef std::function<void(uint64_t, const void*, size_t)> TestCopyFuncType;
+
+template <typename Ehdr>
+void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type);
+
+template <typename Ehdr, typename Shdr>
+void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
+ TestCopyFuncType copy_func);
+
+#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
similarity index 85%
rename from libunwindstack/tests/MapInfoTest.cpp
rename to libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 6e47dc0..d7433e1 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -34,7 +34,7 @@
#include "MapInfo.h"
#include "Memory.h"
-class MapInfoTest : public ::testing::Test {
+class MapInfoCreateMemoryTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
std::vector<uint8_t> buffer(1024);
@@ -58,10 +58,10 @@
static TemporaryFile elf_at_100_;
};
-TemporaryFile MapInfoTest::elf_;
-TemporaryFile MapInfoTest::elf_at_100_;
+TemporaryFile MapInfoCreateMemoryTest::elf_;
+TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
-TEST_F(MapInfoTest, end_le_start) {
+TEST_F(MapInfoCreateMemoryTest, end_le_start) {
MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
std::unique_ptr<Memory> memory;
@@ -80,7 +80,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(MapInfoTest, create_memory_file_backed_non_zero_offset_full_file) {
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@@ -100,7 +100,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(MapInfoTest, create_memory_file_backed_non_zero_offset_partial_file) {
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@@ -119,7 +119,7 @@
}
// Verify that device file names will never result in Memory object creation.
-TEST_F(MapInfoTest, create_memory_check_device_maps) {
+TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
// Set up some memory so that a valid local memory object would
// be returned if the file mapping fails, but the device check is incorrect.
std::vector<uint8_t> buffer(1024);
@@ -135,7 +135,7 @@
ASSERT_TRUE(memory.get() == nullptr);
}
-TEST_F(MapInfoTest, create_memory_local_memory) {
+TEST_F(MapInfoCreateMemoryTest, local_memory) {
// Set up some memory for a valid local memory object.
std::vector<uint8_t> buffer(1024);
for (size_t i = 0; i < buffer.size(); i++) {
@@ -160,7 +160,7 @@
ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
}
-TEST_F(MapInfoTest, create_memory_remote_memory) {
+TEST_F(MapInfoCreateMemoryTest, remote_memory) {
std::vector<uint8_t> buffer(1024);
memset(buffer.data(), 0xa, buffer.size());
@@ -202,19 +202,3 @@
kill(pid, SIGKILL);
}
-
-TEST_F(MapInfoTest, get_elf) {
- // Create a map to use as initialization data.
- void* map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_NE(MAP_FAILED, map);
-
- uint64_t start = reinterpret_cast<uint64_t>(map);
- MapInfo info{.start = start, .end = start + 1024, .offset = 0, .name = ""};
-
- // The map contains garbage, but this should still produce an elf object.
- std::unique_ptr<Elf> elf(info.GetElf(getpid(), false));
- ASSERT_TRUE(elf.get() != nullptr);
- ASSERT_FALSE(elf->valid());
-
- ASSERT_EQ(0, munmap(map, 1024));
-}
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
new file mode 100644
index 0000000..fc36cc6
--- /dev/null
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "Elf.h"
+#include "ElfTestUtils.h"
+#include "MapInfo.h"
+
+class MapInfoGetElfTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map_);
+
+ uint64_t start = reinterpret_cast<uint64_t>(map_);
+ info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""});
+ }
+
+ void TearDown() override { munmap(map_, kMapSize); }
+
+ const size_t kMapSize = 4096;
+
+ void* map_ = nullptr;
+ std::unique_ptr<MapInfo> info_;
+};
+
+TEST_F(MapInfoGetElfTest, invalid) {
+ // The map is empty, but this should still create an invalid elf object.
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != nullptr);
+ ASSERT_FALSE(elf->valid());
+}
+
+TEST_F(MapInfoGetElfTest, valid32) {
+ Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ memcpy(map_, &ehdr, sizeof(ehdr));
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != 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) {
+ Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+ memcpy(map_, &ehdr, sizeof(ehdr));
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != 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) {
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
+ ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) {
+ memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != nullptr);
+ ASSERT_TRUE(elf->valid());
+ EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
+ EXPECT_EQ(ELFCLASS32, elf->class_type());
+ EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
+ ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) {
+ memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != nullptr);
+ ASSERT_TRUE(elf->valid());
+ EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
+ EXPECT_EQ(ELFCLASS64, elf->class_type());
+ EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
+ ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) {
+ memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+ ASSERT_TRUE(elf.get() != nullptr);
+ ASSERT_TRUE(elf->valid());
+ EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
+ EXPECT_EQ(ELFCLASS32, elf->class_type());
+ EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
+ ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) {
+ memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+ ASSERT_TRUE(elf.get() != nullptr);
+ ASSERT_TRUE(elf->valid());
+ EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
+ EXPECT_EQ(ELFCLASS64, elf->class_type());
+ EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
+}
diff --git a/libunwindstack/tests/elf32.xz b/libunwindstack/tests/files/elf32.xz
similarity index 100%
rename from libunwindstack/tests/elf32.xz
rename to libunwindstack/tests/files/elf32.xz
Binary files differ
diff --git a/libunwindstack/tests/elf64.xz b/libunwindstack/tests/files/elf64.xz
similarity index 100%
rename from libunwindstack/tests/elf64.xz
rename to libunwindstack/tests/files/elf64.xz
Binary files differ
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 84a9a2f..333835c 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -50,6 +50,8 @@
"libbase",
"liblog",
],
+
+ export_include_dirs: ["include"],
}
cc_library {
@@ -65,7 +67,6 @@
"liblog",
"libbase",
],
- export_include_dirs: ["include"],
target: {
android: {
shared_libs: [
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ebbec35..84d0f87 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -36,8 +36,6 @@
mount cgroup none /dev/memcg memory
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
- # cgroup for system_server and surfaceflinger
- mkdir /dev/memcg/system 0755 system system
start ueventd
@@ -681,12 +679,17 @@
on property:security.perf_harden=1
write /proc/sys/kernel/perf_event_paranoid 3
+# on shutdown
+# In device's init.rc, this trigger can be used to do device-specific actions
+# before shutdown. e.g disable watchdog and mask error handling
+
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
+ shutdown critical
service healthd /sbin/healthd
class core
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 6d35fed..9620d63 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -4,7 +4,6 @@
"bzip2",
"grep",
"grep_vendor",
- "gzip",
"mkshrc",
"mkshrc_vendor",
"reboot",