vold有一个调试的功能,叫做vdc,对应源码中的vdc.c或vdc.cpp。
如果研究vdc的源码会发现安卓的变迁史。
Android 4.2-5.1
checkout分支jb-release。
vold支持的命令在CommandListener中定义。
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
}
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
int rc = 0;
if (!strcmp(argv[1], "list")) {
return vm->listVolumes(cli);
} else if (!strcmp(argv[1], "debug")) {
if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug ", false);
return 0;
}
vm->setDebug(!strcmp(argv[2], "on") ? true : false);
} else if (!strcmp(argv[1], "mount")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount ", false);
return 0;
}
rc = vm->mountVolume(argv[2]);
} else if (!strcmp(argv[1], "unmount")) {
if (argc < 3 || argc > 4 ||
((argc == 4 && strcmp(argv[3], "force")) &&
(argc == 4 && strcmp(argv[3], "force_and_revert")))) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount [force|force_and_revert]", false);
return 0;
}
bool force = false;
bool revert = false;
if (argc >= 4 && !strcmp(argv[3], "force")) {
force = true;
} else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
force = true;
revert = true;
}
rc = vm->unmountVolume(argv[2], force, revert);
//...省略一些无用的 } else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
}
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
} else {
int erno = errno;
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "volume operation failed", true);
}
return 0;
}
根据上面的代码可以整理vdc的存储命令方法:
1、vdc volume list
用于查看volume。
2、vdc volume mount sdcard
用于挂载sdcard,这里的sdcard是最难确定的。
3、vdc volume unmount sdcard force
用于卸载sdcard,这里的sdcard是最难确定的。
Android 6.0/7.0/8.0
git checkout marshmallow-release
根据commit来看,android 6.0对vold的volume命令进行了大幅重写,reset和shutdown都是这时候加入的。
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
}
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<:mutex> lock(vm->getLock());
// TODO: tease out methods not directly related to volumes
std::string cmd(argv[1]);
if (cmd == "reset") {
return sendGenericOkFail(cli, vm->reset());
} else if (cmd == "shutdown") {
return sendGenericOkFail(cli, vm->shutdown());
} else if (cmd == "debug") {
return sendGenericOkFail(cli, vm->setDebug(true));
} else if (cmd == "partition" && argc > 3) {
// partition [diskId] [public|private|mixed] [ratio] std::string id(argv[2]);
auto disk = vm->findDisk(id);
if (disk == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
}
std::string type(argv[3]);
if (type == "public") {
return sendGenericOkFail(cli, disk->partitionPublic());
} else if (type == "private") {
return sendGenericOkFail(cli, disk->partitionPrivate());
} else if (type == "mixed") {
if (argc < 4) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
int frac = atoi(argv[4]);
return sendGenericOkFail(cli, disk->partitionMixed(frac));
} else {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
} else if (cmd == "mkdirs" && argc > 2) {
// mkdirs [path] return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
} else if (cmd == "user_added" && argc > 3) {
// user_added [user] [serial] return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
} else if (cmd == "user_removed" && argc > 2) {
// user_removed [user] return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
} else if (cmd == "user_started" && argc > 2) {
// user_started [user] return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
} else if (cmd == "user_stopped" && argc > 2) {
// user_stopped [user] return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
} else if (cmd == "mount" && argc > 2) {
// mount [volId] [flags] [user] std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
int res = vol->mount();
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
return sendGenericOkFail(cli, res);
} else if (cmd == "unmount" && argc > 2) {
// unmount [volId] std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->unmount());
} else if (cmd == "format" && argc > 3) {
// format [volId] [fsType|auto] std::string id(argv[2]);
std::string fsType(argv[3]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->format(fsType));
} else if (cmd == "move_storage" && argc > 3) {
// move_storage [fromVolId] [toVolId] auto fromVol = vm->findVolume(std::string(argv[2]));
auto toVol = vm->findVolume(std::string(argv[3]));
if (fromVol == nullptr || toVol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
(new android::vold::MoveTask(fromVol, toVol))->start();
return sendGenericOkFail(cli, 0);
} else if (cmd == "benchmark" && argc > 2) {
// benchmark [volId] std::string id(argv[2]);
nsecs_t res = vm->benchmarkPrivate(id);
return cli->sendMsg(ResponseCode::CommandOkay,
android::base::StringPrintf("%" PRId64, res).c_str(), false);
} else if (cmd == "forget_partition" && argc > 2) {
// forget_partition [partGuid] std::string partGuid(argv[2]);
return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
} else if (cmd == "remount_uid" && argc > 3) {
// remount_uid [uid] [none|default|read|write] uid_t uid = atoi(argv[2]);
std::string mode(argv[3]);
return sendGenericOkFail(cli, vm->remountUid(uid, mode));
}
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
可以发现list功能不见了,但是mount和unmount功能还是在的,其中unmount的功能还简化了,不需要force了。
但是测试vdc volume unmount sdcard却不行。
通过研究源码,发现sdcard现在用的标签名为emulated。
EmulatedVolume::EmulatedVolume(const std::string& rawPath) :
VolumeBase(Type::kEmulated), mFusePid(0) {
setId("emulated");
mRawPath = rawPath;
mLabel = "emulated";
}
用emulated尝试,可以。所以在Android 6.0中,挂载和卸载方法为:
挂载
vdc volume mount emulated
卸载
vdc volume unmount emulated
Android 9.0/10.0
取消了CommandListener,命令直接看vdc.cpp
} else if (args[0] == "volume" && args[1] == "shutdown") {
checkStatus(vold->shutdown());
额,只剩卸载sdcard命令了,挂载哪里去了。。
Android 11.0
在最新版中取消了CommandListener,命令直接看vdc.cpp
} else if (args[0] == "volume" && args[1] == "shutdown") {
checkStatus(args, vold->shutdown());
} else if (args[0] == "volume" && args[1] == "reset") {
checkStatus(args, vold->reset());
可以看出最新版只留了两个命令shutdown和reset了。相比9.0把reset加回来了。