Merge "init: add sigstop option for debugging services from their start"
diff --git a/adb/test_device.py b/adb/test_device.py
index b1ad043..f995be2 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -188,8 +188,6 @@
finally:
self.device.reverse_remove_all()
- # Note: If you run this test when adb connect'd to a physical device over
- # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
def test_forward_reverse_echo(self):
"""Send data through adb forward and read it back via adb reverse"""
forward_port = 12345
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index e60e6be..c2688e9 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -38,6 +38,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/log.h>
#include <cutils/android_reboot.h>
@@ -1096,14 +1097,28 @@
boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total.count());
}
+// Gets the boot time offset. This is useful when Android is running in a
+// container, because the boot_clock is not reset when Android reboots.
+std::chrono::nanoseconds GetBootTimeOffset() {
+ static const int64_t boottime_offset =
+ android::base::GetIntProperty<int64_t>("ro.boot.boottime_offset", 0);
+ return std::chrono::nanoseconds(boottime_offset);
+}
+
+// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME
+// clock.
+android::base::boot_clock::duration GetUptime() {
+ return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset();
+}
+
// Records several metrics related to the time it takes to boot the device,
// including disambiguating boot time on encrypted or non-encrypted devices.
void RecordBootComplete() {
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
- auto time_since_epoch = android::base::boot_clock::now().time_since_epoch();
- auto uptime = std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch);
+ auto uptime_ns = GetUptime();
+ auto uptime_s = std::chrono::duration_cast<std::chrono::seconds>(uptime_ns);
time_t current_time_utc = time(nullptr);
if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
@@ -1128,19 +1143,20 @@
// Log the amount of time elapsed until the device is decrypted, which
// includes the variable amount of time the user takes to enter the
// decryption password.
- boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
+ boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime_s.count());
// Subtract the decryption time to normalize the boot cycle timing.
- std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
+ std::chrono::seconds boot_complete = std::chrono::seconds(uptime_s.count() - record.second);
boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
boot_complete.count());
} else {
- boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", uptime.count());
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
+ uptime_s.count());
}
// Record the total time from device startup to boot complete, regardless of
// encryption state.
- boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime_s.count());
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
@@ -1149,7 +1165,7 @@
const BootloaderTimingMap bootloader_timings = GetBootLoaderTimings();
RecordBootloaderTimings(&boot_event_store, bootloader_timings);
- auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_since_epoch);
+ auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(uptime_ns);
RecordAbsoluteBootTime(&boot_event_store, bootloader_timings, uptime_ms);
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3a3503e..41a3d6b 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -410,12 +410,6 @@
if (!g_cmdline.empty()) {
bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), g_cmdline);
}
- uint32_t header_version_existing =
- reinterpret_cast<boot_img_hdr_v1*>(kdata)->header_version;
- if (g_boot_img_hdr.header_version != header_version_existing) {
- die("header version mismatch, expected: %" PRIu32 " found %" PRIu32 "",
- g_boot_img_hdr.header_version, header_version_existing);
- }
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
diff --git a/init/builtins.cpp b/init/builtins.cpp
index fc74dda..acbeca2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -82,6 +82,7 @@
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
+ LOG(ERROR) << "Rebooting into recovery";
std::string err;
if (!write_bootloader_message(options, &err)) {
return Error() << "Failed to set bootloader message: " << err;
@@ -285,11 +286,8 @@
if (e4crypt_is_native()) {
if (e4crypt_set_directory_policy(args[1].c_str())) {
- const std::vector<std::string> options = {
- "--prompt_and_wipe_data",
- "--reason=set_policy_failed:"s + args[1]};
- reboot_into_recovery(options);
- return Success();
+ return reboot_into_recovery(
+ {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
}
}
return Success();
@@ -493,8 +491,7 @@
/* Setup a wipe via recovery, and reboot into recovery */
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
- reboot_into_recovery(options);
- return Success();
+ return reboot_into_recovery(options);
/* If reboot worked, there is no return. */
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
@@ -987,6 +984,29 @@
return android::base::GetProperty("ro.crypto.type", "") == "file";
}
+static Result<Success> ExecWithRebootOnFailure(const std::string& reboot_reason,
+ const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
+ if (!service) {
+ return Error() << "Could not create exec service";
+ }
+ service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
+ if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
+ if (e4crypt_is_native()) {
+ LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
+ reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ } else {
+ LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
+ }
+ }
+ });
+ if (auto result = service->ExecStart(); !result) {
+ return Error() << "Could not start exec service: " << result.error();
+ }
+ ServiceList::GetInstance().AddService(std::move(service));
+ return Success();
+}
+
static Result<Success> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return Success();
@@ -994,15 +1014,15 @@
if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
return ErrnoError() << "Failed to create " << unencrypted_dir;
}
- std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
- "enablefilecrypto"};
- return do_exec({std::move(exec_args), args.context});
+ return ExecWithRebootOnFailure(
+ "enablefilecrypto_failed",
+ {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto"}, args.context});
}
static Result<Success> do_init_user0(const BuiltinArguments& args) {
- std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
- "init_user0"};
- return do_exec({std::move(exec_args), args.context});
+ return ExecWithRebootOnFailure(
+ "init_user0_failed",
+ {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
}
// Builtin-function-map start
diff --git a/init/service.cpp b/init/service.cpp
index 0227161..03c2cee 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -307,7 +307,7 @@
}
}
-void Service::Reap() {
+void Service::Reap(const siginfo_t& siginfo) {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
KillProcessGroup(SIGKILL);
}
@@ -316,6 +316,10 @@
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
+ for (const auto& f : reap_callbacks_) {
+ f(siginfo);
+ }
+
if (flags_ & SVC_EXEC) UnSetExec();
if (flags_ & SVC_TEMPORARY) return;
diff --git a/init/service.h b/init/service.h
index 9b916c8..cf38f69 100644
--- a/init/service.h
+++ b/init/service.h
@@ -17,6 +17,7 @@
#ifndef _INIT_SERVICE_H
#define _INIT_SERVICE_H
+#include <signal.h>
#include <sys/resource.h>
#include <sys/types.h>
@@ -81,7 +82,7 @@
void Stop();
void Terminate();
void Restart();
- void Reap();
+ void Reap(const siginfo_t& siginfo);
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -89,6 +90,9 @@
is_exec_service_running_ = false;
flags_ &= ~SVC_EXEC;
}
+ void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
+ reap_callbacks_.emplace_back(std::move(callback));
+ }
static bool is_exec_service_running() { return is_exec_service_running_; }
@@ -214,6 +218,8 @@
bool sigstop_ = false;
std::vector<std::string> args_;
+
+ std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
};
class ServiceList {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 3ec76df..0b03324 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -81,16 +81,15 @@
}
}
- auto status = siginfo.si_status;
- if (WIFEXITED(status)) {
- LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
- } else if (WIFSIGNALED(status)) {
- LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
+ if (siginfo.si_code == CLD_EXITED) {
+ LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string;
+ } else {
+ LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
}
if (!service) return true;
- service->Reap();
+ service->Reap(siginfo);
if (service->flags() & SVC_TEMPORARY) {
ServiceList::GetInstance().RemoveService(*service);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5d17698..8209167 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,7 @@
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
+#define AID_LMKD 1069 /* low memory killer daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index f872d0f..619ee34 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -46,6 +46,12 @@
static_libs: ["libunwind_llvm"],
},
},
+
+ // TODO(b/78118944), clang lld link flags do not work with special link
+ // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
+ // boot up in the emulator.
+ use_clang_lld: false,
+
export_include_dirs: ["include"],
local_include_dirs: ["include"],
}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 151e1dc..80711bc 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -68,6 +68,7 @@
#define MEMINFO_PATH "/proc/meminfo"
#define LINE_MAX 128
+/* gid containing AID_SYSTEM required */
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
@@ -455,6 +456,9 @@
return;
}
+ /* gid containing AID_READPROC required */
+ /* CAP_SYS_RESOURCE required */
+ /* CAP_DAC_OVERRIDE required */
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
if (!writefilestring(path, val, false)) {
@@ -496,8 +500,7 @@
soft_limit_mult = 64;
}
- snprintf(path, sizeof(path),
- "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
+ snprintf(path, sizeof(path), MEMCG_SYSFS_PATH "apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
params.uid, params.pid);
snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
@@ -859,6 +862,7 @@
int total;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -882,6 +886,7 @@
char *cp;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -949,6 +954,7 @@
TRACE_KILL_START(pid);
+ /* CAP_KILL required */
r = kill(pid, SIGKILL);
ALOGI(
"Killing '%s' (%d), uid %d, adj %d\n"
@@ -1267,6 +1273,7 @@
int level_idx = (int)level;
const char *levelstr = level_name[level_idx];
+ /* gid containing AID_SYSTEM required */
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
@@ -1478,11 +1485,15 @@
* pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
* in pages.
*/
+ /* CAP_IPC_LOCK required */
if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
ALOGW("mlockall failed %s", strerror(errno));
}
- sched_setscheduler(0, SCHED_FIFO, ¶m);
+ /* CAP_NICE required */
+ if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
+ ALOGW("set SCHED_FIFO failed %s", strerror(errno));
+ }
}
mainloop();
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 3bb84ab..76b6055 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,6 +1,8 @@
service lmkd /system/bin/lmkd
class core
- group root readproc
+ user lmkd
+ group lmkd system readproc
+ capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
critical
socket lmkd seqpacket 0660 system system
writepid /dev/cpuset/system-background/tasks
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1462570..4f008ac 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -34,6 +34,9 @@
# root memory control cgroup, used by lmkd
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg nodev noexec nosuid memory
+ # memory.pressure_level used by lmkd
+ chown root system /dev/memcg/memory.pressure_level
+ chmod 0040 /dev/memcg/memory.pressure_level
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
# cgroup for system_server and surfaceflinger