diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 4ca5b8f0e..7f83037ae 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -140,11 +140,43 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - devices->erase(iter); + // Remove the partition from the list of partitions we're waiting for. + // + // Partitions that we're waiting for here are expected to be on the boot + // device, so only remove from the list if they're on the boot device. + // This prevents us from being confused if there are multiple disks (some + // perhaps connected via USB) that have matching partition names. + // + // ...but... + // + // Some products (especialy emulators) don't seem to set up boot_devices + // or possibly not all the partitions that we need to wait for are on the + // specified boot device. Thus, only require partitions to be on the boot + // device in "strict" mode, which should be used on newer systems. + if (device_handler_->IsBootDevice(uevent) || !device_handler_->IsBootDeviceStrict()) { + devices->erase(iter); + } + device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } +// Wait for partitions that are expected to be on the "boot device" to initialize. +// +// Wait (for up to 10 seconds) for partitions passed in `devices` to show up. +// All block devices found while waiting will be initialized, which includes +// creating symlinks for them in /dev/block. Once all `devices` are found we'll +// return success (true). If any devices aren't found we'll return failure +// (false). As devices are found they will be removed from `devices`. +// +// The contents of `devices` is the names of the partitions. This can be: +// - The `partition_name` reported by a uevent, or the final component in the +// `path` reported by a uevent if the `partition_name` is blank. +// - The result of DeviceHandler::GetPartitionNameForDevice() on the +// `device_name` reported by a uevent. +// +// NOTE: on newer systems partitions _must_ be on the "boot device". See +// comments inside HandleUevent(). bool BlockDevInitializer::InitDevices(std::set devices) { auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction { return HandleUevent(uevent, &devices); diff --git a/init/devices.cpp b/init/devices.cpp index 0b1e13dba..4de1e2030 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -224,6 +224,17 @@ BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path return info; } +bool DeviceHandler::IsBootDeviceStrict() const { + // When using the newer "boot_part_uuid" to specify the boot device then + // we require all core system partitions to be on the boot device. + return !boot_part_uuid_.empty(); +} + +bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { + auto device = GetBlockDeviceInfo(uevent.path); + return device.is_boot_device; +} + std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index cac52bc17..8b6cf6cb1 100644 --- a/init/devices.h +++ b/init/devices.h @@ -141,6 +141,8 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); + bool IsBootDeviceStrict() const; + bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override;