Merge "Add /mnt/vendor rw mount point for vendor partitions."
diff --git a/init/README.md b/init/README.md
index 59ddd77..b14521c 100644
--- a/init/README.md
+++ b/init/README.md
@@ -282,6 +282,10 @@
"shutdown critical" will be killed. When the service tagged with "shutdown critical"
is not running when shut down starts, it will be started.
+`sigstop`
+> Send SIGSTOP to the service immediately before exec is called. This is intended for debugging.
+ See the below section on debugging for how this can be used.
+
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
@@ -708,23 +712,39 @@
Debugging init
--------------
-By default, programs executed by init will drop stdout and stderr into
-/dev/null. To help with debugging, you can execute your program via the
-Android program logwrapper. This will redirect stdout/stderr into the
-Android logging system (accessed via logcat).
+Launching init services without init is not recommended as init sets up a significant amount of
+environment (user, groups, security label, capabilities, etc) that is hard to replicate manually.
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
+If it is required to debug a service from its very start, the `sigstop` service option is added.
+This option will send SIGSTOP to a service immediately before calling exec. This gives a window
+where developers can attach a debugger, strace, etc before continuing the service with SIGCONT.
-For quicker turnaround when working on init itself, use:
+This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
- mm -j &&
- m ramdisk-nodeps &&
- m bootimage-nodeps &&
- adb reboot bootloader &&
- fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+Below is an example of dynamically debugging logd via the above:
-Alternatively, use the emulator:
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ gdbclient.py -p 4343
+ b main
+ c
+ c
+ c
+ > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427
- emulator -partition-size 1024 \
- -verbose -show-kernel -no-window
+Below is an example of doing the same but with strace
+
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ strace -p 4343
+
+ (From a different shell)
+ kill -SIGCONT 4343
+
+ > strace runs
diff --git a/init/init.cpp b/init/init.cpp
index 40b7e87..0d5690b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -238,6 +238,10 @@
static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
// clang-format off
static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+ {"sigstop_on", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(true); return Success(); }}},
+ {"sigstop_off", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(false); return Success(); }}},
{"start", {ControlTarget::SERVICE, DoControlStart}},
{"stop", {ControlTarget::SERVICE, DoControlStop}},
{"restart", {ControlTarget::SERVICE, DoControlRestart}},
diff --git a/init/service.cpp b/init/service.cpp
index f9986c5..03c2cee 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,7 +155,7 @@
}
}
-static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
+static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
std::vector<std::string> expanded_args;
std::vector<char*> c_strings;
@@ -169,6 +169,10 @@
}
c_strings.push_back(nullptr);
+ if (sigstop) {
+ kill(getpid(), SIGSTOP);
+ }
+
return execv(c_strings[0], c_strings.data()) == 0;
}
@@ -582,6 +586,11 @@
return Success();
}
+Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) {
+ sigstop_ = true;
+ return Success();
+}
+
Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
environment_vars_.emplace_back(args[1], args[2]);
return Success();
@@ -704,6 +713,7 @@
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"shutdown", {1, 1, &Service::ParseShutdown}},
+ {"sigstop", {0, 0, &Service::ParseSigstop}},
{"socket", {3, 6, &Service::ParseSocket}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
@@ -862,7 +872,7 @@
// priority. Aborts on failure.
SetProcessAttributes();
- if (!ExpandArgsAndExecv(args_)) {
+ if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
diff --git a/init/service.h b/init/service.h
index bcf1943..cf38f69 100644
--- a/init/service.h
+++ b/init/service.h
@@ -118,6 +118,7 @@
bool is_override() const { return override_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
unsigned long start_order() const { return start_order_; }
+ void set_sigstop(bool value) { sigstop_ = value; }
const std::vector<std::string>& args() const { return args_; }
private:
@@ -153,6 +154,7 @@
Result<Success> ParseSeclabel(const std::vector<std::string>& args);
Result<Success> ParseSetenv(const std::vector<std::string>& args);
Result<Success> ParseShutdown(const std::vector<std::string>& args);
+ Result<Success> ParseSigstop(const std::vector<std::string>& args);
Result<Success> ParseSocket(const std::vector<std::string>& args);
Result<Success> ParseFile(const std::vector<std::string>& args);
Result<Success> ParseUser(const std::vector<std::string>& args);
@@ -213,6 +215,8 @@
std::vector<std::pair<int, rlimit>> rlimits_;
+ bool sigstop_ = false;
+
std::vector<std::string> args_;
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
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/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 2d64144..319b4c7 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -31,6 +31,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