android6.0 把sd卡可以设置成内部存储。
我们先来看下,vold的main函数:
main函数在创建了VolumeManager后,调用了如下函数:
if (process_config(vm)) {
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
我们再来看看这个函数:
static int process_config(VolumeManager *vm) {
std::string path(android::vold::DefaultFstabPath());
fstab = fs_mgr_read_fstab(path.c_str());//获取fstab文件
if (!fstab) {
PLOG(ERROR) << "Failed to open default fstab " << path;
return -1;
}
/* Loop through entries looking for ones that vold manages */
bool has_adoptable = false;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {//fastab文件满足vold的项
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
continue;
}
std::string sysPattern(fstab->recs[i].blk_device);
std::string nickname(fstab->recs[i].label);
int flags = 0;
if (fs_mgr_is_encryptable(&fstab->recs[i])) {
flags |= android::vold::Disk::Flags::kAdoptable;
has_adoptable = true;
}
if (fs_mgr_is_noemulatedsd(&fstab->recs[i])
|| property_get_bool("vold.debug.default_primary", false)) {
flags |= android::vold::Disk::Flags::kDefaultPrimary;
}
vm->addDiskSource(std::shared_ptr(
new VolumeManager::DiskSource(sysPattern, nickname, flags)));
}
}
property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
return 0;
}
这个函数先获取fstab文件,分析fstab文件,创建了DiskSource对象。然后调用了VolumeManager的addDiskSource函数:
void VolumeManager::addDiskSource(const std::shared_ptr& diskSource) {
mDiskSources.push_back(diskSource);
}
保存在mDiskSources中。
下面我们来看下fstab文件,下面文件有机箱是voldmanaged的,就是上面函数满足的条件
/dev/block/platform/comip-mmc.1/by-name/system /system ext4 ro,barrier=1 wait
/dev/block/platform/comip-mmc.1/by-name/cache /cache ext4 noatime,nosuid,nodev,barrier=1,data=ordered wait,check
/dev/block/platform/comip-mmc.1/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,data=ordered,noauto_da_alloc resize,wait,check,encryptable=footer
#/dev/block/platform/comip-mmc.1/by-name/amt /amt ext4 rw wait
/devices/platform/comip-mmc.0/mmc_host/mmc1/* auto vfat defaults voldmanaged=sdcard1:auto,encryptable=false
/devices/a0400000.usb_hcd/usb1/* auto vfat defaults voldmanaged=usbotg:auto,noemulatedsd
/dev/block/mmcblk1p1 /sdcard vfat defaults recoveryonly
/dev/block/platform/comip-mmc.1/by-name/kernel /kernel emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/ramdisk /boot emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/ramdisk_recovery /recovery emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/ramdisk_amt1 /ramdisk_amt1 emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/ramdisk_amt3 /ramdisk_amt3 emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/kernel_recovery /kernel_recovery emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/logo /logo emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/misc /misc emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/fota /fota emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/modemarm /modemarm emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/modemdsp /modemdsp emmc defaults defaults
/dev/block/mmcblk0boot0 /uboot emmc defaults defaults
/dev/block/platform/comip-mmc.1/by-name/lcboot /lcboot emmc defaults defaults
/dev/block/zram0 none swap defaults zramsize=268435456
然后就是有检测到设备,到下面函数:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
}
}
调用了VolumeManager的handleBlockEvent函数:
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
std::lock_guard lock(mLock);
if (mDebug) {
LOG(VERBOSE) << "----------------";
LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
evt->dump();
}
std::string eventPath(evt->findParam("DEVPATH"));
std::string devType(evt->findParam("DEVTYPE"));
if (devType != "disk") return;
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
dev_t device = makedev(major, minor);//创建设备
switch (evt->getAction()) {
case NetlinkEvent::Action::kAdd: {
for (auto source : mDiskSources) {
if (source->matches(eventPath)) {//之前的mDiskSources就是用来匹配的
// For now, assume that MMC devices are SD, and that
// everything else is USB
int flags = source->getFlags();//从source获取flags
if (major == kMajorBlockMmc) {
flags |= android::vold::Disk::Flags::kSd;
} else {
flags |= android::vold::Disk::Flags::kUsb;
}
auto disk = new android::vold::Disk(eventPath, device,
source->getNickname(), flags);//新建Disk
disk->create();
mDisks.push_back(std::shared_ptr(disk));
break;
}
}
break;
}
有设备是主要是Aciton:kAdd,这个函数先创建了设备,根据major和minor。
从mDiskSources看是否有满足的DiskSource,然后获取其flags,然后新建Disk,调用create函数。
Disk::Disk(const std::string& eventPath, dev_t device,
const std::string& nickname, int flags) :
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
false), mJustPartitioned(false) {
mId = StringPrintf("disk:%u,%u", major(device), minor(device));
mEventPath = eventPath;
mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());//设备地址
CreateDeviceNode(mDevPath, mDevice);
}
我们再来看看CreateDeviceNode函数:
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
const char* cpath = path.c_str();
status_t res = 0;
char* secontext = nullptr;
if (sehandle) {
if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
setfscreatecon(secontext);
}
}
mode_t mode = 0660 | S_IFBLK;
if (mknod(cpath, mode, dev) < 0) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to create device node for " << major(dev)
<< ":" << minor(dev) << " at " << path;
res = -errno;
}
}
if (secontext) {
setfscreatecon(nullptr);
freecon(secontext);
}
return res;
}
这个函数里面,其中最重要的就是mknod,把device的设备放在了dev,这个设备目录。等于创建了设备目录,等于我们就有了dev/block/vold/disk:179,128这个目录。
我们再来看,create函数
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
readMetadata();
readPartitions();
return OK;
}
readMetadata主要就是获取信息,然后和MountService通信,和MountService通信我们这里不说了,之前的博客都分析过很多。
status_t Disk::readMetadata() {
mSize = -1;
mLabel.clear();
int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);
if (fd != -1) {
if (ioctl(fd, BLKGETSIZE64, &mSize)) {
mSize = -1;
}
close(fd);
}
switch (major(mDevice)) {
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {
std::string path(mSysPath + "/device/vendor");
std::string tmp;
if (!ReadFileToString(path, &tmp)) {
PLOG(WARNING) << "Failed to read vendor from " << path;
return -errno;
}
mLabel = tmp;
break;
}
case kMajorBlockMmc: {
std::string path(mSysPath + "/device/manfid");
std::string tmp;
if (!ReadFileToString(path, &tmp)) {
PLOG(WARNING) << "Failed to read manufacturer from " << path;
return -errno;
}
uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);
// Our goal here is to give the user a meaningful label, ideally
// matching whatever is silk-screened on the card. To reduce
// user confusion, this list doesn't contain white-label manfid.
switch (manfid) {
case 0x000003: mLabel = "SanDisk"; break;
case 0x00001b: mLabel = "Samsung"; break;
case 0x000028: mLabel = "Lexar"; break;
case 0x000074: mLabel = "Transcend"; break;
}
break;
}
default: {
LOG(WARNING) << "Unsupported block major type" << major(mDevice);
return -ENOTSUP;
}
}
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRId64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
return OK;
}
我们主要看readPartitions这个函数:
status_t Disk::readPartitions() {
int8_t maxMinors = getMaxMinors();
if (maxMinors < 0) {
return -ENOTSUP;
}
destroyAllVolumes();
// Parse partition table
std::vector cmd;
cmd.push_back(kSgdiskPath);//"/system/bin/sgdisk";
cmd.push_back("--android-dump");
cmd.push_back(mDevPath);
std::vector output;
status_t res = ForkExecvp(cmd, output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
notifyEvent(ResponseCode::DiskScanned);
mJustPartitioned = false;
return res;
}
Table table = Table::kUnknown;
bool foundParts = false;
for (auto line : output) {
char* cline = (char*) line.c_str();
char* token = strtok(cline, kSgdiskToken);
if (token == nullptr) continue;
if (!strcmp(token, "DISK")) {
const char* type = strtok(nullptr, kSgdiskToken);
if (!strcmp(type, "mbr")) {//mbr
table = Table::kMbr;
} else if (!strcmp(type, "gpt")) {
table = Table::kGpt;//gpt
}
} else if (!strcmp(token, "PART")) {
foundParts = true;
int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);
if (i <= 0 || i > maxMinors) {
LOG(WARNING) << mId << " is ignoring partition " << i
<< " beyond max supported devices";
continue;
}
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);//和之前Disk一样根据disk的device的major和minor创建volume的device
if (table == Table::kMbr) {
const char* type = strtok(nullptr, kSgdiskToken);
switch (strtol(type, nullptr, 16)) {
case 0x06: // FAT16
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
case 0x0e: // W95 FAT16 (LBA)
createPublicVolume(partDevice);
break;
}
} else if (table == Table::kGpt) {//下面的就是gpt
const char* typeGuid = strtok(nullptr, kSgdiskToken);
const char* partGuid = strtok(nullptr, kSgdiskToken);
if (!strcasecmp(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
} else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {//expand就是privatevolume
createPrivateVolume(partDevice, partGuid);
}
}
}
}
// Ugly last ditch effort, treat entire disk as partition
if (table == Table::kUnknown || !foundParts) {
LOG(WARNING) << mId << " has unknown partition table; trying entire device";
std::string fsType;
std::string unused;
if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {
createPublicVolume(mDevice);
} else {
LOG(WARNING) << mId << " failed to identify, giving up";
}
}
notifyEvent(ResponseCode::DiskScanned);
mJustPartitioned = false;
return OK;
}
上面函数,就是根据sgdisk这个工具,输入命令,去读取输出,相应创建privatevolume还是PublicVolume
下面我们结合sgdisk的命令输出来看:
DISK gpt D25EA824-98CC-4390-899F-40F8B7609491
PART 1 193D1EA4-B3CA-11E4-B075-10604B889DCF 7F3EE593-E357-196F-7707-FA295A508E64 android_expand
这里是内部存储sgdisk的输出。这里disk是gpt。
我们再来看看createPrivatevolume,
void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
std::string normalizedGuid;
if (NormalizeHex(partGuid, normalizedGuid)) {
LOG(WARNING) << "Invalid GUID " << partGuid;
return;
}
std::string keyRaw;
if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) {
PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid;
return;
}
LOG(DEBUG) << "Found key for GUID " << normalizedGuid;
auto vol = std::shared_ptr(new PrivateVolume(device, keyRaw));
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
vol->format("auto");
vol->destroy();
vol->setSilent(false);
}
mVolumes.push_back(vol);
vol->setDiskId(getId());
vol->setPartGuid(partGuid);
vol->create();
}
再来看Privatevolume的构造函数
PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) :
VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {
setId(StringPrintf("private:%u,%u", major(device), minor(device)));
mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
}
doFormat函数就是将sd卡格式化,比如格式化成ext4的。
status_t PrivateVolume::doFormat(const std::string& fsType) {
std::string resolvedFsType = fsType;
if (fsType == "auto") {
// For now, assume that all MMC devices are flash-based SD cards, and
// give everyone else ext4 because sysfs rotational isn't reliable.
if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) {
resolvedFsType = "f2fs";
} else {
resolvedFsType = "ext4";
}
LOG(DEBUG) << "Resolved auto to " << resolvedFsType;
}
if (resolvedFsType == "ext4") {
// TODO: change reported mountpoint once we have better selinux support
if (ext4::Format(mDmDevPath, 0, "/data")) {
PLOG(ERROR) << getId() << " failed to format";
return -EIO;
}
} else if (resolvedFsType == "f2fs") {
if (f2fs::Format(mDmDevPath)) {
PLOG(ERROR) << getId() << " failed to format";
return -EIO;
}
} else {
LOG(ERROR) << getId() << " unsupported filesystem " << fsType;
return -EINVAL;
}
return OK;
}
doCreate函数,就会调用CreateDeviceNode,来创建dev设备,就是将device绑在dev目录下。后面一些函数没有深入研究
status_t PrivateVolume::doCreate() {
if (CreateDeviceNode(mRawDevPath, mRawDevice)) {
return -EIO;
}
// Recover from stale vold by tearing down any old mappings
cryptfs_revert_ext_volume(getId().c_str());
// TODO: figure out better SELinux labels for private volumes
unsigned char* key = (unsigned char*) mKeyRaw.data();
char crypto_blkdev[MAXPATHLEN];
int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(),
key, mKeyRaw.size(), crypto_blkdev);
mDmDevPath = crypto_blkdev;
if (res != 0) {
PLOG(ERROR) << getId() << " failed to setup cryptfs";
return -EIO;
}
return OK;
}
之后就是mount了,内部存储是将dev文件mount到mnt/expand下。
status_t PrivateVolume::doMount() {
if (readMetadata()) {
LOG(ERROR) << getId() << " failed to read metadata";
return -EIO;
}
mPath = StringPrintf("/mnt/expand/%s", mFsUuid.c_str());
setPath(mPath);
if (PrepareDir(mPath, 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create mount point " << mPath;
return -EIO;
}
if (mFsType == "ext4") {
int res = ext4::Check(mDmDevPath, mPath);
if (res == 0 || res == 1) {
LOG(DEBUG) << getId() << " passed filesystem check";
} else {
PLOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
if (ext4::Mount(mDmDevPath, mPath, false, false, true)) {
PLOG(ERROR) << getId() << " failed to mount";
return -EIO;
}
}
外部存储sgdisk的输出命令如下:
05-30 20:23:45.358 175 177 V vold : DISK mbr
05-30 20:23:45.359 175 177 V vold : PART 1 c
我们再来看Disk的readPartitions函数的其中一段
Table table = Table::kUnknown;
bool foundParts = false;
for (auto line : output) {
char* cline = (char*) line.c_str();
char* token = strtok(cline, kSgdiskToken);
if (token == nullptr) continue;
if (!strcmp(token, "DISK")) {
const char* type = strtok(nullptr, kSgdiskToken);
if (!strcmp(type, "mbr")) {//mbr
table = Table::kMbr;
} else if (!strcmp(type, "gpt")) {
table = Table::kGpt;
}
} else if (!strcmp(token, "PART")) {
foundParts = true;
int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);
if (i <= 0 || i > maxMinors) {
LOG(WARNING) << mId << " is ignoring partition " << i
<< " beyond max supported devices";
continue;
}
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
if (table == Table::kMbr) {
const char* type = strtok(nullptr, kSgdiskToken);
switch (strtol(type, nullptr, 16)) {
case 0x06: // FAT16
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
case 0x0e: // W95 FAT16 (LBA)
createPublicVolume(partDevice);// 是mbr的就直接调用createPublicVolume函数
break;
}
} else if (table == Table::kGpt) {
const char* typeGuid = strtok(nullptr, kSgdiskToken);
const char* partGuid = strtok(nullptr, kSgdiskToken);
if (!strcasecmp(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
} else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {
createPrivateVolume(partDevice, partGuid);
}
}
}
}
然后我们看createPublicVolume函数:
void Disk::createPublicVolume(dev_t device) {
auto vol = std::shared_ptr(new PublicVolume(device));
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
vol->format("auto");
vol->destroy();
vol->setSilent(false);
}
mVolumes.push_back(vol);
vol->setDiskId(getId());
vol->create();
}
构造函数
PublicVolume::PublicVolume(dev_t device) :
VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {
setId(StringPrintf("public:%u,%u", major(device), minor(device)));
mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
}
创建设备
status_t PublicVolume::doCreate() {
return CreateDeviceNode(mDevPath, mDevice);
}
格式化
status_t PublicVolume::doFormat(const std::string& fsType) {
if (fsType == "vfat" || fsType == "auto") {
if (WipeBlockDevice(mDevPath) != OK) {
LOG(WARNING) << getId() << " failed to wipe";
}
if (vfat::Format(mDevPath, 0)) {
LOG(ERROR) << getId() << " failed to format";
return -errno;
}
} else {
LOG(ERROR) << "Unsupported filesystem " << fsType;
return -EINVAL;
}
return OK;
}
我们再来看下mount的第一步流程:
status_t PublicVolume::doMount() {
// TODO: expand to support mounting other filesystems
readMetadata();
if (mFsType != "vfat") {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
if (vfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
doMount函数中显示调用了readMetadata函数:
status_t PublicVolume::readMetadata() {
status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
return res;
}
我们可以知道通过ReadMetadataUntrusted函数来获取mFsType, mFsUuid, mFsLabel3个值。
我们再来看下ReadMetadataUntrusted函数:
status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel) {
return readMetadata(path, fsType, fsUuid, fsLabel, true);
}
readMetadata函数,我们通过blkid进程来获取这些值。
static status_t readMetadata(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel, bool untrusted) {
fsType.clear();
fsUuid.clear();
fsLabel.clear();
std::vector cmd;
cmd.push_back(kBlkidPath);//"/system/bin/blkid"
cmd.push_back("-c");
cmd.push_back("/dev/null");
cmd.push_back("-s");
cmd.push_back("TYPE");
cmd.push_back("-s");
cmd.push_back("UUID");
cmd.push_back("-s");
cmd.push_back("LABEL");
cmd.push_back(path);
std::vector output;
status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
if (res != OK) {
LOG(WARNING) << "blkid failed to identify " << path;
return res;
}
char value[128];
for (auto line : output) {
// Extract values from blkid output, if defined
const char* cline = line.c_str();
char* start = strstr(cline, "TYPE=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsType = value;
}
start = strstr(cline, "UUID=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsUuid = value;
}
start = strstr(cline, "LABEL=");
if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
fsLabel = value;
}
}
return OK;
}
在这里我们再看下ForkExecvp函数:
status_t ForkExecvp(const std::vector& args,
std::vector& output, security_context_t context) {
std::string cmd;
for (size_t i = 0; i < args.size(); i++) {
cmd += args[i] + " ";
if (i == 0) {
LOG(VERBOSE) << args[i];//输入的命令打印
} else {
LOG(VERBOSE) << " " << args[i];
}
}
output.clear();
if (setexeccon(context)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
FILE* fp = popen(cmd.c_str(), "r");//通过popen函数
if (setexeccon(nullptr)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
if (!fp) {
PLOG(ERROR) << "Failed to popen " << cmd;
return -errno;
}
char line[1024];
while (fgets(line, sizeof(line), fp) != nullptr) {//获取输出
LOG(VERBOSE) << line;
output.push_back(std::string(line));
}
if (pclose(fp) != 0) {
PLOG(ERROR) << "Failed to pclose " << cmd;
return -errno;
}
return OK;
}
上面通过popen来执行blkid进程获取信息,popen函数先fork,然后调用exec执行cmd,并且返回一个标准I/O的文件指针。
当type是r,文件指针连接到cmd的标准输出。如果是w,文件指针连接到cmd的标准输入。
最后pclose是关闭标准I/O流。
流程我们看完了,但是disk在调用readPartitions函数时,根据sgdisk工具的输出,来决定是创建外部存储还是内部存储。但是这个sgdisk的输出又是谁来决定的,我们可以看下下面两个函数:
第一个就是格式化为内部存储:
status_t Disk::partitionPrivate() {
return partitionMixed(0);
}
partitionMixed函数同样调用了sgdisk工具
status_t Disk::partitionMixed(int8_t ratio) {
int res;
destroyAllVolumes();
mJustPartitioned = true;
// First nuke any existing partition table
std::vector cmd;
cmd.push_back(kSgdiskPath);
cmd.push_back("--zap-all");
cmd.push_back(mDevPath);
// Zap sometimes returns an error when it actually succeeded, so
// just log as warning and keep rolling forward.
if ((res = ForkExecvp(cmd)) != 0) {
LOG(WARNING) << "Failed to zap; status " << res;
}
// We've had some success above, so generate both the private partition
// GUID and encryption key and persist them.
std::string partGuidRaw;
std::string keyRaw;
if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {
LOG(ERROR) << "Failed to generate GUID or key";
return -EIO;
}
std::string partGuid;
StrToHex(partGuidRaw, partGuid);
if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) {
LOG(ERROR) << "Failed to persist key";
return -EIO;
} else {
LOG(DEBUG) << "Persisted key for GUID " << partGuid;
}
// Now let's build the new GPT table. We heavily rely on sgdisk to
// force optimal alignment on the created partitions.
cmd.clear();
cmd.push_back(kSgdiskPath);
// If requested, create a public partition first. Mixed-mode partitioning
// like this is an experimental feature.
if (ratio > 0) {
if (ratio < 10 || ratio > 90) {
LOG(ERROR) << "Mixed partition ratio must be between 10-90%";
return -EINVAL;
}
uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024;
cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb));
cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData));
cmd.push_back("--change-name=0:shared");
}
// Define a metadata partition which is designed for future use; there
// should only be one of these per physical device, even if there are
// multiple private volumes.
/*cmd.push_back("--new=0:0:+16M");// 这段代码被我注释了,因为在我们的手机上有错,不知为何
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta));
cmd.push_back("--change-name=0:android_meta");*/
// Define a single private partition filling the rest of disk.
cmd.push_back("--new=0:0:-0");
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand));
cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));
cmd.push_back("--change-name=0:android_expand");// 这里就是对应我们的PART1 的expand
cmd.push_back(mDevPath);
if ((res = ForkExecvp(cmd)) != 0) {
LOG(ERROR) << "Failed to partition; status " << res;
return res;
}
return OK;
}
原来的意思是先创建一个16M的part1为android_meta, 剩余的存储创建了part2,为android_expand。但是这样后面,在创建part2的时候createPrivatevolume,最后在Privatevolume的docreate函数出错了,没有找到设备。所以将part1,这段代码注释后是可以的。
第二个函数partitionPublic函数如下,变成外部存储。类似上面
status_t Disk::partitionPublic() {
int res;
// TODO: improve this code
destroyAllVolumes();
mJustPartitioned = true;
// First nuke any existing partition table
std::vector cmd;
cmd.push_back(kSgdiskPath);
cmd.push_back("--zap-all");
cmd.push_back(mDevPath);
// Zap sometimes returns an error when it actually succeeded, so
// just log as warning and keep rolling forward.
if ((res = ForkExecvp(cmd)) != 0) {
LOG(WARNING) << "Failed to zap; status " << res;
}
struct disk_info dinfo;
memset(&dinfo, 0, sizeof(dinfo));
if (!(dinfo.part_lst = (struct part_info *) malloc(
MAX_NUM_PARTS * sizeof(struct part_info)))) {
return -1;
}
memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
dinfo.device = strdup(mDevPath.c_str());
dinfo.scheme = PART_SCHEME_MBR;
dinfo.sect_size = 512;
dinfo.skip_lba = 2048;
dinfo.num_lba = 0;
dinfo.num_parts = 1;
struct part_info *pinfo = &dinfo.part_lst[0];
pinfo->name = strdup("android_sdcard");
pinfo->flags |= PART_ACTIVE_FLAG;
pinfo->type = PC_PART_TYPE_FAT32;
pinfo->len_kb = -1;
int rc = apply_disk_config(&dinfo, 0);
if (rc) {
LOG(ERROR) << "Failed to apply disk configuration: " << rc;
goto out;
}
out:
free(pinfo->name);
free(dinfo.device);
free(dinfo.part_lst);
return rc;
}
而在调用这两个函数之后,应该是将某些数据烧录到了sd卡中。
因为下次开机,vold在Disk的readPartitions函数根据sgdisk工具输出,就自动识别出是publicvolume还是Privatevolume。