diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp index 94b43e4f8..e957f6b2e 100644 --- a/fs_mgr/fs_mgr_slotselect.cpp +++ b/fs_mgr/fs_mgr_slotselect.cpp @@ -25,6 +25,9 @@ #include #include +#include +#include +#include #include #include "fs_mgr.h" @@ -77,8 +80,51 @@ static int get_active_slot_suffix_from_misc(struct fstab *fstab, 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 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 @@ static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix, 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 d959798d9..a9deed948 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -123,6 +123,7 @@ int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab); 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 6af237cf9..b3b808b89 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -62,19 +62,7 @@ static const char *firmware_dirs[] = { "/etc/firmware", 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 @@ static void make_device(const char *path, 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 @@ static void make_device(const char *path, 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 @@ out: 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 remove_platform_device(const char *path) } } +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 @@ static char **get_block_device_symlinks(struct uevent *uevent) 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 void handle_firmware_event(uevent* uevent) { } } +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 handle_uevent) { char msg[UEVENT_MSG_LEN+2]; int n; @@ -890,14 +901,18 @@ static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*)) 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 @@ void handle_device_fd() } } - 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 @@ void handle_device_fd() ** 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 @@ static void do_coldboot(DIR *d) 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 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 @@ void device_init() { } 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 8e9ab7d2e..26a064bac 100644 --- a/init/devices.h +++ b/init/devices.h @@ -17,16 +17,37 @@ #ifndef _INIT_DEVICES_H #define _INIT_DEVICES_H +#include #include -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_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 43f601f69..9c1e23bba 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -495,28 +495,48 @@ static void export_kernel_boot_props() { } } -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_ptrdir(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_ptrdir(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 @@ static void set_usb_controller() { } } -/* 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 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 \n + std::vector 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 fstab_file( + fmemopen(static_cast(const_cast(fstab.c_str())), fstab.length(), "r"), fclose); if (!fstab_file) { - PLOG(ERROR) << "Failed to open fstab string as FILE"; - return; - } - std::unique_ptr 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 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-; 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 @@ int main(int argc, char** argv) { 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);