summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Disk.cpp52
-rw-r--r--Utils.cpp4
-rw-r--r--Utils.h3
-rw-r--r--VolumeManager.cpp12
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;