android 6.0sd卡内部存储 & 外部存储
来源:互联网 发布:unity3d 性能测试工具 编辑:程序博客网 时间:2024/06/06 03:41
android6.0 把sd卡可以设置成内部存储。
一、fatab文件匹配
我们先来看下,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<VolumeManager::DiskSource>( 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>& 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<std::mutex> 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<android::vold::Disk>(disk)); break; } } break; }
有设备是主要是Aciton:kAdd,这个函数先创建了设备,根据major和minor。
从mDiskSources看是否有满足的DiskSource,然后获取其flags,然后新建Disk,调用create函数。
三、Disk创建
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<std::string> cmd; cmd.push_back(kSgdiskPath);//"/system/bin/sgdisk"; cmd.push_back("--android-dump"); cmd.push_back(mDevPath); std::vector<std::string> 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-40F8B7609491PART 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<VolumeBase>(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 mbr05-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<VolumeBase>(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<std::string> 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<std::string> 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<std::string>& args, std::vector<std::string>& 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<std::string> 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<std::string> 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。
- android 6.0sd卡内部存储 & 外部存储
- android 存储 内部存储 外部存储 SD卡
- 内部及外部SD卡存储空间存储
- Android外部sd卡存储
- Android 数据存储---外部存储(SD卡)
- Android Environment.getExternalStorageDirectory() 获取的是内部存储还是外部存储?若无SD卡,就用内部。
- 数据存储详解(二)---->File存储:内部存储 -Cache和外部存储-SD卡
- Android--手机外部SD卡存储
- Android五大存储---外部存储(SD卡)
- Android 数据存储-------外部存储(SD卡) External Storage
- Android的内部存储和外部存储
- Android 内部存储和外部存储
- Android的内部存储和外部存储
- Android中内部存储和外部存储
- android中的内部存储与外部存储
- android获得内部存储/外部存储路径
- Android的内部存储与外部存储
- Android内部存储和外部存储
- Easy-题目7:100. Same Tree
- [JavaScript] 8.JS BOM对象
- IOS 关于取消延迟执行函数的种种。performSelector与cancelPreviousPerformRequestsWithTarget
- Django 进阶(装饰器,Mixin,信号,模式)
- Android APP的字体设置
- android 6.0sd卡内部存储 & 外部存储
- tomcat+websocket实现
- PID2 / 开心的金明
- leetcode 11
- 出题&题解
- ViewPager+Fragment+RadioGroup实现页面联动\点击切换
- 手写一个SqlHelper
- spark sql版本的单词统计代码
- <crtdbg.h> 的作用