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;