这段时间一直在研究内置SD卡和外置SD卡的挂载问题,看了网上jecese关于Android4.2的Vold挂载的博客后,结合自己在Android4.4上做的一些实验,记录下来,以便日后查阅!
一:Vold的启动
关于vold的源码在jb4.4-kikat/system/vold/,根据Android.mk可以知道编译后会生成一个可执行文件vold,并安装到system/bin下。而这个vold会作为一个服务在系统启动的时候去启动它!
在init.rc中
service vold /system/bin/vold
class core
socket vold stream 0660 root mount //vold启动的时候创建socket
ioprio be 2 //这个不是很明白
vold的入口为/system/vold/main.cpp中的main函数
int main() {
VolumeManager *vm;//这个类主要是接收经NetlinkManager类处理过的消息进行挂载动作
CommandListener *cl;
NetlinkManager *nm;//这个类主要通过NetlinkHandler类中的onEvent()方法接收来自kernel发过来的事件信息
SLOGI("Vold 2.1 (the revenge) firing up");
mkdir("/dev/block/vold", 0755);//创建/dev/block/vold/存放设备节点
/* For when cryptfs checks and mounts an encrypted filesystem */
klog_set_level(6);
/* Create our singleton managers */
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
exit(1);
};
if (!(nm = NetlinkManager::Instance())) {
SLOGE("Unable to create NetlinkManager");
exit(1);
};
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {//没有实际操作
SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
exit(1);
}
if (process_config(vm)) {
SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
}
if (nm->start()) {//创建接收来自kernel信息的socket,实例化NetlinkHandler类,并开启socket检测
SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
coldboot("/sys/block");//遍历/sys/block下全部的设备信息,并发送一个add事件
// coldboot("/sys/class/switch");
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {//开启vold的socket检测
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);
}
在挂载SD卡或者U盘等存储设备前,Android是通过/system/vold/NetlinkHandler.cpp来获取kernel发过来的事件消息的,这里我们研究的SD卡
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
SLOGD("Javen.tang subsys=%s\n",subsys);
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
}
SD卡与mmc类同,所以这里获取到的subsys就是block。
二:SD卡的挂载流程
1、kerner发出SD卡插入的uevent。
2、NetlinkHandler::onEvent()中接收内核发出的uevent并解析。
3、VolumeManager::handleBlockEvent()继续处理。
4、接下来会调用到DirectVolume.cpp中的handleBlockEvent函数。
5、根据类型devtype是disk还是partition来进行选择,这里我们是内置SD卡,类型为partition,并且事件action为Add,所以调用的是handlePartitionAdded(dp, evt),在该方法中首先会通过setState(Volume::State_Idle)发送广播VolumeStateChange广播,然后在发送一个VolumeDiskInserted。
6、当handlePartitionAdded中通过 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);来发送一个广播时,在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java的onEvent()方法中能接受到。
7、然后在onEvent()中根据发送过来的广播类型,做相应动作,我们这里研究VolumeDiskInserted这个广播类型,当检测到为VolumeDiskInserted的广播类型后会new Thread.start(),然后在该线程中执行doMountVolume(path);
8、在doMountVolume()中通过mConnector.execute("volume", "mount", path)向Vold发送指令。
9、在system/core/libsysutils/src/SocketListener.cpp中有个runListener()函数一直在监听socket,接收从上层发送过来的指令。
10、跟着会调用到FrameworkListener::onDataAvailable()来处理接收到的消息。
11、然后调用FrameworkListener::dispatchCommand(SocketClient *cli, char *data)通过c->runCommand(cli, argc, argv)来分发指令。
12、然后在/system/vold/CommandListener.cpp有具体的runCommand的实现,我们找到CommandListener::VolumeCmd::runCommand这个函数,这个方法就是对Volume分发指令的解析,然后在该方法中会调用rc = vm->mountVolume(argv[2]);,进而调用到VolumeManager::mountVolume方法中去,在该方法中调用v->mountVol();
13、在/system/Volume.cpp中的mountVol就是真正处理挂载的函数,挂载的结果通过setState();函数来通知上层应用。其中setState(Volume::State_Checking)通知上层正在检查SD卡, setState(Volume::State_Mounted)是通知上层SD卡已经挂载成功,最后是在Fat::doMount通过mount函数来挂载SD卡的。
---------------到这里SD卡的挂载已初步完成,接下则是挂载后的消息发送到上层---------------------------
14、如上所述,当Vold通过setState()发送广播过来的时候,在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java中的onEvent()函数接收。所以当我们发送的是
VolumeStateChange类型的广播时,onEvent中会执行:
15、然后在MountService.java中的notifyVolumeStateChange(String label, String path, int oldState, int newState) 中执行updatePublicVolumeState();同时通过sendStorageIntent(action, volume, UserHandle.ALL)发送一个action = Intent.ACTION_MEDIA_MOUNTED的挂载成功的广播,应用层可以去接收这个广播做相关动作!
16、接着在updatePublicVolumeState()中会执行到bl.mListener.onStorageStateChanged(path, oldState, state)这个函数!
17、在Android源码中的package/apps/Settings/src/com.android.settings.deviceinfo/Memory.java中,实现了StorageEventListener的内部类,并重写了onStorageStateChanged()方法,当updatePublicVolumeState()中调用了onStorageStateChanged()后,Memory.java中也会收到,在Memory.java收到后会在Setting界面进行更新,系统设置--存储中会更新SD卡的状态。
--------------------------至此SD卡从底层到上层的挂载流程就完成了----------------------------