From 942d4e830b2057177fd2d47c51b788edd6e94398 Mon Sep 17 00:00:00 2001 From: Yu Ning Date: Fri, 8 Jan 2016 17:36:47 +0800 Subject: [PATCH] Support emulator's virtio-blk based SD card Currently, vold only supports MMC (for SD cards) and SCSI (for USB drives) devices. It does not recognize any device whose major number is not one of those used by MMC and SCSI. Unfortunately, virtio-blk is one such device. It is used by the new Android emulator (a.k.a. qemu2, featuring the "ranchu" virtual board) for SD card emulation. In order to make this virtio-blk based SD card device appear in Android and appear as an SD card (rather than a USB drive), changes have to be made to both vold (wherever the device major number is checked) and ranchu's storage configuration. This CL implements former. This is a stop-gap solution for emulator in nyc. A longer term solution in-tune with upstream kernel is in the pipes. Updated from aosp/master version. BUG:27431753 Change-Id: I5014edec73be7c5b565d91542464c82cbe58992c Signed-off-by: Yu Ning (cherry picked from commit 5b1d1c7dfa13b4dca75213581dc8351b841b76c8) --- Disk.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++---- Utils.cpp | 4 ++++ Utils.h | 3 +++ VolumeManager.cpp | 12 ++++++++--- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Disk.cpp b/Disk.cpp index 920edab..ebd55da 100644 --- a/Disk.cpp +++ b/Disk.cpp @@ -65,6 +65,8 @@ static const unsigned int kMajorBlockScsiN = 133; static const unsigned int kMajorBlockScsiO = 134; static const unsigned int kMajorBlockScsiP = 135; static const unsigned int kMajorBlockMmc = 179; +static const unsigned int kMajorBlockExperimentalMin = 240; +static const unsigned int kMajorBlockExperimentalMax = 254; static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"; static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF"; @@ -76,6 +78,33 @@ enum class Table { kGpt, }; +static bool isVirtioBlkDevice(unsigned int major) { + /* + * The new emulator's "ranchu" virtual board no longer includes a goldfish + * MMC-based SD card device; instead, it emulates SD cards with virtio-blk, + * which has been supported by upstream kernel and QEMU for quite a while. + * Unfortunately, the virtio-blk block device driver does not use a fixed + * major number, but relies on the kernel to assign one from a specific + * range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE" + * per Documentation/devices.txt. This is true even for the latest Linux + * kernel (4.4; see init() in drivers/block/virtio_blk.c). + * + * This makes it difficult for vold to detect a virtio-blk based SD card. + * The current solution checks two conditions (both must be met): + * + * a) If the running environment is the emulator; + * b) If the major number is an experimental block device major number (for + * x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number + * 253, but it is safer to match the range than just one value). + * + * Other conditions could be used, too, e.g. the hardware name should be + * "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc. + * But just having a) and b) is enough for now. + */ + return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin + && major <= kMajorBlockExperimentalMax; +} + Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags) : mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated( @@ -197,7 +226,8 @@ status_t Disk::readMetadata() { close(fd); } - switch (major(mDevice)) { + unsigned int majorId = major(mDevice); + switch (majorId) { case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL: @@ -231,7 +261,13 @@ status_t Disk::readMetadata() { break; } default: { - LOG(WARNING) << "Unsupported block major type" << major(mDevice); + if (isVirtioBlkDevice(majorId)) { + LOG(DEBUG) << "Recognized experimental block major ID " << majorId + << " as virtio-blk (emulator's virtual SD card device)"; + mLabel = "Virtual"; + break; + } + LOG(WARNING) << "Unsupported block major type " << majorId; return -ENOTSUP; } } @@ -490,7 +526,8 @@ void Disk::notifyEvent(int event, const std::string& value) { int Disk::getMaxMinors() { // Figure out maximum partition devices supported - switch (major(mDevice)) { + unsigned int majorId = major(mDevice); + switch (majorId) { case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL: @@ -507,9 +544,16 @@ int Disk::getMaxMinors() { } return atoi(tmp.c_str()); } + default: { + if (isVirtioBlkDevice(majorId)) { + // drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is + // 2^4 - 1 = 15 + return 15; + } + } } - LOG(ERROR) << "Unsupported block major type " << major(mDevice); + LOG(ERROR) << "Unsupported block major type " << majorId; return -ENOTSUP; } diff --git a/Utils.cpp b/Utils.cpp index 942945d..9d5f168 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -664,5 +664,9 @@ ScopedDir::~ScopedDir() { } } +bool IsRunningInEmulator() { + return property_get_bool("ro.kernel.qemu", 0); +} + } // namespace vold } // namespace android diff --git a/Utils.h b/Utils.h index cfc8050..d2970e7 100644 --- a/Utils.h +++ b/Utils.h @@ -134,6 +134,9 @@ public: DISALLOW_COPY_AND_ASSIGN(ScopedDir); }; +/* Checks if Android is running in QEMU */ +bool IsRunningInEmulator(); + } // namespace vold } // namespace android diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 9304630..5cc60a1 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -91,6 +91,8 @@ const char *VolumeManager::LOOPDIR = "/mnt/obb"; static const char* kUserMountPath = "/mnt/user"; static const unsigned int kMajorBlockMmc = 179; +static const unsigned int kMajorBlockExperimentalMin = 240; +static const unsigned int kMajorBlockExperimentalMax = 254; /* writes superblock at end of file or device given by name */ static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) { @@ -296,10 +298,14 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { case NetlinkEvent::Action::kAdd: { for (auto source : mDiskSources) { if (source->matches(eventPath)) { - // For now, assume that MMC devices are SD, and that - // everything else is USB + // For now, assume that MMC and virtio-blk (the latter is + // emulator-specific; see Disk.cpp for details) devices are SD, + // and that everything else is USB int flags = source->getFlags(); - if (major == kMajorBlockMmc) { + if (major == kMajorBlockMmc + || (android::vold::IsRunningInEmulator() + && major >= (int) kMajorBlockExperimentalMin + && major <= (int) kMajorBlockExperimentalMax)) { flags |= android::vold::Disk::Flags::kSd; } else { flags |= android::vold::Disk::Flags::kUsb;