Vold:Volume Daemon,管理和控制Android平台外部存储设备的后台进程,包括SD卡的插拔时间检测、SD卡挂载、卸载、格式化等等。
MountService和Vold交互,比如会发送一些广播,是接受到了vold的信息之后采取的动作。另外也会向vold发送挂载SD卡等命令。
Vold中的NetlinkManager模块(NM)接受来自linux内核的uevent消息。例如SD卡插拔等动作会引起Kernel向NM发送uevent消息。
NM将这些消息转发给VolumManager模块(VM)。VM会对应做一些操作,然后把相关信息通过CommandListener(CL)发送给MountService,MountService根据收到的消息会发送相关的处理命令给VM做进一步的处理。例如:SD卡插入后,VM会将来自NM的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”给Vold,指示它挂载这个SD卡。
CL模块内部封装了一个socket用于跨进程通信。它在vold进程中属于监听端,而连接端是MountService。它一方面接受来自MountService的控制命令(例如卸载存储卡、格式化存储卡),另一方面VM和NM模块又会通过它将一些信息发送给MountService。
下面我们开始分析Vold代码:
先从main函数:
int main() {
VolumeManager *vm;
CommandListener *cl;
NetlinkManager *nm;
mkdir("/dev/block/vold", 0755);
klog_set_level(6);
if (!(vm = VolumeManager::Instance())) {//创建VolumeManager
SLOGE("Unable to create VolumeManager");
exit(1);
};
if (!(nm = NetlinkManager::Instance())) {//创建NetlinkManager
SLOGE("Unable to create NetlinkManager");
exit(1);
};
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);//设置Broadcaster用来vold向MountService通信
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {
SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
exit(1);
}
if (process_config(vm)) {//根据文件配置VM对象,后面详细介绍
SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
}
if (nm->start()) {
SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
coldboot("/sys/block");//通过往/sys/block目录下对应的uevent文件写入“add\n"来触发内核发送Uevent消息,通过这种方式得到这些设备的当前信息。
// coldboot("/sys/class/switch");
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
SLOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
// Eventually we'll become the monitoring thread
while(1) {//无限循环
sleep(1000);
}
SLOGI("Vold exiting");
exit(0);
}
接下来我们看下NetlinkManager模块:
NetlinkManager *NetlinkManager::Instance() {
if (!sInstance)
sInstance = new NetlinkManager();
return sInstance;
}
NetlinkManager::NetlinkManager() {
mBroadcaster = NULL;
}
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
int on = 1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;//用来接受内核的netlink消息
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
if ((mSock = socket(PF_NETLINK,
SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
goto out;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {//主要看下NetlinkHandler
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
而接下来我们看下NetlinkHandler
NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
NetlinkHandler::~NetlinkHandler() {
}
int NetlinkHandler::start() {
return this->startListener();
}
int NetlinkHandler::stop() {
return this->stopListener();
}
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);
}
}
NetlinkHandler中的start调用了startListener函数,而NetlinkHandler继承了NetlinkListener类,因此看下NetlinkListener有没有startListener函数:
NetlinkListener::NetlinkListener(int socket) :
SocketListener(socket, false) {
mFormat = NETLINK_FORMAT_ASCII;
}
#endif
NetlinkListener::NetlinkListener(int socket, int format) :
SocketListener(socket, false), mFormat(format) {
}
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
ssize_t count;
uid_t uid = -1;
count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
socket, mBuffer, sizeof(mBuffer), &uid));
if (count < 0) {
if (uid > 0)
LOG_EVENT_INT(65537, uid);
SLOGE("recvmsg failed (%s)", strerror(errno));
return false;
}
NetlinkEvent *evt = new NetlinkEvent();
if (evt->decode(mBuffer, count, mFormat)) {
onEvent(evt);
} else if (mFormat != NETLINK_FORMAT_BINARY) {
// Don't complain if parseBinaryNetlinkMessage returns false. That can
// just mean that the buffer contained no messages we're interested in.
SLOGE("Error decoding NetlinkEvent");
}
delete evt;
return true;
}
也没有,NetlinkListener继承了SocketListener类,再看看SocketListener类中有没有startListener函数,
int SocketListener::startListener() {
return startListener(4);
}
int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
SLOGE("Obtaining file descriptor socket '%s' failed: %s",
mSocketName, strerror(errno));
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
}
if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {//开启了一个线程
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
SocketListener果然有startListener函数,开启了一个线程,再看看threadStart函数
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
直接调用了runlistener,在runlistener使用了select进行了IO复用。
void SocketListener::runListener() {
SocketClientCollection pendingList;
while(1) {
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
int max = -1;
FD_ZERO(&read_fds);
if (mListen) {
max = mSock;
FD_SET(mSock, &read_fds);
}
FD_SET(mCtrlPipe[0], &read_fds);
if (mCtrlPipe[0] > max)
max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
// NB: calling out to an other object with mClientsLock held (safe)
int fd = (*it)->getSocket();
FD_SET(fd, &read_fds);
if (fd > max) {
max = fd;
}
}
pthread_mutex_unlock(&mClientsLock);
SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
sleep(1);
continue;
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
break;
}
continue;
}
if (mListen && FD_ISSET(mSock, &read_fds)) {
struct sockaddr addr;
socklen_t alen;
int c;
do {
alen = sizeof(addr);
c = accept(mSock, &addr, &alen);
SLOGV("%s got %d from accept", mSocketName, c);
} while (c < 0 && errno == EINTR);
if (c < 0) {
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
}
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
}
/* Add all active clients to the pending list first */
pendingList.clear();
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
SocketClient* c = *it;
// NB: calling out to an other object with mClientsLock held (safe)
int fd = c->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pendingList.push_back(c);
c->incRef();
}
}
pthread_mutex_unlock(&mClientsLock);
/* Process the pending list, since it is owned by the thread,
* there is no need to lock it */
while (!pendingList.empty()) {
/* Pop the first item from the list */
it = pendingList.begin();
SocketClient* c = *it;
pendingList.erase(it);
/* Process it, if false is returned, remove from list */
if (!onDataAvailable(c)) {//onDataAviailable是一个虚函数在NetlinkListener类中有实现
release(c, false);
}
c->decRef();
}
}
}
而在NetlinkListener类中的onDataAvailable函数中又调用了onEvent函数,而这个函数是一个虚函数在NetlinkHandler类中实现,如下:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();//调用VolumeManager单例
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);//如果是这个子系统的继续调用VM的handleBlockEvent
}
}
下面再看VolumeManager中的handleBlockEvent函数:
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
const char *devpath = evt->findParam("DEVPATH");
/* Lookup a volume to handle this device */
VolumeCollection::iterator it;
bool hit = false;
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {//根据VolumeManager中的mVolumes一个个遍历去处理
if (!(*it)->handleBlockEvent(evt)) {
#ifdef NETLINK_DEBUG
SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
#endif
hit = true;
break;
}
}
if (!hit) {
#ifdef NETLINK_DEBUG
SLOGW("No volumes handled block event for '%s'", devpath);
#endif
}
}
VolumeManager中根据Volumes的list一个个去遍历根据每个volume的handleBlockEvent函数处理。接下来我们需要看,何时volume加入到VolumeManager中去的:答案是在main函数中调用了process_config函数,其根据配置文件配置VM对象。
static int process_config(VolumeManager *vm)
{
char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
char propbuf[PROPERTY_VALUE_MAX];
int i;
int ret = -1;
int flags;
property_get("ro.hardware", propbuf, "");
snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
fstab = fs_mgr_read_fstab(fstab_filename);
if (!fstab) {
SLOGE("failed to open %s\n", fstab_filename);
return -1;
}
/* Loop through entries looking for ones that vold manages */
for (i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
DirectVolume *dv = NULL;
flags = 0;
/* Set any flags that might be set for this volume */
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
flags |= VOL_NONREMOVABLE;
}
if (fs_mgr_is_encryptable(&fstab->recs[i])) {
flags |= VOL_ENCRYPTABLE;
}
/* Only set this flag if there is not an emulated sd card */
if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) &&
!strcmp(fstab->recs[i].fs_type, "vfat")) {
flags |= VOL_PROVIDES_ASEC;
}
dv = new DirectVolume(vm, &(fstab->recs[i]), flags);//新建DirectVolume对象
if (dv->addPath(fstab->recs[i].blk_device)) {//添加设备在sysfs中的路径
SLOGE("Failed to add devpath %s to volume %s",
fstab->recs[i].blk_device, fstab->recs[i].label);
goto out_fail;
}
vm->addVolume(dv);//VM中加入DirectVolume对象
}
}
ret = 0;
out_fail:
return ret;
}
process_config主要是解析/etc/vold.fstab。这个文件就是设置一些存储设备的挂载点,并且在VM中添加了DirectVolume对象。
DirectVolume从Volume派生,可以看成是外部存储卡的代表。封装了加载、卸载存储卡、格式化等。
DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) :
Volume(vm, rec, flags) {//参数rec->label: “sdcard” rec->mount_point: "/mnt/sdcard"
mPaths = new PathCollection();
for (int i = 0; i < MAX_PARTITIONS; i++)
mPartMinors[i] = -1;
mPendingPartCount = 0;
mDiskMajor = -1;
mDiskMinor = -1;
mDiskNumParts = 0;
mIsDecrypted = 0;
if (strcmp(rec->mount_point, "auto") != 0) {
ALOGE("Vold managed volumes must have auto mount point; ignoring %s",
rec->mount_point);
}
char mount[PATH_MAX];
snprintf(mount, PATH_MAX, "%s/%s", Volume::MEDIA_DIR, rec->label);
mMountpoint = strdup(mount);
snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label);
mFuseMountpoint = strdup(mount);
setState(Volume::State_NoMedia);
}
addPath函数,主要是添加设备在sysfs中的路径,把某个存储卡相关的设备路径与这个DirectVolume绑定到一起,这个设备路径和Uevent中的DEVPATH对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。不过一般手机只有一个存储卡接口,所以vold也只有一个DirectVolume。
int DirectVolume::addPath(const char *path) {
mPaths->push_back(new PathInfo(path));
return 0;
}
继续回到主题,前面分析到VM中遍历mVolumes,去执行DirectVolume中的handleBlockEvent,如下
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
const char *dp = evt->findParam("DEVPATH");
PathCollection::iterator it;
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if ((*it)->match(dp)) {//去看Uevent中的DEVPATH是否在mPaths中
/* We can handle this disk */
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
if (action == NetlinkEvent::NlActionAdd) {
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
if (createDeviceNode(nodepath, major, minor)) {
SLOGE("Error making device node '%s' (%s)", nodepath,
strerror(errno));
}
if (!strcmp(devtype, "disk")) {
handleDiskAdded(dp, evt);
} else {
handlePartitionAdded(dp, evt);
}
/* Send notification iff disk is ready (ie all partitions found) */
if (getState() == Volume::State_Idle) {
char msg[255];
snprintf(msg, sizeof(msg),
"Volume %s %s disk inserted (%d:%d)", getLabel(),
getFuseMountpoint(), mDiskMajor, mDiskMinor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);
}
} else if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype, "disk")) {
handleDiskRemoved(dp, evt);
} else {
handlePartitionRemoved(dp, evt);
}
} else if (action == NetlinkEvent::NlActionChange) {
if (!strcmp(devtype, "disk")) {
handleDiskChanged(dp, evt);
} else {
handlePartitionChanged(dp, evt);
}
} else {
SLOGW("Ignoring non add/remove/change event");
}
return 0;
}
}
errno = ENODEV;
return -1;
}
上面函数就是内核发送的Uevent最后的处理函数,详细的分析我们最后通过一个SD卡插入的实例看。
下面我们分析下CommandListener,CommandListener在main函数中,实例化,并且调用startListener函数,而发现CommandListener中没有startListener函数,就去父类FrameworkListener中找,也没有再去FrameworkListener的父类SocketListener中找,前面分析NetlinkHandler已经分析过这个类,它会开启一个线程,并且在线程中使用select的IO复用监听socket(是由MountService传过来的数据),最后调用onDataAvailable虚函数,而FrameworkListener实现了这个函数,在onDataAvailable函数中调用了FrameworkListener::dispatchCommand函数,在这个函数最后会调用各个command中的runCommand。
下面直接通过一个SD卡插入的实例说明整个过程:
先看SD卡插入,的Uevent信息:
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
ACTION=add //add表示设备插入动作 ,还有remove change动作
//DEVPATH表示设备位于/sys目录中的设备路径
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
//SUBSYSTEM表示该设备属于哪一类设备,block块设备,磁盘也属于这类,另外还有字符型设备
SUBSYSTEM=block
MAJOR=179 //MAJOR和MINOR分别表示该设备的主次设备号,两者联合起来表示一个设备。
MINOR=0
DEVNAME=mmcblk0
DEVTYPE=disk //设备Type为disk
NPARTS=3 //表示该SD卡上的分区,这里表示有3块分区
SEQNUM=1357 //序号
DirectVolume会处理这个Uevent信息,
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
const char *dp = evt->findParam("DEVPATH");
PathCollection::iterator it;
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if ((*it)->match(dp)) {
/* We can handle this disk */
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
if (action == NetlinkEvent::NlActionAdd) {//插入设备
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
if (createDeviceNode(nodepath, major, minor)) {
SLOGE("Error making device node '%s' (%s)", nodepath,
strerror(errno));
}
if (!strcmp(devtype, "disk")) {//是disk类型的
handleDiskAdded(dp, evt);
} else {
handlePartitionAdded(dp, evt);
}
/* Send notification iff disk is ready (ie all partitions found) */
if (getState() == Volume::State_Idle) {
char msg[255];
snprintf(msg, sizeof(msg),
"Volume %s %s disk inserted (%d:%d)", getLabel(),
getFuseMountpoint(), mDiskMajor, mDiskMinor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);//给MountService发送VolumeDiskInserted信息
}
} else if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype, "disk")) {
handleDiskRemoved(dp, evt);
} else {
handlePartitionRemoved(dp, evt);
}
} else if (action == NetlinkEvent::NlActionChange) {
if (!strcmp(devtype, "disk")) {
handleDiskChanged(dp, evt);
} else {
handlePartitionChanged(dp, evt);
}
} else {
SLOGW("Ignoring non add/remove/change event");
}
return 0;
}
}
errno = ENODEV;
return -1;
}
下面来看下handleDiskAdded函数
void DirectVolume::handleDiskAdded(const char * /*devpath*/,
NetlinkEvent *evt) {
mDiskMajor = atoi(evt->findParam("MAJOR"));
mDiskMinor = atoi(evt->findParam("MINOR"));
const char *tmp = evt->findParam("NPARTS");//分区数
if (tmp) {
mDiskNumParts = atoi(tmp);
} else {
SLOGW("Kernel block uevent missing 'NPARTS'");
mDiskNumParts = 1;
}
mPendingPartCount = mDiskNumParts;
for (int i = 0; i < MAX_PARTITIONS; i++)
mPartMinors[i] = -1;
if (mDiskNumParts == 0) {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - No partitions - good to go son!");
#endif
setState(Volume::State_Idle);
} else {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - waiting for %d pending partitions", mPendingPartCount);
#endif
setState(Volume::State_Pending);
}
}
我们来分析下setState这个函数
void Volume::setState(int state) {
char msg[255];
int oldState = mState;
if (oldState == state) {//一样的状态
SLOGW("Duplicate state (%d)\n", state);
return;
}
if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) {
mRetryMount = false;
}
mState = state;
SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
oldState, stateToStr(oldState), mState, stateToStr(mState));
snprintf(msg, sizeof(msg),
"Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
getFuseMountpoint(), oldState, stateToStr(oldState), mState,
stateToStr(mState));
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
msg, false);//给MountService发送VolumeStateChange信息
}
接下来我们看看MountService收到VolumeDiskInserted信息后会怎么处理:
public boolean onEvent(int code, String raw, String[] cooked) {
if (DEBUG_EVENTS) {
StringBuilder builder = new StringBuilder();
builder.append("onEvent::");
builder.append(" raw= " + raw);
if (cooked != null) {
builder.append(" cooked = " );
for (String str : cooked) {
builder.append(" " + str);
}
}
Slog.i(TAG, builder.toString());
}
if (code == VoldResponseCode.VolumeStateChange) {
/*
* One of the volumes we're managing has changed state.
* Format: "NNN Volume <label> <path> state changed
* from <old_#> (<old_str>) to <new_#> (<new_str>)"
*/
notifyVolumeStateChange(
cooked[2], cooked[3], Integer.parseInt(cooked[7]),
Integer.parseInt(cooked[10]));
} else if (code == VoldResponseCode.VolumeUuidChange) {
// Format: nnn <label> <path> <uuid>
final String path = cooked[2];
final String uuid = (cooked.length > 3) ? cooked[3] : null;
final StorageVolume vol = mVolumesByPath.get(path);
if (vol != null) {
vol.setUuid(uuid);
}
} else if (code == VoldResponseCode.VolumeUserLabelChange) {
// Format: nnn <label> <path> <label>
final String path = cooked[2];
final String userLabel = (cooked.length > 3) ? cooked[3] : null;
final StorageVolume vol = mVolumesByPath.get(path);
if (vol != null) {
vol.setUserLabel(userLabel);
}
} else if ((code == VoldResponseCode.VolumeDiskInserted) ||//插入设备
(code == VoldResponseCode.VolumeDiskRemoved) ||
(code == VoldResponseCode.VolumeBadRemoval)) {
// FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
// FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
// FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
String action = null;
final String label = cooked[2];
final String path = cooked[3];
int major = -1;
int minor = -1;
try {
String devComp = cooked[6].substring(1, cooked[6].length() -1);
String[] devTok = devComp.split(":");
major = Integer.parseInt(devTok[0]);
minor = Integer.parseInt(devTok[1]);
} catch (Exception ex) {
Slog.e(TAG, "Failed to parse major/minor", ex);
}
final StorageVolume volume;
final String state;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
state = mVolumeStates.get(path);
}
if (code == VoldResponseCode.VolumeDiskInserted) {//如果是插入设备
new Thread("MountService#VolumeDiskInserted") {
@Override
public void run() {
try {
int rc;
if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {//开启线程执行doMountVolume
Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
}
} catch (Exception ex) {
Slog.w(TAG, "Failed to mount media on insertion", ex);
}
}
}.start();
} else if (code == VoldResponseCode.VolumeDiskRemoved) {
/*
* This event gets trumped if we're already in BAD_REMOVAL state
*/
if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
return true;
}
/* Send the media unmounted event first */
if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);
action = Intent.ACTION_MEDIA_REMOVED;
} else if (code == VoldResponseCode.VolumeBadRemoval) {
if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
/* Send the media unmounted event first */
updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);
action = Intent.ACTION_MEDIA_BAD_REMOVAL;
} else if (code == VoldResponseCode.FstrimCompleted) {
EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
} else {
Slog.e(TAG, String.format("Unknown code {%d}", code));
}
if (action != null) {
sendStorageIntent(action, volume, UserHandle.ALL);
}
} else {
return false;
}
return true;
}
private int doMountVolume(String path) {
int rc = StorageResultCode.OperationSucceeded;
final StorageVolume volume;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
}
if (!volume.isEmulated() && hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA)) {
Slog.w(TAG, "User has restriction DISALLOW_MOUNT_PHYSICAL_MEDIA; cannot mount volume.");
return StorageResultCode.OperationFailedInternalError;
}
if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
try {
mConnector.execute("volume", "mount", path);//mConnector是与vold通信部分,发送volume mount命令挂载磁盘
} catch (NativeDaemonConnectorException e) {
//异常处理
}
再回到vold中,看处理mount命令:
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")) {
bool broadcast = argc >= 3 && !strcmp(argv[2], "broadcast");
return vm->listVolumes(cli, broadcast);
} 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 <off/on>", false);
return 0;
}
vm->setDebug(!strcmp(argv[2], "on") ? true : false);
} else if (!strcmp(argv[1], "mount")) {//处理mount命令
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
return 0;
}
rc = vm->mountVolume(argv[2]);//调用mountVolume函数
}
。。。。。。。。。。
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);//发送Okay消息返回
} else {
int erno = errno;
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "volume operation failed", true);
}
return 0;
}
mountVolume函数如下:
int VolumeManager::mountVolume(const char *label) {
Volume *v = lookupVolume(label);//查找Volume
if (!v) {
errno = ENOENT;
return -1;
}
return v->mountVol();
}
mountVol函数如下:
int Volume::mountVol() {
dev_t deviceNodes[4];
int n, i, rc = 0;
char errmsg[255];
int flags = getFlags();
bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;
// TODO: handle "bind" style mounts, for emulated storage
char decrypt_state[PROPERTY_VALUE_MAX];
char crypto_state[PROPERTY_VALUE_MAX];
char encrypt_progress[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt_state, "");
property_get("vold.encrypt_progress", encrypt_progress, "");
/* Don't try to mount the volumes if we have not yet entered the disk password
* or are in the process of encrypting.
*/
if ((getState() == Volume::State_NoMedia) ||//还没初始化
((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) {
snprintf(errmsg, sizeof(errmsg),
"Volume %s %s mount failed - no media",
getLabel(), getFuseMountpoint());
mVm->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeMountFailedNoMedia,
errmsg, false);
errno = ENODEV;
return -1;
} else if (getState() != Volume::State_Idle) {//当前状态正忙
errno = EBUSY;
if (getState() == Volume::State_Pending) {
mRetryMount = true;
}
return -1;
}
if (isMountpointMounted(getMountpoint())) {//是否已经挂载
SLOGW("Volume is idle but appears to be mounted - fixing");
setState(Volume::State_Mounted);//设置挂载状态
// mCurrentlyMountedKdev = XXX
return 0;
}
n = getDeviceNodes((dev_t *) &deviceNodes, 4);
。。。。。。。。
for (i = 0; i < n; i++) {
char devicePath[255];
sprintf(devicePath, "/dev/block/vold/%d:%d", major(deviceNodes[i]),
minor(deviceNodes[i]));
SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
errno = 0;
setState(Volume::State_Checking);
if (Fat::check(devicePath)) {
if (errno == ENODATA) {
SLOGW("%s does not contain a FAT filesystem\n", devicePath);
continue;
}
errno = EIO;
/* Badness - abort the mount */
SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
setState(Volume::State_Idle);
return -1;
}
errno = 0;
int gid;
//把设备mount一个地址
if (Fat::doMount(devicePath, getMountpoint(), false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
continue;
}
extractMetadata(devicePath);
if (providesAsec && mountAsecExternal() != 0) {
SLOGE("Failed to mount secure area (%s)", strerror(errno));
umount(getMountpoint());
setState(Volume::State_Idle);
return -1;
}
char service[64];
snprintf(service, 64, "fuse_%s", getLabel());
property_set("ctl.start", service);
setState(Volume::State_Mounted);//设置设备状态State_Mounted
mCurrentlyMountedKdev = deviceNodes[i];
return 0;
}
SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
setState(Volume::State_Idle);
return -1;
}
设置设备状态State_Mounted会发送VolumeStateChange消息给MountService,当MountService收到后会发送广播
public boolean onEvent(int code, String raw, String[] cooked) {
if (DEBUG_EVENTS) {
StringBuilder builder = new StringBuilder();
builder.append("onEvent::");
builder.append(" raw= " + raw);
if (cooked != null) {
builder.append(" cooked = " );
for (String str : cooked) {
builder.append(" " + str);
}
}
Slog.i(TAG, builder.toString());
}
if (code == VoldResponseCode.VolumeStateChange) {
/*
* One of the volumes we're managing has changed state.
* Format: "NNN Volume <label> <path> state changed
* from <old_#> (<old_str>) to <new_#> (<new_str>)"
*/
notifyVolumeStateChange(
cooked[2], cooked[3], Integer.parseInt(cooked[7]),
Integer.parseInt(cooked[10]));
}
最后会在notifyVolumeStateChange发送广播:
private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
final StorageVolume volume;
final String state;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
state = getVolumeState(path);
}
if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);
String action = null;
if (oldState == VolumeState.Shared && newState != oldState) {
if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);
}
if (newState == VolumeState.Init) {
} else if (newState == VolumeState.NoMedia) {
// NoMedia is handled via Disk Remove events
} else if (newState == VolumeState.Idle) {
/*
* Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
* if we're in the process of enabling UMS
*/
if (!state.equals(
Environment.MEDIA_BAD_REMOVAL) && !state.equals(
Environment.MEDIA_NOFS) && !state.equals(
Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
action = Intent.ACTION_MEDIA_UNMOUNTED;
}
} else if (newState == VolumeState.Pending) {
} else if (newState == VolumeState.Checking) {
if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);
action = Intent.ACTION_MEDIA_CHECKING;
} else if (newState == VolumeState.Mounted) {
if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
action = Intent.ACTION_MEDIA_MOUNTED;
} else if (newState == VolumeState.Unmounting) {
action = Intent.ACTION_MEDIA_EJECT;
} else if (newState == VolumeState.Formatting) {
} else if (newState == VolumeState.Shared) {
if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
/* Send the media unmounted event first */
updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
updatePublicVolumeState(volume, Environment.MEDIA_SHARED);
action = Intent.ACTION_MEDIA_SHARED;
if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
} else if (newState == VolumeState.SharedMnt) {
Slog.e(TAG, "Live shared mounts not supported yet!");
return;
} else {
Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
}
if (action != null) {
sendStorageIntent(action, volume, UserHandle.ALL);
}
}
至此Vold、和MountService分析结束。