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 <yu.ning@intel.com>
(cherry picked from commit 5b1d1c7dfa13b4dca75213581dc8351b841b76c8)
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 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
+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 @@
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 @@
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 @@
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;