Merge changes from topic 'adb_perf'
* changes:
adb: Add bMaxBurst to superspeed descriptors
adb: Set max socket sizes to larger values.
adb: Pre allocate kernel memory
diff --git a/base/Android.bp b/base/Android.bp
index b9a6e0b..a7600f3 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -37,6 +37,9 @@
cppflags: libbase_cppflags,
export_include_dirs: ["include"],
shared_libs: ["liblog"],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
target: {
android: {
srcs: [
@@ -86,6 +89,9 @@
"strings_test.cpp",
"test_main.cpp",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
target: {
android: {
srcs: ["properties_test.cpp"],
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4d7082a..e275fa2 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -58,6 +58,9 @@
// tell you whether or not your call succeeded. A `false` return value definitely means failure.
bool SetProperty(const std::string& key, const std::string& value);
+// Waits for the system property `key` to have the value `expected_value`, .
+void WaitForProperty(const std::string& key, const std::string& expected_value);
+
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 37daf9a..0f0f638 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+
#include "android-base/properties.h"
#include <sys/system_properties.h>
+#include <sys/_system_properties.h>
#include <string>
@@ -78,5 +81,43 @@
return (__system_property_set(key.c_str(), value.c_str()) == 0);
}
+struct WaitForPropertyData {
+ bool done;
+ const std::string* expected_value;
+ unsigned last_read_serial;
+};
+
+static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
+ WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
+ if (*data->expected_value == value) {
+ data->done = true;
+ } else {
+ data->last_read_serial = serial;
+ }
+}
+
+void WaitForProperty(const std::string& key, const std::string& expected_value) {
+ // Find the property's prop_info*.
+ const prop_info* pi;
+ unsigned global_serial = 0;
+ while ((pi = __system_property_find(key.c_str())) == nullptr) {
+ // The property doesn't even exist yet.
+ // Wait for a global change and then look again.
+ global_serial = __system_property_wait_any(global_serial);
+ }
+
+ WaitForPropertyData data;
+ data.expected_value = &expected_value;
+ data.done = false;
+ while (true) {
+ // Check whether the property has the value we're looking for?
+ __system_property_read_callback(pi, WaitForPropertyCallback, &data);
+ if (data.done) return;
+
+ // It didn't so wait for it to change before checking again.
+ __system_property_wait(pi, data.last_read_serial);
+ }
+}
+
} // namespace base
} // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index da89ec5..d8186be 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -18,7 +18,12 @@
#include <gtest/gtest.h>
+#include <atomic>
+#include <chrono>
#include <string>
+#include <thread>
+
+using namespace std::chrono_literals;
TEST(properties, smoke) {
android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -119,3 +124,18 @@
TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
+
+TEST(properties, WaitForProperty) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ std::this_thread::sleep_for(100ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a");
+ flag = true;
+ android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b");
+ thread.join();
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index 46fe939..bfdaf12 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -36,11 +36,12 @@
size_t base = 0;
size_t found;
- do {
+ while (true) {
found = s.find_first_of(delimiters, base);
result.push_back(s.substr(base, found - base));
+ if (found == s.npos) break;
base = found + 1;
- } while (found != s.npos);
+ }
return result;
}
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7a65a00..7ed5b2b 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -251,3 +251,7 @@
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
}
+
+TEST(strings, ubsan_28729303) {
+ android::base::Split("/dev/null", ":");
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 3b3d698..636477d 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -57,7 +57,13 @@
static std::string GetSystemTempDir() {
#if defined(__ANDROID__)
- return "/data/local/tmp";
+ const char* tmpdir = "/data/local/tmp";
+ if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+ return tmpdir;
+ }
+ // Tests running in app context can't access /data/local/tmp,
+ // so try current directory if /data/local/tmp is not accessible.
+ return ".";
#elif defined(_WIN32)
char tmp_dir[MAX_PATH];
DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index d98a9d7..f744ad1 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
bootstat_lib_src_files = [
"boot_event_record_store.cpp",
- "histogram_logger.cpp",
"uptime_parser.cpp",
]
@@ -27,15 +26,12 @@
"-Wall",
"-Wextra",
"-Werror",
-
- // 524291 corresponds to sysui_histogram, from
- // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
- "-DHISTOGRAM_LOG_TAG=524291",
],
shared_libs: [
"libbase",
"libcutils",
"liblog",
+ "libmetricslogger",
],
whole_static_libs: ["libgtest_prod"],
// Clang is required because of C++14
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index f902af3..2648594 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -26,7 +26,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
-#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index c85667e..a7354a7 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -35,9 +35,9 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
+#include <metricslogger/metrics_logger.h>
#include "boot_event_record_store.h"
-#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
@@ -49,7 +49,7 @@
auto events = boot_event_store.GetAllBootEvents();
for (auto i = events.cbegin(); i != events.cend(); ++i) {
- bootstat::LogHistogram(i->first, i->second);
+ android::metricslogger::LogHistogram(i->first, i->second);
}
}
@@ -317,18 +317,18 @@
if (current_time_utc < 0) {
// UMA does not display negative values in buckets, so convert to positive.
- bootstat::LogHistogram(
+ android::metricslogger::LogHistogram(
"factory_reset_current_time_failure", std::abs(current_time_utc));
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_current_time_failure", std::abs(current_time_utc));
return;
} else {
- bootstat::LogHistogram("factory_reset_current_time", current_time_utc);
+ android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_current_time", current_time_utc);
@@ -347,9 +347,9 @@
// Calculate and record the difference in time between now and the
// factory_reset time.
time_t factory_reset_utc = record.second;
- bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
+ android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_record_value", factory_reset_utc);
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 002e940..e22d6a9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -407,3 +407,35 @@
});
AssertDeath(SIGUSR1);
}
+
+TEST(crash_dump, zombie) {
+ pid_t forkpid = fork();
+
+ int pipefd[2];
+ ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+
+ pid_t rc;
+ int status;
+
+ if (forkpid == 0) {
+ errno = 0;
+ rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
+ if (rc != -1 || errno != ECHILD) {
+ errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+ }
+
+ raise(DEBUGGER_SIGNAL);
+
+ errno = 0;
+ rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+ if (rc != -1 || errno != ECHILD) {
+ errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+ }
+ _exit(0);
+ } else {
+ rc = waitpid(forkpid, &status, 0);
+ ASSERT_EQ(forkpid, rc);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
+ }
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 38a7be3..353f642 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -249,7 +249,7 @@
// Don't leave a zombie child.
int status;
- if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) {
+ if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
__libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
strerror(errno));
} else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 94b43e4..e957f6b 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -25,6 +25,9 @@
#include <stdlib.h>
#include <string.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/properties.h>
#include "fs_mgr.h"
@@ -77,8 +80,51 @@
return 0;
}
-// Gets slot_suffix from either the kernel cmdline / firmware or the
-// misc partition. Sets |out_suffix| on success and returns 0. Returns
+// finds slot_suffix in androidboot.slot_suffix kernel command line argument
+// or in the device tree node at /firmware/android/slot_suffix property
+static int get_active_slot_suffix_from_kernel(char *out_suffix,
+ size_t suffix_len)
+{
+ std::string cmdline;
+ if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+ std::vector<std::string> pieces = android::base::Split(entry, "=");
+ if (pieces.size() == 2) {
+ if (pieces[0] == "androidboot.slot_suffix") {
+ strncpy(out_suffix, pieces[1].c_str(), suffix_len);
+ return 0;
+ }
+ }
+ }
+ }
+
+ // if we can't find slot_suffix in cmdline, check the DT
+ static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
+ std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
+ std::string dt_value;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ if (!dt_value.compare("android,firmware")) {
+ LERROR << "Error finding compatible android DT node";
+ return -1;
+ }
+
+ file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
+ if (!android::base::ReadFileToString(file_name, &dt_value)) {
+ LERROR << "Error finding slot_suffix in device tree";
+ return -1;
+ }
+
+ // DT entries have a terminating '\0', so 'suffix_len' is safe.
+ strncpy(out_suffix, dt_value.c_str(), suffix_len);
+ return 0;
+ }
+
+ // slot_suffix missing in kernel cmdline or device tree
+ return -1;
+}
+
+// Gets slot_suffix from either the kernel cmdline / device tree / firmware
+// or the misc partition. Sets |out_suffix| on success and returns 0. Returns
// -1 if slot_suffix could not be determined.
static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
size_t suffix_len)
@@ -94,6 +140,15 @@
return 0;
}
+ // if the property is not set, we are either being invoked too early
+ // or the slot suffix in mentioned in the misc partition. If its
+ // "too early", try to find the slotsuffix ourselves in the kernel command
+ // line or the device tree
+ if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
+ LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
+ return 0;
+ }
+
// If we couldn't get the suffix from the kernel cmdline, try the
// the misc partition.
if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index d959798..a9deed9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -123,6 +123,7 @@
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_slotselect(struct fstab_rec *fstab);
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_is_latemount(struct fstab_rec *fstab);
int fs_mgr_is_quota(struct fstab_rec *fstab);
diff --git a/init/devices.cpp b/init/devices.cpp
index 6af237c..b3b808b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -62,19 +62,7 @@
extern struct selabel_handle *sehandle;
-static int device_fd = -1;
-
-struct uevent {
- const char *action;
- const char *path;
- const char *subsystem;
- const char *firmware;
- const char *partition_name;
- const char *device_name;
- int partition_num;
- int major;
- int minor;
-};
+static android::base::unique_fd device_fd;
struct perms_ {
char *name;
@@ -249,11 +237,13 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
- PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
- return;
+ if (sehandle) {
+ if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
+ return;
+ }
+ setfscreatecon(secontext);
}
- setfscreatecon(secontext);
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
@@ -264,7 +254,7 @@
setegid(gid);
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
- if (mknod(path, mode, dev) && (errno == EEXIST)) {
+ if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
char* fcon = nullptr;
int rc = lgetfilecon(path, &fcon);
@@ -285,8 +275,10 @@
chown(path, uid, -1);
setegid(AID_ROOT);
- freecon(secontext);
- setfscreatecon(NULL);
+ if (secontext) {
+ freecon(secontext);
+ setfscreatecon(NULL);
+ }
}
static void add_platform_device(const char *path)
@@ -349,6 +341,19 @@
}
}
+static void destroy_platform_devices() {
+ struct listnode* node;
+ struct listnode* n;
+ struct platform_node* bus;
+
+ list_for_each_safe(node, n, &platform_names) {
+ list_remove(node);
+ bus = node_to_item(node, struct platform_node, list);
+ free(bus->path);
+ free(bus);
+ }
+}
+
/* Given a path that may start with a PCI device, populate the supplied buffer
* with the PCI domain/bus number and the peripheral ID and return 0.
* If it doesn't start with a PCI device, or there is some error, return -1 */
@@ -515,7 +520,7 @@
return NULL;
memset(links, 0, sizeof(char *) * 4);
- LOG(INFO) << "found " << type << " device " << device;
+ LOG(VERBOSE) << "found " << type << " device " << device;
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
@@ -875,9 +880,15 @@
}
}
+static bool inline should_stop_coldboot(coldboot_action_t act)
+{
+ return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
+}
+
#define UEVENT_MSG_LEN 2048
-static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
+static inline coldboot_action_t handle_device_fd_with(
+ std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
{
char msg[UEVENT_MSG_LEN+2];
int n;
@@ -890,14 +901,18 @@
struct uevent uevent;
parse_event(msg, &uevent);
- handle_uevent(&uevent);
+ coldboot_action_t act = handle_uevent(&uevent);
+ if (should_stop_coldboot(act))
+ return act;
}
+
+ return COLDBOOT_CONTINUE;
}
-void handle_device_fd()
+coldboot_action_t handle_device_fd(coldboot_callback fn)
{
- handle_device_fd_with(
- [](struct uevent *uevent) {
+ coldboot_action_t ret = handle_device_fd_with(
+ [&](uevent* uevent) -> coldboot_action_t {
if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
@@ -907,9 +922,21 @@
}
}
- handle_device_event(uevent);
- handle_firmware_event(uevent);
+ // default is to always create the devices
+ coldboot_action_t act = COLDBOOT_CREATE;
+ if (fn) {
+ act = fn(uevent);
+ }
+
+ if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
+ handle_device_event(uevent);
+ handle_firmware_event(uevent);
+ }
+
+ return act;
});
+
+ return ret;
}
/* Coldboot walks parts of the /sys tree and pokes the uevent files
@@ -921,21 +948,24 @@
** socket's buffer.
*/
-static void do_coldboot(DIR *d)
+static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
{
struct dirent *de;
int dfd, fd;
+ coldboot_action_t act = COLDBOOT_CONTINUE;
dfd = dirfd(d);
fd = openat(dfd, "uevent", O_WRONLY);
- if(fd >= 0) {
+ if (fd >= 0) {
write(fd, "add\n", 4);
close(fd);
- handle_device_fd();
+ act = handle_device_fd(fn);
+ if (should_stop_coldboot(act))
+ return act;
}
- while((de = readdir(d))) {
+ while (!should_stop_coldboot(act) && (de = readdir(d))) {
DIR *d2;
if(de->d_type != DT_DIR || de->d_name[0] == '.')
@@ -949,85 +979,31 @@
if(d2 == 0)
close(fd);
else {
- do_coldboot(d2);
+ act = do_coldboot(d2, fn);
closedir(d2);
}
}
+
+ // default is always to continue looking for uevents
+ return act;
}
-static void coldboot(const char *path)
+static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
{
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
- if(d) {
- do_coldboot(d.get());
- }
-}
-
-static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
-{
- const char *name;
- char devpath[DEVPATH_LEN];
-
- if (is_block && strncmp(uevent->subsystem, "block", 5))
- return;
-
- name = parse_device_name(uevent, MAX_DEV_NAME);
- if (!name) {
- LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
- << " " << uevent->partition_name << " " << uevent->partition_num
- << " " << uevent->major << ":" << uevent->minor;
- return;
+ if (d) {
+ return do_coldboot(d.get(), fn);
}
- snprintf(devpath, sizeof(devpath), "%s%s", base, name);
- make_dir(base, 0755);
-
- dev_t dev = makedev(uevent->major, uevent->minor);
- mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
- mknod(devpath, mode, dev);
+ return COLDBOOT_CONTINUE;
}
-void early_create_dev(const std::string& syspath, early_device_type dev_type)
-{
- android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
- if (dfd < 0) {
- LOG(ERROR) << "Failed to open " << syspath;
- return;
- }
-
- android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
- if (fd < 0) {
- LOG(ERROR) << "Failed to open " << syspath << "/uevent";
- return;
- }
-
- fcntl(device_fd, F_SETFL, O_NONBLOCK);
-
- write(fd, "add\n", 4);
- handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/block/", true);
- } :
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/", false);
- });
-}
-
-int early_device_socket_open() {
- device_fd = uevent_open_socket(256*1024, true);
- return device_fd < 0;
-}
-
-void early_device_socket_close() {
- close(device_fd);
-}
-
-void device_init() {
+void device_init(const char* path, coldboot_callback fn) {
sehandle = selinux_android_file_context_handle();
selinux_status_open(true);
/* is 256K enough? udev uses 16MB! */
- device_fd = uevent_open_socket(256*1024, true);
+ device_fd.reset(uevent_open_socket(256*1024, true));
if (device_fd == -1) {
return;
}
@@ -1039,13 +1015,33 @@
}
Timer t;
- coldboot("/sys/class");
- coldboot("/sys/block");
- coldboot("/sys/devices");
- close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ coldboot_action_t act;
+ if (!path) {
+ act = coldboot("/sys/class", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/block", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/devices", fn);
+ }
+ }
+ } else {
+ act = coldboot(path, fn);
+ }
+
+ // If we have a callback, then do as it says. If no, then the default is
+ // to always create COLDBOOT_DONE file.
+ if (!fn || (act == COLDBOOT_FINISH)) {
+ close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ }
+
LOG(INFO) << "Coldboot took " << t;
}
+void device_close() {
+ destroy_platform_devices();
+ device_fd.reset();
+}
+
int get_device_fd() {
return device_fd;
}
diff --git a/init/devices.h b/init/devices.h
index 8e9ab7d..26a064b 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,16 +17,37 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
+#include <functional>
#include <sys/stat.h>
-extern void handle_device_fd();
-extern void device_init(void);
+enum coldboot_action_t {
+ // coldboot continues without creating the device for the uevent
+ COLDBOOT_CONTINUE = 0,
+ // coldboot continues after creating the device for the uevent
+ COLDBOOT_CREATE,
+ // coldboot stops after creating the device for uevent but doesn't
+ // create the COLDBOOT_DONE file
+ COLDBOOT_STOP,
+ // same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
+ COLDBOOT_FINISH
+};
-enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+struct uevent {
+ const char* action;
+ const char* path;
+ const char* subsystem;
+ const char* firmware;
+ const char* partition_name;
+ const char* device_name;
+ int partition_num;
+ int major;
+ int minor;
+};
-extern int early_device_socket_open();
-extern void early_device_socket_close();
-extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
+extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
+extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
+extern void device_close();
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
diff --git a/init/init.cpp b/init/init.cpp
index 43f601f..9c1e23b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -495,28 +495,48 @@
}
}
-static void process_kernel_dt() {
- static const char android_dir[] = "/proc/device-tree/firmware/android";
+static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
- std::string file_name = StringPrintf("%s/compatible", android_dir);
+static bool is_dt_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
- std::string dt_file;
- android::base::ReadFileToString(file_name, &dt_file);
- if (!dt_file.compare("android,firmware")) {
+ android::base::ReadFileToString(file_name, &dt_value);
+ if (!dt_value.compare("android,firmware")) {
LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
- return;
+ return false;
}
- std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+ return true;
+}
+
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
+
+ android::base::ReadFileToString(file_name, &dt_value);
+ if (!dt_value.compare("android,fstab")) {
+ LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
+ return false;
+ }
+
+ return true;
+}
+
+static void process_kernel_dt() {
+ if (!is_dt_compatible()) return;
+
+ std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
if (!dir) return;
+ std::string dt_file;
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
continue;
}
- file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
+ std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -643,102 +663,208 @@
}
}
-/* Returns a new path consisting of base_path and the file name in reference_path. */
-static std::string get_path(const std::string& base_path, const std::string& reference_path) {
- std::string::size_type pos = reference_path.rfind('/');
- if (pos == std::string::npos) {
- return base_path + '/' + reference_path;
- } else {
- return base_path + reference_path.substr(pos);
+static std::string import_dt_fstab() {
+ std::string fstab;
+ if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+ return fstab;
}
-}
-/* Imports the fstab info from cmdline. */
-static std::string import_cmdline_fstab() {
- std::string prefix, fstab, fstab_full;
+ std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
+ std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+ if (!fstabdir) return fstab;
- import_kernel_cmdline(false,
- [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
- if (key == "android.early.prefix") {
- prefix = value;
- } else if (key == "android.early.fstab") {
- fstab = value;
- }
- });
- if (!fstab.empty()) {
- // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
- std::replace(fstab.begin(), fstab.end(), '+', ' ');
- for (const auto& entry : android::base::Split(fstab, "\n")) {
- fstab_full += prefix + entry + '\n';
+ dirent* dp;
+ while ((dp = readdir(fstabdir.get())) != NULL) {
+ // skip over name and compatible
+ if (dp->d_type != DT_DIR) {
+ continue;
}
+
+ // skip if its not 'vendor', 'odm' or 'system'
+ if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+ strcmp(dp->d_name, "vendor")) {
+ continue;
+ }
+
+ // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
+ std::vector<std::string> fstab_entry;
+ std::string file_name;
+ std::string value;
+ file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ // trim the terminating '\0' out
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+ fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
+
+ file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ fstab += android::base::Join(fstab_entry, " ");
+ fstab += '\n';
}
- return fstab_full;
+
+ return fstab;
}
-/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
-static void early_mount() {
- std::string fstab_string = import_cmdline_fstab();
- if (fstab_string.empty()) {
- LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
- return;
+/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
+static bool early_mount() {
+ std::string fstab = import_dt_fstab();
+ if (fstab.empty()) {
+ LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
+ return true;
}
- FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
+
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
if (!fstab_file) {
- PLOG(ERROR) << "Failed to open fstab string as FILE";
- return;
- }
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
- fclose(fstab_file);
- if (!fstab) {
- LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
- return;
- }
- LOG(INFO) << "Loaded vendor fstab from cmdline";
-
- if (early_device_socket_open()) {
- LOG(ERROR) << "Failed to open device uevent socket";
- return;
+ PLOG(ERROR) << "Early mount failed to open fstab file in memory";
+ return false;
}
- /* Create /dev/device-mapper for dm-verity */
- early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
+ fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
+ if (!tab) {
+ LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
+ return false;
+ }
- for (int i = 0; i < fstab->num_entries; ++i) {
- struct fstab_rec *rec = &fstab->recs[i];
- std::string mount_point = rec->mount_point;
- std::string syspath = rec->blk_device;
+ // find out fstab records for odm, system and vendor
+ fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
+ fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
+ fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
+ if (!odm_rec && !system_rec && !vendor_rec) {
+ // nothing to early mount
+ return true;
+ }
- if (mount_point != "/vendor" && mount_point != "/odm")
- continue;
+ // assume A/B device if we find 'slotselect' in any fstab entry
+ bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
+ (system_rec && fs_mgr_is_slotselect(system_rec)) ||
+ (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
+ bool found_odm = !odm_rec;
+ bool found_system = !system_rec;
+ bool found_vendor = !vendor_rec;
+ int count_odm = 0, count_vendor = 0, count_system = 0;
- /* Create mount target under /dev/block/ from sysfs via uevent */
- LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
- char *devpath = strdup(get_path("/dev/block", syspath).c_str());
- if (!devpath) {
- PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
- continue;
- }
- rec->blk_device = devpath;
- early_create_dev(syspath, EARLY_BLOCK_DEV);
-
- int rc = fs_mgr_early_setup_verity(rec);
- if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
- /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
- early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
- } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
- LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
- continue;
- } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
- LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+ // create the devices we need..
+ device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
+ if (!strncmp(uevent->subsystem, "firmware", 8)) {
+ return COLDBOOT_CONTINUE;
}
- mkdir(mount_point.c_str(), 0755);
- rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
- if (rc) {
- PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+ // we need platform devices to create symlinks
+ if (!strncmp(uevent->subsystem, "platform", 8)) {
+ return COLDBOOT_CREATE;
}
+
+ // Ignore everything that is not a block device
+ if (strncmp(uevent->subsystem, "block", 5)) {
+ return COLDBOOT_CONTINUE;
+ }
+
+ coldboot_action_t ret;
+ bool create_this_node = false;
+ if (uevent->partition_name) {
+ // prefix match partition names so we create device nodes for
+ // A/B-ed partitions
+ if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+ // wait twice for A/B-ed partitions
+ count_odm++;
+ if (!is_ab) {
+ found_odm = true;
+ } else if (count_odm == 2) {
+ found_odm = true;
+ }
+
+ create_this_node = true;
+ } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+ count_system++;
+ if (!is_ab) {
+ found_system = true;
+ } else if (count_system == 2) {
+ found_system = true;
+ }
+
+ create_this_node = true;
+ } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+ count_vendor++;
+ if (!is_ab) {
+ found_vendor = true;
+ } else if (count_vendor == 2) {
+ found_vendor = true;
+ }
+
+ create_this_node = true;
+ }
+ }
+
+ // if we found all other partitions already, create this
+ // node and stop coldboot. If this is a prefix matched
+ // partition, create device node and continue. For everything
+ // else skip the device node
+ if (found_odm && found_system && found_vendor) {
+ ret = COLDBOOT_STOP;
+ } else if (create_this_node) {
+ ret = COLDBOOT_CREATE;
+ } else {
+ ret = COLDBOOT_CONTINUE;
+ }
+
+ return ret;
+ });
+
+ // TODO: add support to mount partitions w/ verity
+
+ int ret = 0;
+ if (odm_rec &&
+ (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
+ PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
+ return false;
}
- early_device_socket_close();
+
+ if (vendor_rec &&
+ (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
+ PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
+ return false;
+ }
+
+ device_close();
+
+ return true;
}
int main(int argc, char** argv) {
@@ -787,8 +913,10 @@
LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
if (is_first_stage) {
- // Mount devices defined in android.early.* kernel commandline
- early_mount();
+ if (!early_mount()) {
+ LOG(ERROR) << "Failed to mount required partitions early ...";
+ panic();
+ }
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 5e54328..0a2f5a3 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -21,6 +21,7 @@
#include <dwarf.h>
}
+#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -30,6 +31,7 @@
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <string>
#include <vector>
@@ -90,9 +92,6 @@
has_debug_frame(false), has_gnu_debugdata(false) { }
};
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>& g_debug_frames =
- *new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
-
void Space::Clear() {
start = 0;
end = 0;
@@ -282,39 +281,14 @@
// vaddr in the elf file.
uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
- if (debug_frame->has_arm_exidx) {
- auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
- if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
- // Use binary search to find the correct function.
- auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
- static_cast<uint32_t>(ip_vaddr));
- if (it != func_vaddrs.begin()) {
- --it;
- // Found the exidx entry.
- size_t index = it - func_vaddrs.begin();
- proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
- proc_info->unwind_info = reinterpret_cast<void*>(
- static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
- debug_frame->arm_exidx.exidx_vaddr +
- debug_frame->min_vaddr));
-
- // Prepare arm_exidx space and arm_extab space.
- arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
- arm_exidx_space_.end = arm_exidx_space_.start +
- debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
- arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
- debug_frame->arm_exidx.exidx_data.data());
-
- arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
- arm_extab_space_.end = arm_extab_space_.start +
- debug_frame->arm_exidx.extab_data.size();
- arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
- return true;
- }
- }
- }
-
+ // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
+ // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
+ // function range for each entry, by matching ip address with the function range, we know exactly
+ // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
+ // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
+ // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
+ // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
if (debug_frame->has_eh_frame) {
if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
ip_vaddr < debug_frame->text_end_vaddr) {
@@ -323,7 +297,6 @@
eh_frame_hdr_space_.end =
eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
-
eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
eh_frame_space_.data = debug_frame->eh_frame.data.data();
@@ -345,7 +318,6 @@
}
}
}
-
if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
unw_dyn_info_t di;
unw_word_t segbase = map.start - map.offset;
@@ -359,6 +331,40 @@
}
}
}
+
+ if (debug_frame->has_arm_exidx) {
+ auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
+ if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
+ // Use binary search to find the correct function.
+ auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
+ static_cast<uint32_t>(ip_vaddr));
+ if (it != func_vaddrs.begin()) {
+ --it;
+ // Found the exidx entry.
+ size_t index = it - func_vaddrs.begin();
+ proc_info->start_ip = *it;
+ proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+ proc_info->unwind_info = reinterpret_cast<void*>(
+ static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
+ debug_frame->arm_exidx.exidx_vaddr +
+ debug_frame->min_vaddr));
+ eh_frame_hdr_space_.Clear();
+ eh_frame_space_.Clear();
+ // Prepare arm_exidx space and arm_extab space.
+ arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
+ arm_exidx_space_.end = arm_exidx_space_.start +
+ debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
+ arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
+ debug_frame->arm_exidx.exidx_data.data());
+
+ arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
+ arm_extab_space_.end = arm_extab_space_.start +
+ debug_frame->arm_exidx.extab_data.size();
+ arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
+ return true;
+ }
+ }
+ }
return false;
}
@@ -549,18 +555,31 @@
return "";
}
+static std::mutex g_lock;
+static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
+
static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
if (cache_file_) {
- auto it = g_debug_frames.find(filename);
- if (it != g_debug_frames.end()) {
- return it->second.get();
+ std::lock_guard<std::mutex> lock(g_lock);
+ if (g_debug_frames != nullptr) {
+ auto it = g_debug_frames->find(filename);
+ if (it != g_debug_frames->end()) {
+ return it->second.get();
+ }
}
}
DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
if (cache_file_) {
- g_debug_frames.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+ std::lock_guard<std::mutex> lock(g_lock);
+ if (g_debug_frames == nullptr) {
+ g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
+ }
+ auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+ if (!pair.second) {
+ debug_frame = pair.first->second.get();
+ }
}
return debug_frame;
}
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 49fcb29..465b3f9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -220,25 +220,7 @@
#endif
}
-static void BacktraceOfflineTest(const std::string& testlib_name) {
- const std::string arch = GetArch();
- if (arch.empty()) {
- GTEST_LOG_(INFO) << "This test does nothing on current arch.";
- return;
- }
- const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
- std::string testdata;
- ASSERT_TRUE(android::base::ReadFileToString(offline_testdata_path, &testdata));
-
- const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
- struct stat st;
- if (stat(testlib_path.c_str(), &st) == -1) {
- GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
- return;
- }
-
- // Parse offline_testdata.
- std::vector<std::string> lines = android::base::Split(testdata, "\n");
+struct OfflineTestData {
int pid;
int tid;
std::vector<backtrace_map_t> maps;
@@ -246,63 +228,93 @@
backtrace_stackinfo_t stack_info;
std::vector<uint8_t> stack;
std::vector<FunctionSymbol> symbols;
+};
+
+bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
+ std::string s;
+ if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
+ return false;
+ }
+ // Parse offline_testdata.
+ std::vector<std::string> lines = android::base::Split(s, "\n");
+ memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
for (const auto& line : lines) {
if (android::base::StartsWith(line, "pid:")) {
- sscanf(line.c_str(), "pid: %d tid: %d", &pid, &tid);
+ sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
} else if (android::base::StartsWith(line, "map:")) {
- maps.resize(maps.size() + 1);
+ testdata->maps.resize(testdata->maps.size() + 1);
+ backtrace_map_t& map = testdata->maps.back();
int pos;
sscanf(line.c_str(),
"map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
" load_base: %" SCNxPTR " flags: %d name: %n",
- &maps.back().start, &maps.back().end, &maps.back().offset,
- &maps.back().load_base, &maps.back().flags, &pos);
- maps.back().name = android::base::Trim(line.substr(pos));
+ &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+ map.name = android::base::Trim(line.substr(pos));
} else if (android::base::StartsWith(line, "registers:")) {
size_t size;
int pos;
sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
- ASSERT_EQ(sizeof(unw_context), size);
- HexStringToRawData(&line[pos], &unw_context, size);
+ if (sizeof(testdata->unw_context) != size) {
+ return false;
+ }
+ HexStringToRawData(&line[pos], &testdata->unw_context, size);
} else if (android::base::StartsWith(line, "stack:")) {
size_t size;
int pos;
sscanf(line.c_str(),
"stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
- &stack_info.start, &stack_info.end, &size, &pos);
- stack.resize(size);
- HexStringToRawData(&line[pos], &stack[0], size);
- stack_info.data = stack.data();
+ &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
+ testdata->stack.resize(size);
+ HexStringToRawData(&line[pos], &testdata->stack[0], size);
+ testdata->stack_info.data = testdata->stack.data();
} else if (android::base::StartsWith(line, "function:")) {
- symbols.resize(symbols.size() + 1);
+ testdata->symbols.resize(testdata->symbols.size() + 1);
+ FunctionSymbol& symbol = testdata->symbols.back();
int pos;
sscanf(line.c_str(),
"function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
- &symbols.back().start, &symbols.back().end,
- &pos);
- symbols.back().name = line.substr(pos);
+ &symbol.start, &symbol.end, &pos);
+ symbol.name = line.substr(pos);
}
}
+ return true;
+}
+
+static void BacktraceOfflineTest(const std::string& testlib_name) {
+ const std::string arch = GetArch();
+ if (arch.empty()) {
+ GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+ return;
+ }
+ const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
+ struct stat st;
+ if (stat(testlib_path.c_str(), &st) == -1) {
+ GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+ return;
+ }
+
+ const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+ OfflineTestData testdata;
+ ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
// Fix path of libbacktrace_testlib.so.
- for (auto& map : maps) {
+ for (auto& map : testdata.maps) {
if (map.name.find("libbacktrace_test.so") != std::string::npos) {
map.name = testlib_path;
}
}
// Do offline backtrace.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid, maps));
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
ASSERT_TRUE(map != nullptr);
std::unique_ptr<Backtrace> backtrace(
- Backtrace::CreateOffline(pid, tid, map.get(), stack_info));
+ Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
ASSERT_TRUE(backtrace != nullptr);
- ucontext_t ucontext = GetUContextFromUnwContext(unw_context);
+ ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
// Collect pc values of the call stack frames.
std::vector<uintptr_t> pc_values;
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
@@ -311,17 +323,20 @@
size_t test_one_index = 0;
for (size_t i = 0; i < pc_values.size(); ++i) {
- if (FunctionNameForAddress(pc_values[i], symbols) == "test_level_one") {
+ if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
test_one_index = i;
break;
}
}
ASSERT_GE(test_one_index, 3u);
- ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], symbols));
- ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], symbols));
- ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2], symbols));
- ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3], symbols));
+ ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
+ ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
+ testdata.symbols));
+ ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
+ testdata.symbols));
+ ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
+ testdata.symbols));
}
TEST(libbacktrace, offline_eh_frame) {
@@ -339,3 +354,47 @@
TEST(libbacktrace, offline_arm_exidx) {
BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
}
+
+// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
+// overlap with each other, which appears in /system/lib/libart.so.
+TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+ const std::string arch = GetArch();
+ if (arch.empty() || arch != "arm") {
+ GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+ return;
+ }
+ const std::string testlib_path = "testdata/" + arch + "/libart.so";
+ struct stat st;
+ ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
+
+ const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata_for_libart";
+ OfflineTestData testdata;
+ ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+
+ // Fix path of /system/lib/libart.so.
+ for (auto& map : testdata.maps) {
+ if (map.name.find("libart.so") != std::string::npos) {
+ map.name = testlib_path;
+ }
+ }
+
+ // Do offline backtrace.
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
+ ASSERT_TRUE(map != nullptr);
+
+ std::unique_ptr<Backtrace> backtrace(
+ Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+ ASSERT_TRUE(backtrace != nullptr);
+
+ ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
+ ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+ // The last frame is outside of libart.so
+ ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
+ for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
+ uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
+ testdata.maps[0].load_base;
+ std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+ ASSERT_EQ(name, testdata.symbols[i].name);
+ }
+}
diff --git a/libbacktrace/testdata/arm/libart.so b/libbacktrace/testdata/arm/libart.so
new file mode 100644
index 0000000..bed8e35
--- /dev/null
+++ b/libbacktrace/testdata/arm/libart.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
new file mode 100644
index 0000000..63f6a07
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -0,0 +1,10 @@
+pid: 32232 tid: 32233
+registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+map: start: e9380000 end: e9766000 offset: 0 load_base: b000 flags: 5 name: /system/lib/libart.so
+stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
+function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
+function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
+function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
+function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
+function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
+function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
\ No newline at end of file
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index b701bba..7e27c3e 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -161,7 +161,7 @@
/* Support wifi_hal_legacy administering a network interface. */
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
- "system/bin/hw/android.hardware.wifi@1.0-service" },
+ "vendor/bin/hw/android.hardware.wifi@1.0-service" },
/* Support Bluetooth legacy hal accessing /sys/class/rfkill */
{ 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 43ad574..d2645e6 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -129,7 +129,7 @@
void* cookie;
};
-static void trampoline(void* raw_data, const char* name, const char* value) {
+static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
callback_data* data = reinterpret_cast<callback_data*>(raw_data);
data->callback(name, value, data->cookie);
}
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
new file mode 100644
index 0000000..75eab66
--- /dev/null
+++ b/libmetricslogger/Android.bp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+metricslogger_lib_src_files = [
+ "metrics_logger.cpp",
+]
+
+cc_defaults {
+ name: "metricslogger_defaults",
+
+ clang: true,
+ host_supported: true,
+
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+ shared_libs: ["liblog"],
+ whole_static_libs: ["libgtest_prod"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+
+ // 524291 corresponds to sysui_histogram, from
+ // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
+ "-DHISTOGRAM_LOG_TAG=524291",
+ ],
+}
+
+// metricslogger shared library
+// -----------------------------------------------------------------------------
+cc_library_shared {
+ name: "libmetricslogger",
+ srcs: metricslogger_lib_src_files,
+ defaults: ["metricslogger_defaults"],
+}
+
+// metricslogger shared library, debug
+// -----------------------------------------------------------------------------
+cc_library_shared {
+ name: "libmetricslogger_debug",
+ srcs: metricslogger_lib_src_files,
+ defaults: ["metricslogger_defaults"],
+
+ target: {
+ host: {
+ cflags: ["-UNDEBUG"],
+ },
+ },
+}
+
+// Native tests
+// -----------------------------------------------------------------------------
+cc_test {
+ name: "metricslogger_tests",
+ defaults: ["metricslogger_defaults"],
+ shared_libs: [
+ "libbase",
+ "libmetricslogger_debug",
+ ],
+ static_libs: ["libBionicGtestMain"],
+ srcs: [
+ "metrics_logger_test.cpp",
+ ],
+}
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
similarity index 72%
rename from bootstat/histogram_logger.h
rename to libmetricslogger/include/metricslogger/metrics_logger.h
index 60c7776..d30e56c 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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,10 +17,12 @@
#include <cstdint>
#include <string>
-namespace bootstat {
+namespace android {
+namespace metricslogger {
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
+// Logs a Tron histogram metric named |event| containing |data| to the Tron log
+// buffer.
void LogHistogram(const std::string& event, int32_t data);
-} // namespace bootstat
\ No newline at end of file
+} // namespace metricslogger
+} // namespace android
diff --git a/bootstat/histogram_logger.cpp b/libmetricslogger/metrics_logger.cpp
similarity index 76%
rename from bootstat/histogram_logger.cpp
rename to libmetricslogger/metrics_logger.cpp
index 73f3295..f8e0174 100644
--- a/bootstat/histogram_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#include "histogram_logger.h"
+#include "metricslogger/metrics_logger.h"
#include <cstdlib>
-#include <android-base/logging.h>
#include <log/log_event_list.h>
-namespace bootstat {
+namespace android {
+namespace metricslogger {
void LogHistogram(const std::string& event, int32_t data) {
- LOG(INFO) << "Logging histogram: " << event << " " << data;
android_log_event_list log(HISTOGRAM_LOG_TAG);
log << event << data << LOG_ID_EVENTS;
}
-} // namespace bootstat
+} // namespace metricslogger
+} // namespace android
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/metrics_logger_test.cpp
similarity index 70%
copy from bootstat/histogram_logger.h
copy to libmetricslogger/metrics_logger_test.cpp
index 60c7776..5a30ad7 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/metrics_logger_test.cpp
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-#include <cstdint>
-#include <string>
+#include "metricslogger/metrics_logger.h"
-namespace bootstat {
+#include <gtest/gtest.h>
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+TEST(MetricsLoggerTest, AddSingleBootEvent) {
+ android::metricslogger::LogHistogram("test_event", 42);
+ // TODO(jhawkins): Verify the EventLog is updated.
+}
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 02e7075..ac64f71 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -22,16 +22,15 @@
__BEGIN_DECLS
/*
- * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
- * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- * The libraries in this list should be loaded prior to this call.
+ * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
+ * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
*
- * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * The library_search_path is the search path for anonymous namespace. The anonymous namespace
* is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
* for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
*/
-extern bool android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path);
enum {
@@ -87,6 +86,26 @@
android_namespace_t* parent);
/*
+ * Creates a link between namespaces. Every link has list of sonames of
+ * shared libraries. These are the libraries which are accessible from
+ * namespace 'from' but loaded within namespace 'to' context.
+ * When to namespace is nullptr this function establishes a link between
+ * 'from' namespace and the default namespace.
+ *
+ * The lookup order of the libraries in namespaces with links is following:
+ * 1. Look inside current namespace using 'this' namespace search path.
+ * 2. Look in linked namespaces
+ * 2.1. Perform soname check - if library soname is not in the list of shared
+ * libraries sonames skip this link, otherwise
+ * 2.2. Search library using linked namespace search path. Note that this
+ * step will not go deeper into linked namespaces for this library but
+ * will do so for DT_NEEDED libraries.
+ */
+extern bool android_link_namespaces(android_namespace_t* from,
+ android_namespace_t* to,
+ const char* shared_libs_sonames);
+
+/*
* Get the default library search path.
* The path will be copied into buffer, which must have space for at least
* buffer_size chars. Elements are separated with ':', and the path will always
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 2f23c2c..74f2f1d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -165,6 +165,11 @@
return false;
}
+ if (!android_link_namespaces(ns, nullptr, public_libraries_.c_str())) {
+ *error_msg = dlerror();
+ return false;
+ }
+
native_loader_ns = NativeLoaderNamespace(ns);
} else {
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
@@ -310,8 +315,8 @@
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- initialized_ = android_init_namespaces(public_libraries_.c_str(),
- is_native_bridge ? nullptr : library_path);
+ initialized_ = android_init_anonymous_namespace(public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
if (!initialized_) {
*error_msg = dlerror();
return false;
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index ed11164..80bb673 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 66e7750..36bb443 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main