init: refactor: add support for doing early coldboot
We don't want to spend time creating devices that are unncessesary
during early (init first-stage) mount. So, refactor the devices code
tha allows us to call into coldboot and has the
- ability to only create devices that are specified by the caller
- ability to stop coldboot cycle when all devices that the caller is
interested in
- ability to run coldboot for a specific syspath
- ability to run ueventd code unmodified
Test: Tested boot on angler, sailfish
Change-Id: Id8f3492380696760414eadc20d624d300c904f8e
Signed-off-by: Sandeep Patil <sspatil@google.com>
diff --git a/init/devices.cpp b/init/devices.cpp
index fbc0359..c7f3efa 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -64,18 +64,6 @@
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;
-};
-
struct perms_ {
char *name;
char *attr;
@@ -879,9 +867,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*))
+template<typename T>
+static inline coldboot_action_t handle_device_fd_with(const T& handle_uevent)
{
char msg[UEVENT_MSG_LEN+2];
int n;
@@ -894,14 +888,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();
@@ -911,9 +909,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
@@ -925,21 +935,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] == '.')
@@ -953,34 +966,39 @@
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());
+ if (d) {
+ return do_coldboot(d.get(), fn);
}
+
+ return COLDBOOT_CONTINUE;
}
-static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
+static coldboot_action_t 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;
+ return COLDBOOT_STOP;
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;
+ return COLDBOOT_STOP;
}
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
@@ -989,6 +1007,8 @@
dev_t dev = makedev(uevent->major, uevent->minor);
mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
mknod(devpath, mode, dev);
+
+ return COLDBOOT_STOP;
}
void early_create_dev(const std::string& syspath, early_device_type dev_type)
@@ -1009,11 +1029,11 @@
write(fd, "add\n", 4);
handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/block/", true);
+ [](uevent* uevent) -> coldboot_action_t {
+ return early_uevent_handler(uevent, "/dev/block/", true);
} :
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/", false);
+ [](uevent* uevent) -> coldboot_action_t {
+ return early_uevent_handler(uevent, "/dev/", false);
});
}
@@ -1026,7 +1046,7 @@
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);
@@ -1043,10 +1063,25 @@
}
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;
}