Merge "liblog: accept log messages with hdr_size greater than known headers"
diff --git a/init/README.md b/init/README.md
index e8df4ec..b8300fa 100644
--- a/init/README.md
+++ b/init/README.md
@@ -583,6 +583,7 @@
Note that this is _not_ synchronous, and even if it were, there is
no guarantee that the operating system's scheduler will execute the
service sufficiently to guarantee anything about the service's status.
+ See the `exec_start` command for a synchronous version of `start`.
> This creates an important consequence that if the service offers
functionality to other services, such as providing a
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 98a9805..1028330 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -84,6 +84,7 @@
using namespace std::literals::string_literals;
using android::base::Basename;
+using android::base::SetProperty;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -561,16 +562,16 @@
LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
}
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "block");
+ SetProperty("ro.crypto.state", "encrypted");
+ SetProperty("ro.crypto.type", "block");
ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
return {};
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
- property_set("ro.crypto.state", "unencrypted");
+ SetProperty("ro.crypto.state", "unencrypted");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return {};
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
- property_set("ro.crypto.state", "unsupported");
+ SetProperty("ro.crypto.state", "unsupported");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return {};
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
@@ -586,8 +587,8 @@
if (!FscryptInstallKeyring()) {
return Error() << "FscryptInstallKeyring() failed";
}
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "file");
+ SetProperty("ro.crypto.state", "encrypted");
+ SetProperty("ro.crypto.type", "file");
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
@@ -597,8 +598,8 @@
if (!FscryptInstallKeyring()) {
return Error() << "FscryptInstallKeyring() failed";
}
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "file");
+ SetProperty("ro.crypto.state", "encrypted");
+ SetProperty("ro.crypto.type", "file");
// Although encrypted, vold has already set the device up, so we do not need to
// do anything different from the nonencrypted case.
@@ -608,8 +609,8 @@
if (!FscryptInstallKeyring()) {
return Error() << "FscryptInstallKeyring() failed";
}
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "file");
+ SetProperty("ro.crypto.state", "encrypted");
+ SetProperty("ro.crypto.type", "file");
// Although encrypted, vold has already set the device up, so we do not need to
// do anything different from the nonencrypted case.
@@ -662,7 +663,7 @@
}
auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
- property_set(prop_name, std::to_string(t.duration().count()));
+ SetProperty(prop_name, std::to_string(t.duration().count()));
if (import_rc && SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
@@ -718,7 +719,7 @@
<< "' from init; use the restorecon builtin directly";
}
- property_set(args[1], args[2]);
+ SetProperty(args[1], args[2]);
return {};
}
@@ -832,7 +833,7 @@
// To be consistent in vboot 1.0 and vboot 2.0 (AVB), use "system" for the partition even
// for system as root, so it has property [partition.system.verified].
std::string partition = entry.mount_point == "/" ? "system" : Basename(entry.mount_point);
- property_set("partition." + partition + ".verified", std::to_string(mode));
+ SetProperty("partition." + partition + ".verified", std::to_string(mode));
}
return {};
@@ -1221,8 +1222,8 @@
static Result<void> do_finish_userspace_reboot(const BuiltinArguments&) {
LOG(INFO) << "Userspace reboot successfully finished";
boot_clock::time_point now = boot_clock::now();
- property_set("sys.init.userspace_reboot.last_finished",
- std::to_string(now.time_since_epoch().count()));
+ SetProperty("sys.init.userspace_reboot.last_finished",
+ std::to_string(now.time_since_epoch().count()));
if (!android::sysprop::InitProperties::userspace_reboot_in_progress(false)) {
return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
}
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 30d3129..caa8f8d 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -39,15 +39,6 @@
inline bool CanReadProperty(const std::string&, const std::string&) {
return true;
}
-inline uint32_t SetProperty(const std::string& key, const std::string& value) {
- android::base::SetProperty(key, value);
- return 0;
-}
-inline uint32_t (*property_set)(const std::string& name, const std::string& value) = SetProperty;
-inline uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&,
- const ucred&, std::string*) {
- return 0;
-}
// reboot_utils.h
inline void SetFatalRebootTarget() {}
diff --git a/init/init.cpp b/init/init.cpp
index 8e2da59..c457de6 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -81,6 +81,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::ReadFileToString;
+using android::base::SetProperty;
using android::base::StringPrintf;
using android::base::Timer;
using android::base::Trim;
@@ -91,8 +92,6 @@
static int property_triggers_enabled = 0;
-static char qemu[32];
-
static int signal_fd = -1;
static int property_fd = -1;
@@ -101,7 +100,6 @@
static std::string wait_prop_value;
static std::string shutdown_command;
static bool do_shutdown = false;
-static bool load_debug_prop = false;
static std::unique_ptr<Subcontext> subcontext;
@@ -208,7 +206,7 @@
// to wait.
if (name == kColdBootDoneProp) {
auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0;
- property_set("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
+ SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
}
if (waiting_for_prop) {
@@ -364,85 +362,15 @@
return {};
}
-static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
- if (key.empty()) return;
-
- if (for_emulator) {
- // In the emulator, export any kernel option with the "ro.kernel." prefix.
- property_set("ro.kernel." + key, value);
- return;
- }
-
- if (key == "qemu") {
- strlcpy(qemu, value.c_str(), sizeof(qemu));
- } else if (android::base::StartsWith(key, "androidboot.")) {
- property_set("ro.boot." + key.substr(12), value);
- }
-}
-
static void export_oem_lock_status() {
if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
return;
}
- import_kernel_cmdline(
- false, [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.verifiedbootstate") {
- property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
- }
- });
-}
-
-static void export_kernel_boot_props() {
- constexpr const char* UNSET = "";
- struct {
- const char *src_prop;
- const char *dst_prop;
- const char *default_value;
- } prop_map[] = {
- { "ro.boot.serialno", "ro.serialno", UNSET, },
- { "ro.boot.mode", "ro.bootmode", "unknown", },
- { "ro.boot.baseband", "ro.baseband", "unknown", },
- { "ro.boot.bootloader", "ro.bootloader", "unknown", },
- { "ro.boot.hardware", "ro.hardware", "unknown", },
- { "ro.boot.revision", "ro.revision", "0", },
- };
- for (const auto& prop : prop_map) {
- std::string value = GetProperty(prop.src_prop, prop.default_value);
- if (value != UNSET)
- property_set(prop.dst_prop, value);
- }
-}
-
-static void process_kernel_dt() {
- if (!is_android_dt_value_expected("compatible", "android,firmware")) {
- return;
- }
-
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), 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;
+ ImportKernelCmdline([](const std::string& key, const std::string& value) {
+ if (key == "androidboot.verifiedbootstate") {
+ SetProperty("ro.boot.flash.locked", value == "orange" ? "0" : "1");
}
-
- std::string file_name = get_android_dt_dir() + dp->d_name;
-
- android::base::ReadFileToString(file_name, &dt_file);
- std::replace(dt_file.begin(), dt_file.end(), ',', '.');
-
- property_set("ro.boot."s + dp->d_name, dt_file);
- }
-}
-
-static void process_kernel_cmdline() {
- // The first pass does the common stuff, and finds if we are in qemu.
- // The second pass is only necessary for qemu to export all kernel params
- // as properties.
- import_kernel_cmdline(false, import_kernel_nv);
- if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
+ });
}
static Result<void> property_enable_triggers_action(const BuiltinArguments& args) {
@@ -468,7 +396,7 @@
while ((dp = readdir(dir.get())) != nullptr) {
if (dp->d_name[0] == '.') continue;
- property_set("sys.usb.controller", dp->d_name);
+ SetProperty("sys.usb.controller", dp->d_name);
break;
}
}
@@ -591,7 +519,7 @@
int64_t first_stage_start_time_ns = -1;
if (auto first_stage_start_time_str = getenv(kEnvFirstStageStartedAt);
first_stage_start_time_str) {
- property_set("ro.boottime.init", first_stage_start_time_str);
+ SetProperty("ro.boottime.init", first_stage_start_time_str);
android::base::ParseInt(first_stage_start_time_str, &first_stage_start_time_ns);
}
unsetenv(kEnvFirstStageStartedAt);
@@ -605,11 +533,11 @@
if (selinux_start_time_ns == -1) return;
if (first_stage_start_time_ns == -1) return;
- property_set("ro.boottime.init.first_stage",
- std::to_string(selinux_start_time_ns - first_stage_start_time_ns));
- property_set("ro.boottime.init.selinux",
- std::to_string(second_stage_start_time.time_since_epoch().count() -
- selinux_start_time_ns));
+ SetProperty("ro.boottime.init.first_stage",
+ std::to_string(selinux_start_time_ns - first_stage_start_time_ns));
+ SetProperty("ro.boottime.init.selinux",
+ std::to_string(second_stage_start_time.time_since_epoch().count() -
+ selinux_start_time_ns));
}
void SendLoadPersistentPropertiesMessage() {
@@ -706,34 +634,27 @@
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
- property_init();
-
- // If arguments are passed both on the command line and in DT,
- // properties set in DT always have priority over the command-line ones.
- process_kernel_dt();
- process_kernel_cmdline();
-
- // Propagate the kernel variables to internal variables
- // used by init as well as the current required properties.
- export_kernel_boot_props();
-
- // Make the time that init stages started available for bootstat to log.
- RecordStageBoottimes(start_time);
-
- // Set libavb version for Framework-only OTA match in Treble build.
- const char* avb_version = getenv("INIT_AVB_VERSION");
- if (avb_version) property_set("ro.boot.avb_version", avb_version);
-
// See if need to load debug props to allow adb root, when the device is unlocked.
const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+ bool load_debug_prop = false;
if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
load_debug_prop = "true"s == force_debuggable_env;
}
-
- // Clean up our environment.
- unsetenv("INIT_AVB_VERSION");
unsetenv("INIT_FORCE_DEBUGGABLE");
+ // Umount the debug ramdisk so property service doesn't read .prop files from there, when it
+ // is not meant to.
+ if (!load_debug_prop) {
+ UmountDebugRamdisk();
+ }
+
+ PropertyInit();
+
+ // Umount the debug ramdisk after property service has read the .prop files when it means to.
+ if (load_debug_prop) {
+ UmountDebugRamdisk();
+ }
+
// Now set up SELinux for second stage.
SelinuxSetupKernelLogging();
SelabelInitialize();
@@ -746,16 +667,22 @@
InstallSignalFdHandler(&epoll);
- property_load_boot_defaults(load_debug_prop);
- UmountDebugRamdisk();
- fs_mgr_vendor_overlay_mount_all();
- export_oem_lock_status();
-
StartPropertyService(&property_fd);
if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
}
+ // Make the time that init stages started available for bootstat to log.
+ RecordStageBoottimes(start_time);
+
+ // Set libavb version for Framework-only OTA match in Treble build.
+ if (const char* avb_version = getenv("INIT_AVB_VERSION"); avb_version != nullptr) {
+ SetProperty("ro.boot.avb_version", avb_version);
+ }
+ unsetenv("INIT_AVB_VERSION");
+
+ fs_mgr_vendor_overlay_mount_all();
+ export_oem_lock_status();
MountHandler mount_handler(&epoll);
set_usb_controller();
@@ -779,9 +706,9 @@
// Make the GSI status available before scripts start running.
if (android::gsi::IsGsiRunning()) {
- property_set("ro.gsid.image_running", "1");
+ SetProperty("ro.gsid.image_running", "1");
} else {
- property_set("ro.gsid.image_running", "0");
+ SetProperty("ro.gsid.image_running", "0");
}
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 791a019..0e4e024 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -38,7 +38,6 @@
#include <libdm/dm.h>
#include "epoll.h"
-#include "property_service.h"
namespace android {
namespace init {
@@ -96,7 +95,7 @@
// handling, except for clearing non-existent or already clear property.
// Goal is reduction of empty properties and associated triggers.
if (value.empty() && android::base::GetProperty(mount_prop, "").empty()) return;
- property_set(mount_prop, value);
+ android::base::SetProperty(mount_prop, value);
}
} // namespace
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 0745148..940fb6b 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -25,6 +25,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include "util.h"
@@ -79,30 +80,69 @@
return updatable;
}
+static Result<void> MountDir(const std::string& path, const std::string& mount_path) {
+ if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && ret != EEXIST) {
+ return ErrnoError() << "Could not create mount point " << mount_path;
+ }
+ if (mount(path.c_str(), mount_path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
+ return ErrnoError() << "Could not bind mount " << path << " to " << mount_path;
+ }
+ return {};
+}
+
+static Result<void> ActivateFlattenedApexesFrom(const std::string& from_dir,
+ const std::string& to_dir) {
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(from_dir.c_str()), closedir);
+ if (!dir) {
+ return {};
+ }
+ dirent* entry;
+ while ((entry = readdir(dir.get())) != nullptr) {
+ if (entry->d_name[0] == '.') continue;
+ if (entry->d_type == DT_DIR) {
+ const std::string apex_path = from_dir + "/" + entry->d_name;
+ const std::string mount_path = to_dir + "/" + entry->d_name;
+ if (auto result = MountDir(apex_path, mount_path); !result) {
+ return result;
+ }
+ }
+ }
+ return {};
+}
+
static bool ActivateFlattenedApexesIfPossible() {
if (IsRecoveryMode() || IsApexUpdatable()) {
return true;
}
- constexpr const char kSystemApex[] = "/system/apex";
- constexpr const char kApexTop[] = "/apex";
- if (mount(kSystemApex, kApexTop, nullptr, MS_BIND, nullptr) != 0) {
- PLOG(ERROR) << "Could not bind mount " << kSystemApex << " to " << kApexTop;
- return false;
- }
+ const std::string kApexTop = "/apex";
+ const std::vector<std::string> kBuiltinDirsForApexes = {
+ "/system/apex",
+ "/system_ext/apex",
+ "/product/apex",
+ "/vendor/apex",
+ };
+ for (const auto& dir : kBuiltinDirsForApexes) {
+ if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop); !result) {
+ LOG(ERROR) << result.error();
+ return false;
+ }
+ }
// Special casing for the ART APEX
- constexpr const char kArtApexMountPath[] = "/system/apex/com.android.art";
+ constexpr const char kArtApexMountPath[] = "/apex/com.android.art";
static const std::vector<std::string> kArtApexDirNames = {"com.android.art.release",
"com.android.art.debug"};
bool success = false;
for (const auto& name : kArtApexDirNames) {
- std::string path = std::string(kSystemApex) + "/" + name;
+ std::string path = kApexTop + "/" + name;
if (access(path.c_str(), F_OK) == 0) {
- if (mount(path.c_str(), kArtApexMountPath, nullptr, MS_BIND, nullptr) == 0) {
- success = true;
- break;
+ if (auto result = MountDir(path, kArtApexMountPath); !result) {
+ LOG(ERROR) << result.error();
+ return false;
}
+ success = true;
+ break;
}
}
if (!success) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7d707cc..adf8929 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -97,8 +97,6 @@
static PropertyInfoAreaFile property_info_area;
-void CreateSerializedPropertyInfo();
-
struct PropertyAuditData {
const ucred* cr;
const char* name;
@@ -117,21 +115,6 @@
return 0;
}
-void property_init() {
- selinux_callback cb;
- cb.func_audit = PropertyAuditCallback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
- mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
- CreateSerializedPropertyInfo();
- if (__system_property_area_init()) {
- LOG(FATAL) << "Failed to initialize property area";
- }
- if (!property_info_area.LoadDefaultPath()) {
- LOG(FATAL) << "Failed to load serialized property info file";
- }
-}
-
bool CanReadProperty(const std::string& source_context, const std::string& name) {
const char* target_context = nullptr;
property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
@@ -527,20 +510,6 @@
return PropertySet(name, value, error);
}
-uint32_t InitPropertySet(const std::string& name, const std::string& value) {
- uint32_t result = 0;
- ucred cr = {.pid = 1, .uid = 0, .gid = 0};
- std::string error;
- result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
- if (result != PROP_SUCCESS) {
- LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
- }
-
- return result;
-}
-
-uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
-
static void handle_property_set_fd() {
static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
@@ -634,6 +603,18 @@
}
}
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+ uint32_t result = 0;
+ ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+ std::string error;
+ result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
+ if (result != PROP_SUCCESS) {
+ LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
+ }
+
+ return result;
+}
+
static bool load_properties_from_file(const char*, const char*,
std::map<std::string, std::string>*);
@@ -765,11 +746,11 @@
bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
std::string config = android::base::GetProperty("persist.sys.usb.config", "");
if (config.empty()) {
- property_set("persist.sys.usb.config", is_debuggable ? "adb" : "none");
+ InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
} else if (is_debuggable && config.find("adb") == std::string::npos &&
config.length() + 4 < PROP_VALUE_MAX) {
config.append(",adb");
- property_set("persist.sys.usb.config", config);
+ InitPropertySet("persist.sys.usb.config", config);
}
}
@@ -890,7 +871,7 @@
}
}
-void property_load_boot_defaults(bool load_debug_prop) {
+void PropertyLoadBootDefaults() {
// TODO(b/117892318): merge prop.default and build.prop files into one
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
@@ -916,7 +897,7 @@
load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
- if (load_debug_prop) {
+ if (access(kDebugRamdiskProp, R_OK) == 0) {
LOG(INFO) << "Loading " << kDebugRamdiskProp;
load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
}
@@ -1009,6 +990,97 @@
selinux_android_restorecon(kPropertyInfosPath, 0);
}
+static void ExportKernelBootProps() {
+ constexpr const char* UNSET = "";
+ struct {
+ const char* src_prop;
+ const char* dst_prop;
+ const char* default_value;
+ } prop_map[] = {
+ // clang-format off
+ { "ro.boot.serialno", "ro.serialno", UNSET, },
+ { "ro.boot.mode", "ro.bootmode", "unknown", },
+ { "ro.boot.baseband", "ro.baseband", "unknown", },
+ { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+ { "ro.boot.hardware", "ro.hardware", "unknown", },
+ { "ro.boot.revision", "ro.revision", "0", },
+ // clang-format on
+ };
+ for (const auto& prop : prop_map) {
+ std::string value = GetProperty(prop.src_prop, prop.default_value);
+ if (value != UNSET) InitPropertySet(prop.dst_prop, value);
+ }
+}
+
+static void ProcessKernelDt() {
+ if (!is_android_dt_value_expected("compatible", "android,firmware")) {
+ return;
+ }
+
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), 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;
+ }
+
+ std::string file_name = get_android_dt_dir() + dp->d_name;
+
+ android::base::ReadFileToString(file_name, &dt_file);
+ std::replace(dt_file.begin(), dt_file.end(), ',', '.');
+
+ InitPropertySet("ro.boot."s + dp->d_name, dt_file);
+ }
+}
+
+static void ProcessKernelCmdline() {
+ bool for_emulator = false;
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ if (key == "qemu") {
+ for_emulator = true;
+ } else if (StartsWith(key, "androidboot.")) {
+ InitPropertySet("ro.boot." + key.substr(12), value);
+ }
+ });
+
+ if (for_emulator) {
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ // In the emulator, export any kernel option with the "ro.kernel." prefix.
+ InitPropertySet("ro.kernel." + key, value);
+ });
+ }
+}
+
+void PropertyInit() {
+ selinux_callback cb;
+ cb.func_audit = PropertyAuditCallback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
+ mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
+ CreateSerializedPropertyInfo();
+ if (__system_property_area_init()) {
+ LOG(FATAL) << "Failed to initialize property area";
+ }
+ if (!property_info_area.LoadDefaultPath()) {
+ LOG(FATAL) << "Failed to load serialized property info file";
+ }
+
+ // If arguments are passed both on the command line and in DT,
+ // properties set in DT always have priority over the command-line ones.
+ ProcessKernelDt();
+ ProcessKernelCmdline();
+
+ // Propagate the kernel variables to internal variables
+ // used by init as well as the current required properties.
+ ExportKernelBootProps();
+
+ PropertyLoadBootDefaults();
+}
+
static void HandleInitSocket() {
auto message = ReadMessage(init_socket);
if (!message) {
@@ -1075,7 +1147,7 @@
}
void StartPropertyService(int* epoll_socket) {
- property_set("ro.property_service.version", "2");
+ InitPropertySet("ro.property_service.version", "2");
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
@@ -1095,11 +1167,6 @@
listen(property_set_fd, 8);
std::thread{PropertyServiceThread}.detach();
-
- property_set = [](const std::string& key, const std::string& value) -> uint32_t {
- android::base::SetProperty(key, value);
- return 0;
- };
}
} // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 8f7d8d9..506d116 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -29,10 +29,7 @@
bool CanReadProperty(const std::string& source_context, const std::string& name);
-extern uint32_t (*property_set)(const std::string& name, const std::string& value);
-
-void property_init();
-void property_load_boot_defaults(bool load_debug_prop);
+void PropertyInit();
void StartPropertyService(int* epoll_socket);
} // namespace init
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b04db7f..e9d918e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -59,7 +59,6 @@
#include "builtin_arguments.h"
#include "init.h"
#include "mount_namespace.h"
-#include "property_service.h"
#include "reboot_utils.h"
#include "service.h"
#include "service_list.h"
@@ -548,7 +547,7 @@
reasons[1] == "hard" || reasons[1] == "warm")) {
skip = strlen("reboot,");
}
- property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
+ SetProperty(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
sync();
bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
@@ -619,7 +618,7 @@
bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
if (do_shutdown_animation) {
- property_set("service.bootanim.exit", "0");
+ SetProperty("service.bootanim.exit", "0");
// Could be in the middle of animation. Stop and start so that it can pick
// up the right mode.
boot_anim->Stop();
@@ -733,8 +732,8 @@
static Result<void> DoUserspaceReboot() {
LOG(INFO) << "Userspace reboot initiated";
boot_clock::time_point now = boot_clock::now();
- property_set("sys.init.userspace_reboot.last_started",
- std::to_string(now.time_since_epoch().count()));
+ SetProperty("sys.init.userspace_reboot.last_started",
+ std::to_string(now.time_since_epoch().count()));
auto guard = android::base::make_scope_guard([] {
// Leave shutdown so that we can handle a full reboot.
LeaveShutdown();
diff --git a/init/selinux.cpp b/init/selinux.cpp
index a9cd290..2fc8f6d 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -88,12 +88,11 @@
EnforcingStatus StatusFromCmdline() {
EnforcingStatus status = SELINUX_ENFORCING;
- import_kernel_cmdline(false,
- [&](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.selinux" && value == "permissive") {
- status = SELINUX_PERMISSIVE;
- }
- });
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ if (key == "androidboot.selinux" && value == "permissive") {
+ status = SELINUX_PERMISSIVE;
+ }
+ });
return status;
}
diff --git a/init/service.cpp b/init/service.cpp
index ad42df7..cc97d94 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -45,7 +45,6 @@
#include <android/api-level.h>
#include "mount_namespace.h"
-#include "property_service.h"
#include "selinux.h"
#else
#include "host_init_stubs.h"
@@ -55,6 +54,7 @@
using android::base::GetProperty;
using android::base::Join;
using android::base::make_scope_guard;
+using android::base::SetProperty;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -164,13 +164,13 @@
}
std::string prop_name = "init.svc." + name_;
- property_set(prop_name, new_state);
+ SetProperty(prop_name, new_state);
if (new_state == "running") {
uint64_t start_ns = time_started_.time_since_epoch().count();
std::string boottime_property = "ro.boottime." + name_;
if (GetProperty(boottime_property, "").empty()) {
- property_set(boottime_property, std::to_string(start_ns));
+ SetProperty(boottime_property, std::to_string(start_ns));
}
}
@@ -178,9 +178,9 @@
// on device for security checks.
std::string pid_property = "init.svc_debug_pid." + name_;
if (new_state == "running") {
- property_set(pid_property, std::to_string(pid_));
+ SetProperty(pid_property, std::to_string(pid_));
} else if (new_state == "stopped") {
- property_set(pid_property, "");
+ SetProperty(pid_property, "");
}
}
@@ -324,7 +324,7 @@
LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
<< (boot_completed ? "in 4 minutes" : "before boot completed");
// Notifies update_verifier and apexd
- property_set("sys.init.updatable_crashing", "1");
+ SetProperty("sys.init.updatable_crashing", "1");
}
}
} else {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index bebcc77..f3f759d 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -176,11 +176,6 @@
SelabelInitialize();
- property_set = [](const std::string& key, const std::string& value) -> uint32_t {
- android::base::SetProperty(key, value);
- return 0;
- };
-
trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
diff --git a/init/util.cpp b/init/util.cpp
index e5254dd..0ca0da5 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -234,15 +234,14 @@
return -1;
}
-void import_kernel_cmdline(bool in_qemu,
- const std::function<void(const std::string&, const std::string&, bool)>& fn) {
+void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>& fn) {
std::string cmdline;
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) {
- fn(pieces[0], pieces[1], in_qemu);
+ fn(pieces[0], pieces[1]);
}
}
}
@@ -359,12 +358,11 @@
// Use the standard procfs-based path by default
std::string android_dt_dir = kDefaultAndroidDtDir;
// The platform may specify a custom Android DT path in kernel cmdline
- import_kernel_cmdline(false,
- [&](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.android_dt_dir") {
- android_dt_dir = value;
- }
- });
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ if (key == "androidboot.android_dt_dir") {
+ android_dt_dir = value;
+ }
+ });
LOG(INFO) << "Using Android DT directory " << android_dt_dir;
return android_dt_dir;
}
diff --git a/init/util.h b/init/util.h
index 9d89ed7..ad322d9 100644
--- a/init/util.h
+++ b/init/util.h
@@ -47,8 +47,7 @@
bool mkdir_recursive(const std::string& pathname, mode_t mode);
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
-void import_kernel_cmdline(bool in_qemu,
- const std::function<void(const std::string&, const std::string&, bool)>&);
+void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>&);
bool make_dir(const std::string& path, mode_t mode);
bool is_dir(const char* pathname);
Result<std::string> ExpandProps(const std::string& src);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 512c962..9cd3d65 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -251,6 +251,7 @@
"tests/files/offline/shared_lib_in_apk_arm64/*",
"tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
"tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
+ "tests/files/offline/signal_load_bias_arm/*",
"tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 6627787..f01b092 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -173,7 +173,12 @@
if (!valid_) {
return false;
}
- return regs->StepIfSignalHandler(rel_pc, this, process_memory);
+
+ // Convert the rel_pc to an elf_offset.
+ if (rel_pc < static_cast<uint64_t>(load_bias_)) {
+ return false;
+ }
+ return regs->StepIfSignalHandler(rel_pc - load_bias_, this, process_memory);
}
// The relative pc is always relative to the start of the map from which it comes.
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index 885dc94..1b1f7eb 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -127,12 +127,12 @@
return regs;
}
-bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsArm::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint32_t data;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+ if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
return false;
}
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index 2e8af20..1df1dff 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -126,12 +126,12 @@
return regs;
}
-bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint64_t data;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+ if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
return false;
}
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index f330fe0..ebefe42 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -129,13 +129,13 @@
return regs;
}
-bool RegsMips::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsMips::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint64_t data;
uint64_t offset = 0;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+ if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
return false;
}
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index 3f67d92..be2fd22 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -127,12 +127,12 @@
return regs;
}
-bool RegsMips64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsMips64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint64_t data;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+ if (!elf_memory->Read(elf_offset, &data, sizeof(data))) {
return false;
}
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index 9bb39d1..5538fc0 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -119,12 +119,12 @@
return regs;
}
-bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsX86::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint64_t data;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+ if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
return false;
}
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 74cd1cb..5b9aa58 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -139,17 +139,17 @@
return regs;
}
-bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+bool RegsX86_64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
uint64_t data;
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
- if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+ if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
return false;
}
uint16_t data2;
- if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
return false;
}
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1c2a81c..4f761b4 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -66,7 +66,7 @@
virtual uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) = 0;
- virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
+ virtual bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) = 0;
virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
index 44f6744..aa029be 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -40,7 +40,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index a72f91f..5cd7e5b 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -40,7 +40,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
index c9dd202..8164a15 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -40,7 +40,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index 7c42812..c982542 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -40,7 +40,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index d19e449..2323a4f 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -41,7 +41,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void SetFromUcontext(x86_ucontext_t* ucontext);
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index dc9a220..3e919a4 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -41,7 +41,7 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
- bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+ bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
void SetFromUcontext(x86_64_ucontext_t* ucontext);
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index d227b60..4866345 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -104,6 +104,8 @@
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
}
+ void VerifyStepIfSignalHandler(uint64_t load_bias);
+
MemoryFake* memory_;
};
@@ -281,7 +283,7 @@
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
}
-TEST_F(ElfTest, step_in_signal_map) {
+void ElfTest::VerifyStepIfSignalHandler(uint64_t load_bias) {
ElfFake elf(memory_);
RegsArm regs;
@@ -290,6 +292,7 @@
ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
elf.FakeSetInterface(interface);
+ elf.FakeSetLoadBias(load_bias);
memory_->SetData32(0x3000, 0xdf0027ad);
MemoryFake process_memory;
@@ -299,12 +302,20 @@
}
elf.FakeSetValid(true);
- ASSERT_TRUE(elf.StepIfSignalHandler(0x3000, ®s, &process_memory));
+ ASSERT_TRUE(elf.StepIfSignalHandler(0x3000 + load_bias, ®s, &process_memory));
EXPECT_EQ(ERROR_NONE, elf.GetLastErrorCode());
EXPECT_EQ(15U, regs.pc());
EXPECT_EQ(13U, regs.sp());
}
+TEST_F(ElfTest, step_in_signal_map) {
+ VerifyStepIfSignalHandler(0);
+}
+
+TEST_F(ElfTest, step_in_signal_map_non_zero_load_bias) {
+ VerifyStepIfSignalHandler(0x1000);
+}
+
class ElfInterfaceMock : public ElfInterface {
public:
ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0d58c09..364101a 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1629,4 +1629,72 @@
EXPECT_EQ(0xfffe1d74ULL, unwinder.frames()[10].sp);
}
+TEST_F(UnwindOfflineTest, signal_load_bias_arm) {
+ ASSERT_NO_FATAL_FAILURE(Init("signal_load_bias_arm/", ARCH_ARM));
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0029ef9e libunwindstack_unit_test (SignalInnerFunction+10)\n"
+ " #01 pc 0029efa7 libunwindstack_unit_test (SignalMiddleFunction+2)\n"
+ " #02 pc 0029efaf libunwindstack_unit_test (SignalOuterFunction+2)\n"
+ " #03 pc 002a280b libunwindstack_unit_test (unwindstack::SignalCallerHandler(int, "
+ "siginfo*, void*)+10)\n"
+ " #04 pc 00058bd4 libc.so (__restore)\n"
+ " #05 pc 0029f01e libunwindstack_unit_test (InnerFunction+106)\n"
+ " #06 pc 0029f633 libunwindstack_unit_test (MiddleFunction+16)\n"
+ " #07 pc 0029f64b libunwindstack_unit_test (OuterFunction+16)\n"
+ " #08 pc 002a1711 libunwindstack_unit_test (unwindstack::RemoteThroughSignal(int, unsigned "
+ "int)+260)\n"
+ " #09 pc 002a1603 libunwindstack_unit_test "
+ "(unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+10)\n"
+ " #10 pc 002c8fe3 libunwindstack_unit_test (testing::Test::Run()+130)\n"
+ " #11 pc 002c9b25 libunwindstack_unit_test (testing::TestInfo::Run()+184)\n"
+ " #12 pc 002c9e27 libunwindstack_unit_test (testing::TestSuite::Run()+202)\n"
+ " #13 pc 002d193d libunwindstack_unit_test "
+ "(testing::internal::UnitTestImpl::RunAllTests()+660)\n"
+ " #14 pc 002d160b libunwindstack_unit_test (testing::UnitTest::Run()+134)\n"
+ " #15 pc 002de035 libunwindstack_unit_test (IsolateMain+680)\n"
+ " #16 pc 00058155 libc.so (__libc_init+68)\n",
+ frame_info);
+
+ EXPECT_EQ(0xb6955f9eULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0xf2790ce8ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0xb6955fa7ULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0xf2790ce8ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0xb6955fafULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0xf2790cf0ULL, unwinder.frames()[2].sp);
+ EXPECT_EQ(0xb695980bULL, unwinder.frames()[3].pc);
+ EXPECT_EQ(0xf2790cf8ULL, unwinder.frames()[3].sp);
+ EXPECT_EQ(0xf23febd4ULL, unwinder.frames()[4].pc);
+ EXPECT_EQ(0xf2790d10ULL, unwinder.frames()[4].sp);
+ EXPECT_EQ(0xb695601eULL, unwinder.frames()[5].pc);
+ EXPECT_EQ(0xffe67798ULL, unwinder.frames()[5].sp);
+ EXPECT_EQ(0xb6956633ULL, unwinder.frames()[6].pc);
+ EXPECT_EQ(0xffe67890ULL, unwinder.frames()[6].sp);
+ EXPECT_EQ(0xb695664bULL, unwinder.frames()[7].pc);
+ EXPECT_EQ(0xffe678a0ULL, unwinder.frames()[7].sp);
+ EXPECT_EQ(0xb6958711ULL, unwinder.frames()[8].pc);
+ EXPECT_EQ(0xffe678b0ULL, unwinder.frames()[8].sp);
+ EXPECT_EQ(0xb6958603ULL, unwinder.frames()[9].pc);
+ EXPECT_EQ(0xffe67ac8ULL, unwinder.frames()[9].sp);
+ EXPECT_EQ(0xb697ffe3ULL, unwinder.frames()[10].pc);
+ EXPECT_EQ(0xffe67ad8ULL, unwinder.frames()[10].sp);
+ EXPECT_EQ(0xb6980b25ULL, unwinder.frames()[11].pc);
+ EXPECT_EQ(0xffe67ae8ULL, unwinder.frames()[11].sp);
+ EXPECT_EQ(0xb6980e27ULL, unwinder.frames()[12].pc);
+ EXPECT_EQ(0xffe67b18ULL, unwinder.frames()[12].sp);
+ EXPECT_EQ(0xb698893dULL, unwinder.frames()[13].pc);
+ EXPECT_EQ(0xffe67b48ULL, unwinder.frames()[13].sp);
+ EXPECT_EQ(0xb698860bULL, unwinder.frames()[14].pc);
+ EXPECT_EQ(0xffe67bb0ULL, unwinder.frames()[14].sp);
+ EXPECT_EQ(0xb6995035ULL, unwinder.frames()[15].pc);
+ EXPECT_EQ(0xffe67bd0ULL, unwinder.frames()[15].sp);
+ EXPECT_EQ(0xf23fe155ULL, unwinder.frames()[16].pc);
+ EXPECT_EQ(0xffe67d10ULL, unwinder.frames()[16].sp);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
new file mode 100644
index 0000000..f046624
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test b/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
new file mode 100644
index 0000000..f460dd6
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
new file mode 100644
index 0000000..165ae49
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
@@ -0,0 +1,4 @@
+b66b7000-b670c000 r--p 0 00:00 0 libunwindstack_unit_test
+b670c000-b69a8000 r-xp 54000 00:00 0 libunwindstack_unit_test
+f23a6000-f23d0000 r--p 0 00:00 0 libc.so
+f23d0000-f2451000 r-xp 29000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
new file mode 100644
index 0000000..e03f8fd
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: b69b7c84
+r1: 1
+r2: 1
+r3: 1
+r4: f1e52bd0
+r5: f1e11000
+r6: f1e52bd0
+r7: f1e52a38
+r8: f1e11000
+r9: 5de82a8f
+r10: f1e06030
+r11: f1e6d080
+ip: ffe67a88
+sp: f2790ce8
+lr: b6955fab
+pc: b6955f9e
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
new file mode 100644
index 0000000..d9f23f8
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
new file mode 100644
index 0000000..6011883
--- /dev/null
+++ b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
Binary files differ
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 02a61a5..c0e11d3 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -282,72 +282,78 @@
fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
- fprintf(stderr, "options include:\n"
- " -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
- " -f <file>, --file=<file> Log to file. Default is stdout\n"
- " -r <kbytes>, --rotate-kbytes=<kbytes>\n"
- " Rotate log every kbytes. Requires -f option\n"
- " -n <count>, --rotate-count=<count>\n"
- " Sets max number of rotated logs to <count>, default 4\n"
- " --id=<id> If the signature id for logging to file changes, then clear\n"
- " the fileset and continue\n"
- " -v <format>, --format=<format>\n"
- " Sets log print format verb and adverbs, where <format> is:\n"
- " brief help long process raw tag thread threadtime time\n"
- " and individually flagged modifying adverbs can be added:\n"
- " color descriptive epoch monotonic printable uid\n"
- " usec UTC year zone\n"
- " Multiple -v parameters or comma separated list of format and\n"
- " format modifiers are allowed.\n"
- // private and undocumented nsec, no signal, too much noise
- // useful for -T or -t <timestamp> accurate testing though.
- " -D, --dividers Print dividers between each log buffer\n"
- " -c, --clear Clear (flush) the entire log and exit\n"
- " if Log to File specified, clear fileset instead\n"
- " -d Dump the log and then exit (don't block)\n"
- " -e <expr>, --regex=<expr>\n"
- " Only print lines where the log message matches <expr>\n"
- " where <expr> is a regular expression\n"
- // Leave --head undocumented as alias for -m
- " -m <count>, --max-count=<count>\n"
- " Quit after printing <count> lines. This is meant to be\n"
- " paired with --regex, but will work on its own.\n"
- " --print Paired with --regex and --max-count to let content bypass\n"
- " regex filter but still stop at number of matches.\n"
- // Leave --tail undocumented as alias for -t
- " -t <count> Print only the most recent <count> lines (implies -d)\n"
- " -t '<time>' Print most recent lines since specified time (implies -d)\n"
- " -T <count> Print only the most recent <count> lines (does not imply -d)\n"
- " -T '<time>' Print most recent lines since specified time (not imply -d)\n"
- " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
- " 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
- " -g, --buffer-size Get the size of the ring buffer.\n"
- " -G <size>, --buffer-size=<size>\n"
- " Set size of log ring buffer, may suffix with K or M.\n"
- " -L, --last Dump logs from prior to last reboot\n"
- " -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
- " 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
- " Additionally, 'kernel' for userdebug and eng builds, and\n"
- " 'security' for Device Owner installations.\n"
- " Multiple -b parameters or comma separated list of buffers are\n"
- " allowed. Buffers interleaved.\n"
- " Default -b main,system,crash,kernel.\n"
- " -B, --binary Output the log in binary.\n"
- " -S, --statistics Output statistics.\n"
- " -p, --prune Print prune white and ~black list. Service is specified as\n"
- " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
- " with ~, otherwise weighed for longevity if unadorned. All\n"
- " other pruning activity is oldest first. Special case ~!\n"
- " represents an automatic quicker pruning for the noisiest\n"
- " UID as determined by the current statistics.\n"
- " -P '<list> ...', --prune='<list> ...'\n"
- " Set prune white and ~black list, using same format as\n"
- " listed above. Must be quoted.\n"
- " --pid=<pid> Only prints logs from the given pid.\n"
- // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
- " --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
- " comes first. Improves efficiency of polling by providing\n"
- " an about-to-wrap wakeup.\n");
+ fprintf(stderr, R"init(
+General options:
+ -b, --buffer=<buffer> Request alternate ring buffer(s):
+ main system radio events crash default all
+ Additionally, 'kernel' for userdebug and eng builds, and
+ 'security' for Device Owner installations.
+ Multiple -b parameters or comma separated list of buffers are
+ allowed. Buffers are interleaved.
+ Default -b main,system,crash,kernel.
+ -L, --last Dump logs from prior to last reboot from pstore.
+ -c, --clear Clear (flush) the entire log and exit.
+ if -f is specified, clear the specified file and its related rotated
+ log files instead.
+ if -L is specified, clear pstore log instead.
+ -d Dump the log and then exit (don't block).
+ --pid=<pid> Only print logs from the given pid.
+ --wrap Sleep for 2 hours or when buffer about to wrap whichever
+ comes first. Improves efficiency of polling by providing
+ an about-to-wrap wakeup.
+
+Formatting:
+ -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
+ brief help long process raw tag thread threadtime time
+ Modifying adverbs can be added:
+ color descriptive epoch monotonic printable uid usec UTC year zone
+ Multiple -v parameters or comma separated list of format and format
+ modifiers are allowed.
+ -D, --dividers Print dividers between each log buffer.
+ -B, --binary Output the log in binary.
+
+Outfile files:
+ -f, --file=<file> Log to file instead of stdout.
+ -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
+ -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
+ --id=<id> If the signature <id> for logging to file changes, then clear the
+ associated files and continue.
+
+Logd control:
+ These options send a control message to the logd daemon on device, print its return message if
+ applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
+ -g, --buffer-size Get the size of the ring buffers within logd.
+ -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
+ This can individually control each buffer's size with -b.
+ -S, --statistics Output statistics.
+ --pid can be used to provide pid specific stats.
+ -p, --prune Print prune white and ~black list. Service is specified as UID,
+ UID/PID or /PID. Weighed for quicker pruning if prefix with ~,
+ otherwise weighed for longevity if unadorned. All other pruning
+ activity is oldest first. Special case ~! represents an automatic
+ quicker pruning for the noisiest UID as determined by the current
+ statistics.
+ -P, --prune='<list> ...' Set prune white and ~black list, using same format as listed above.
+ Must be quoted.
+
+Filtering:
+ -s Set default filter to silent. Equivalent to filterspec '*:S'
+ -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
+ an ECMAScript regular expression.
+ -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
+ --regex, but will work on its own.
+ --print This option is only applicable when --regex is set and only useful if
+ --max-count is also provided.
+ With --print, logcat will print all messages even if they do not
+ match the regex. Logcat will quit after printing the max-count number
+ of lines that match the regex.
+ -t <count> Print only the most recent <count> lines (implies -d).
+ -t '<time>' Print the lines since specified time (implies -d).
+ -T <count> Print only the most recent <count> lines (does not imply -d).
+ -T '<time>' Print the lines since specified time (not imply -d).
+ count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
+ 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
+)init");
fprintf(stderr, "\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
@@ -1154,7 +1160,13 @@
struct log_msg log_msg;
int ret = android_logger_list_read(logger_list.get(), &log_msg);
if (!ret) {
- LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
+ LogcatPanic(HELP_FALSE, R"init(read: unexpected EOF!
+
+This means that either logd crashed, or more likely, this instance of logcat was unable to read log
+messages as quickly as they were being produced.
+
+If you have enabled significant logging, look into using the -G option to increase log buffer sizes.
+)init");
}
if (ret < 0) {