Andriod Vold进程工作机制分析
一、Andriod存储系统
MountService是为应用提供服务的Binder类,运行在SystemServer中;StorageManager是MountServer的代理,在用户进程中使用。
Vold是一个守护进程,负责和底层存储系统的交互。
MountService和Vold之间通过socket进行双向通信,MountService向Vold发送操作命令,Vold向MountService发送底层硬件发生变化的通知消息。
Vold进程的主体是VolumeManager对象,管理着系统底层所有Volume对象,实现各种存储相关的操作。
Vold中CommandListener对象负责和MountService中的NativeDemonConnector进行Socket通信;NetlinkHandler对象负责监听来自驱动的Neilink Socket消息;NetlinkManager对象负责创建3个NetlinkHandler对象。
二、Vold进程启动
1、由Kernel发起挂载请求
Kernel通过Netlink发送请求(传递uevent)给NetlinkManager,NetlinkManager通过内部的线程NetlinkHandler交给VolumeManager进行实际操作,然后VolumeManager通过CommandListener通知MountService。
2、由SystemServer发起挂载请求
运行在SystemServer进程的MountService通过NativeDaemonConnector给CommandListener发送请求,CommandListener再通知VolumeManager进行实际操作。
3、Vold进程启动
Vold也是通过init进程启动,它的启动文件定义如下:
system\vold\vold.rc:
*
service vold /system/bin/vold \
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
socket vold stream 0660 root mount
socket cryptd stream 0660 root mount
ioprio be 2
writepid /dev/cpuset/foreground/tasks
vold服务放到了core分组,意味着系统启动时它就会被init进程启动。
vold模块的源码及其入口函数main:
system\vold\main.cpp
*
int main(int argc, char** argv) {
...
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;
NetlinkManager *nm;
parse_args(argc, argv);
解析vold.rc中定义的blkid和fsck相关的参数
...
mkdir("/dev/block/vold", 0755);
//创建vold目录
...
/* Create our singleton managers */
if (!(vm = VolumeManager::Instance())) {
//创建VolumeManager对象
LOG(ERROR) << "Unable to create VolumeManager";
exit(1);
}
if (!(nm = NetlinkManager::Instance())) {
//创建NetlinkManager对象
LOG(ERROR) << "Unable to create NetlinkManager";
exit(1);
}
...
cl = new CommandListener();
//创建CommandListener对象
ccl = new CryptCommandListener();
vm->setBroadcaster((SocketListener *) cl);
//建立vm和cl的联系
nm->setBroadcaster((SocketListener *) cl);
//建立nm和cl的联系
if (vm->start()) {
//启动VolumeManager
PLOG(ERROR) << "Unable to start VolumeManager";
exit(1);
}
if (process_config(vm)) {
//根据配置文件初始化VolumeManager
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
if (nm->start()) {
//启动NetlinkManager
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
...
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
//启动CommandListener,开始监听
PLOG(ERROR) << "Unable to start CommandListener";
exit(1);
}
...
// Eventually we'll become the monitoring thread
while(1) {
sleep(1000);
}
LOG(ERROR) << "Vold exiting";
exit(0);
}
主函数的主要工作是创建三个对象VolumeManager、NetlinkManager、CommandListener,同时将CommandListener对象分别设置到了VolumeManager和NetlinkManager中。因为CommandListener用于和Java层的NativeDaemonConnector对象进行socket通信,所以VolumeManager和NetlinkManager都需要拥有CommandListener对象的引用。接下来,Vold进程具体的工作就会交付给子模块进行处理。
三、由Kernel发起挂载请求
SD卡插入,Kernel发起挂载请求为例。
1、监听驱动发出的消息——Vold的NetlinkListener对象
NetlinkListener对象的主要作用是监听驱动发出的uevent消息。Vold的main函数中调用NetlinkListener类的静态函数Instance()来创建NetlinkListener对象并通过静态变量sInstance来引用,所以vold进程中只有一个NetlinkListener对象。NetlinkListener的构造函数:
system\vold\NetlinkManager.cpp:
*
NetlinkManager::NetlinkManager() {
mBroadcaster = NULL;
//初始化
}
构造函数只是简单的初始化,Vold的main函数会调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。然后调用NetlinkManager的start()函数:
*
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
//定义并初始化socket的地址结构
int sz = 64 * 1024;
int on = 1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
//创建PF_NETLINK地址簇的socket,NETLINK_KOBJECT_UEVENT表示该socket将接收内核的Uevent事件
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
//setsockopt设置socket的选项,此处设置socket的接收缓冲区大小为64 * 1024
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) {
//将创建出的socket绑定到之前的地址上,此时socket可以收到Kernel的数据了
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
mHandler = new NetlinkHandler(mSock);
//①创建并②启动一个NetlinkHandler
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
NetlinkManager启动后就是创建一个可以接收Kernel消息的socket,并以此socket构建并启动NetlinkHandler。NetlinkHandler则用于监听和接收socket的数据。
①NetlinkHandler的创建:
system\vold\NetlinkHandler.cpp:
*
NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
NetlinkHandler初始化时,将与Kernel通信的socket描述符传入到父类NetlinkListener中。
system\core\libsysutils\src\NetlinkListener.cpp:
*
NetlinkListener::NetlinkListener(int socket) :
SocketListener(socket, false) {
mFormat = NETLINK_FORMAT_ASCII;
}
NetlinkListener又进一步调用其父类SocketListener。
system\core\libsysutils\src\SocketListener.cpp:
*
SocketListener::SocketListener(int socketFd, bool listen) {
init(NULL, socketFd, listen, false);
}
*
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
mListen = listen;
mSocketName = socketName;
mSock = socketFd;
mUseCmdNum = useCmdNum;
pthread_mutex_init(&mClientsLock, NULL);
mClients = new SocketClientCollection();
}
创建完NetlinkHandler后,NetlinkManager调用了NetlinkHandler的start方法。
②NetlinkHandler的启动:
*
int NetlinkHandler::start() {
return this->startListener();
//根据继承体系,实际上调用了SocketListener的startListenr函数
}
*
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);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
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));
//利用mSocket构造SocketClient加入到mClients中
if (pipe(mCtrlPipe)) {
//pipe系统调用将创建一个匿名管道(资料显示:mCtrlPipe是一个int类型的二元数组,其中mCtrlPipe[0]用于从管道读数据,mCtrlPipe[1]用于往管道写数据)
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
//创建一个监听线程,线程的执行函数为threadStart
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
startListener()函数将开始监听socket,这个函数在NetlinkHandler中会被调用,在CommandListener中也会被调用。startListener()函数首先判断mSocketName是否有值,只有CommandListener对象会对这个变量赋值,它的值就是在init.rc中定义的socket字符串。调用函数android_get_control_socket()的目的就是为了从环境变量中取得socket的值。这样CommandListener对象得到了它需要监听的socket。而对于NetlinkHandler对象而言,它的mSocket不为NULL,前面已经创建出了socket。
NetlinkHandler启动后,创建了一个工作线程,用于接收和处理数据。
*
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast
(obj);
me->runListener();
//调用SocketListener的runListener函数
pthread_exit(NULL);
return NULL;
}
*
void SocketListener::runListener() {
SocketClientCollection pendingList;
while(1) {
//无线循环,接收socket收到的数据
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);
//把mSock加入read_fds
}
FD_SET(mCtrlPipe[0], &read_fds);
//把管道mCtrlPipe[0]也加入read_fds
if (mCtrlPipe[0] > max)
max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
//mClients中保存的是NetlinkHandler对象的socket,或者CommandListener接入的socket
// NB: calling out to an other object with mClientsLock held (safe)
int fd = (*it)->getSocket();
FD_SET(fd, &read_fds);
//把它也加入到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) {
//执行select调用,开始等待socket上的数据,监听是否有数据到来
if (errno == EINTR)
continue;
//因为中断退出select,继续
SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
sleep(1);
//select出错,休眠一秒后继续
continue;
} else if (!rc)
continue;
//如果fd上没有数据到达,继续
if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
//FD_ISSET用于测试指定的文件描述符是否在该集合中,前面已经加入了
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
//如果从管道中读出CtrlPipe_Shutdown,则退出工作线程
break;
}
continue;
}
if (mListen && FD_ISSET(mSock, &read_fds)) {
//如果mSock是服务器端,进入这个分支,NetlinkHandler中的mSock并不是服务器端
sockaddr_storage ss;
sockaddr* addrp = reinterpret_cast(&ss);
socklen_t alen;
int c;
do {
alen = sizeof(ss);
c = accept(mSock, addrp, &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;
//接入发生错误,继续循环
}
fcntl(c, F_SETFD, FD_CLOEXEC);
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c, true, mUseCmdNum));
//将新的接入的socket加入到mClients中,这样再循环时就能监听到它的数据到达
pthread_mutex_unlock(&mClientsLock);
}
/* Add all active clients to the pending list first */
//当mSocket是服务端的时候,上面的代码将会增加新的mClient,但在下一次循环之前,这些mClient还未被加入到read_fds中
pendingList.clear();
pthread_mutex_lock(&mClientsLock);
//由于NetlinkHandler中的mSocket不是服务端,因此mClients中实际上只有mSocket自己(前面startListener中加入的)
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)) {
//如果mClients中某个socket上有数据了
pendingList.push_back(c);
//待处理的SocketClient加入到pendingList中
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()) {
//处理pendingList列表
/* Pop the first item from the list */
it = pendingList.begin();
SocketClient* c = *it;
pendingList.erase(it);
//把处理过的socket从列表中移除
/* Process it, if false is returned, remove from list */
if (!onDataAvailable(c)) {
//调用子类的onDataAvailable函数处理收到的数据
release(c, false);
//返回false时,需要关闭该SocketClient,关闭SocketClient将直接操作mClients对象
}
c->decRef();
}
}
}
runListener()函数接收到从驱动传递的数据或者MountService传递的数据后,调用onDataAvailable()函数来处理,FrameworkListener类和NetlinkListener类都会重载这个函数。Kernel发起挂载请求,即接收从驱动传递的数据,就用到NetlinkListener的onDataAvailable()函数。
*
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
ssize_t count;
uid_t uid = -1;
...
count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
mBuffer, sizeof(mBuffer), require_group, &uid));
//这里用uevent_kernel_recv函数,从socket中取出Uevent数据
if (count < 0) {
if (uid > 0)
LOG_EVENT_INT(65537, uid);
SLOGE("recvmsg failed (%s)", strerror(errno));
return false;
}
NetlinkEvent *evt = new NetlinkEvent();
//此处将Uevent数据解码成NetlinkEvent,然后调用子类的onEvent进行处理
if (evt->decode(mBuffer, count, mFormat)) {
//解析获得NetlinkEvent实例
onEvent(evt);
//传入NetlinkEvent实例
} 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;
}
先从socket中的字节流中取出Uevent事件,然后将这些事件解码成NetlinkEvent,接下来用得到的消息数据给NetlinkEvent对象的成员变量赋值,最后调用onEvent()做进一步处理。
*
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
//调用VolumeManager的instance函数创建VolumeManager
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
//如果event类型是block
vm->handleBlockEvent(evt);
//递交给VolumeManager进行处理
if (evt->getAction() == NetlinkEvent::Action::kAdd) {
if (coldboot_sent_uevent_count > 0 && (--coldboot_sent_uevent_count) <= 0) {
SLOGI("Coldboot: sem_post() because all uevent has handled");
sem_post(&coldboot_sem);
}
}
}
}
NetlinkHandler的onEvent函数中会判断event属于哪个系统,如果属于“bolck”,则调用VolumeManager的handleBlockEvent()函数来处理。至此,监听驱动发出消息的任务便已经完成,接下来任务递交给VolumeManager。
2、使用Disk对象来抽象实际的存储设备——VolumeManager模块
同样,vold的main()函数中调用了VolumeManager的Instance()函数来创建实例对象。VolumeManager的构造函数:
system\vold\VolumeManager.cpp:
*
VolumeManager::VolumeManager() {
mDebug = true;
mHandleUevent = true;
mActiveContainers = new AsecIdCollection();
mBroadcaster = NULL;
mUmsSharingCount = 0;
mSavedDirtyRatio = -1;
mUmsDirtyRatio = dirtyRatio();
mSkipUmountForResetCommand = false;
}
构造函数执行简单的初始化,Vold的main函数调用VolumeManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。完成VolumeManager的创建后,Vold进程调用start函数,启动VolumeManager。
*
int VolumeManager::start() {
// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
unmountAll();
//清除所有已经挂载的设备
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
//创建一个内部的挂载设备
mInternalEmulated = std::shared_ptr(
new android::vold::EmulatedVolume("/data/media"));
mInternalEmulated->create();
return 0;
}
通过清除所有已经挂载的设备可以让VolumeManager每次都从一个确定的“干净”的状态启动,避免之前出现Vold进程出现过crash。mInternalEmulated是一个VolumeBase类型的对象,用来创建一个内部的挂载设备。
system\vold\VolumeBase.cpp:
*
status_t VolumeBase::create() {
CHECK(!mCreated);
mCreated = true;
status_t res = doCreate();
//doCreate进行实际的创建
setState(State::kUnmounted);
//设置未挂载状态
notifyEvent(ResponseCode::VolumeCreated,
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
//*调用notifyEvent方法,通过CommandListener通知框架中的MountService
return res;
}
Vold进程的main函数中,创建并启动完VolumeManager后,就调用process_config函数对VolumeManager进行配置:
system\vold\main.cpp:
*
static int process_config(VolumeManager *vm) {
std::string path(android::vold::DefaultFstabPath());
//读取默认的fstab文件
fstab = fs_mgr_read_fstab(path.c_str());
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;
bool has_support_external_sd = false;
for (int i = 0; i < fstab->num_entries; i++) {
//循环处理文件所有行
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
//是否能被vold管理
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
continue;
}
//根据fstab文件中设备的信息构造sysPattern、nickname和flags
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;
}
if (!has_support_external_sd &&
(strstr(fstab->recs[i].blk_device, "msdc1") ||
strstr(fstab->recs[i].blk_device, "msdc.1") ||
strstr(fstab->recs[i].blk_device, "MSDC1"))) {
has_support_external_sd = true;
}
vm->addDiskSource(std::shared_ptr(
new VolumeManager::DiskSource(sysPattern, nickname, flags)));
//用构造出的sysPattern、nickname和flags信息创建DiskSource,并放入list中
#ifdef MTK_FAT_ON_NAND
if (!strncmp(fstab->recs[i].blk_device, "/devices/virtual/block/loop", 27)) {
int mLoopDeviceIdx = atoi((fstab->recs[i].blk_device+27));
/* Bind loop device */
char devicepath[100];
char fatimgfilepath[200];
int fd, ffd, mode;
struct loop_info loopinfo;
const char *fat_mnt;
const char *fat_filename;
fat_mnt = FAT_PARTITION_MOUNT_POINT;
fat_filename = FAT_IMG_NAME;
snprintf(devicepath, sizeof(devicepath), "/dev/block/loop%d", mLoopDeviceIdx);
snprintf(fatimgfilepath, sizeof(fatimgfilepath), "%s/%s", fat_mnt, fat_filename);
mode = O_RDWR;
if ((ffd = open(fatimgfilepath, mode)) < 0) {
if (ffd < 0) {
SLOGE("[FON]Fail to open %s %s(%d)", fatimgfilepath, strerror(errno), errno);
}
}
if ((fd = open(devicepath, mode)) < 0) {
SLOGE("[FON]Fail to open %s %s(%d)", devicepath, strerror(errno), errno);
}
/* Determine loop device is available or not */
if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0 && errno == ENXIO) {
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
SLOGE("[FON]Fail to ioctl: LOOP_SET_FD %s(%d)", strerror(errno), errno);
}
}
else {
SLOGE("[FON]Fail to bind FAT image %s to %s.Loop device is busy!", fatimgfilepath, devicepath);
}
close(fd);
close(ffd);
}
#endif
}
}
property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
property_set("vold.support_external_sd", has_support_external_sd ? "1" : "0");
return 0;
}
process_config其实就是解析fstab文件,然后设置一些存储设备的挂载点。
了解VolumeManager的创建、启动和设置完成后,继续回到Kernel发起挂载请求的流程中。VolumeManager的handleBlockEvent()函数继续处理从驱动中获取的NetlinkEvent信息。
*
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
std::lock_guard lock(mLock);
if (mDebug) {
// LOG(VERBOSE) << "----------------";
// LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
evt->dump();
}
if (!mHandleUevent) {
LOG(DEBUG) << "Ignore Event if mHandleUevent is false";
return;
}
std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
std::string devType(evt->findParam("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: {
//创建新的disk
std::string devName(evt->findParam("DEVNAME"));
if (strstr(devName.c_str(), "boot") || strstr(devName.c_str(), "rpmb")){
LOG(DEBUG) << "Skip '" << devName << "' disk uevent";
break;
}
for (auto source : mDiskSources) {
if (source->matches(eventPath)) {
#ifdef MTK_SHARED_SDCARD
if (major == kMajorBlockMmc && minor == kMinorBlockEMMC) {
SLOGI("%s(): For MTK_SHARED_SDCARD, remove EMMC disk", __FUNCTION__);
break;
}
#endif
// For now, assume that MMC and virtio-blk (the latter is
// emulator-specific; see Disk.cpp for details) devices are SD,
// and that everything else is USB
int flags = source->getFlags();
if (major == kMajorBlockMmc
|| (android::vold::IsRunningInEmulator()
&& major >= (int) kMajorBlockExperimentalMin
&& major <= (int) kMajorBlockExperimentalMax)) {
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();
//调用disk 的create方法
mDisks.push_back(std::shared_ptr(disk));
break;
}
}
break;
}
case NetlinkEvent::Action::kChange: {
//改变对应的disk信息
...
}
case NetlinkEvent::Action::kRemove: {
//移除对应的disk
...
}
default: {
LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
break;
}
}
}
VolumeManager的handleBlockEvent()函数,根据事件的内容,判断设备的变化情况,然后操作对应的Disk对象。例如新增存储设备,就利用事件中的内容创建出新的Disk,调用disk->create()方法;设备被移除了,VolumeManager就负责移除对应的Disk。
system\vold\Disk.cpp:
*
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);
//创建设备节点
mSkipDiskChangedUevent = false;
mShared = false;
}
*
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
//①*调用notifyEvent方法,通知DiskCreated事件
readMetadata();
//②读取分区数据,创建Volume
readPartitions();
return OK;
}
在create方法里调用notifyEvent通知DiskCreated事件,然后还有readMetadata方法创建Volume。
status_t Disk::readMetadata() {
//读取设备信息
...
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
return OK;
}
status_t Disk::readPartitions() {
...
createPublicVolume(partDevice);
...
createPrivateVolume(partDevice, partGuid);
...
}
读取分区数据这一部分代码阅读难度较大,而且代码保持了安卓源码的内容,即没有MTK或者360在这里有任何修改的地方。所以了解到代码最终根据不同情况调用了两个函数:createPublicVolume和createPrivateVolume,所以可以将关注重点放在createPublicVolume和createPrivateVolume上。而createPrivateVolume和createPublicVolume类似:
*
void Disk::createPublicVolume(dev_t device) {
auto vol = std::shared_ptr(new PublicVolume(device));
//获取PublicVolume实例
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());
if (major(mDevice) == android::vold::Disk::kMajorBlockMmc) {
if (minor(mDevice) == kMinorBlockEMMC) {
vol->setStorageType(android::vold::VolumeBase::StorageType::kPhoneStorage);
}
else {
vol->setStorageType(android::vold::VolumeBase::StorageType::kExternalSD);
}
}
if (major(mDevice) == kMajorBlockLoop && minor(mDevice) == kMinorBlockFon) {
vol->setStorageType(android::vold::VolumeBase::StorageType::kPhoneStorage);
}
vol->create();
//调用PublicVolume的create()方法
}
这里获取PublicVolume实例以后,调用了PublicVolume的create()方法,这个方法在之前分析过,用来创建一个新的的挂载设备。
在分析创建Disk和Volume的代码的过程中,注意到1行实际工作后,均会调用notifyEvent函数。这是一个发送通知消息的函数:
*
void Disk::notifyEvent(int event, const std::string& value) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
}
获取单例VolumeManager对象,然后使用getBroadcaster()方法获取到与VolumeManager对象建立联系的SocketListener对象,再调用其sendBroadcast()方法。
core\libsysutils\src\SocketListener.cpp:
*
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
SocketClientCollection safeList;
/* Add all active clients to the safe list first */
safeList.clear();
//清理SocketClient安全列表
pthread_mutex_lock(&mClientsLock);
//函数锁,阻塞线程
SocketClientCollection::iterator i;
for (i = mClients->begin(); i != mClients->end(); ++i) {
//将SocketListener当前所有的SocketClient均加入到safeList;对于Vold进程而言,它的client只有MountService对应的socket
SocketClient* c = *i;
c->incRef();
safeList.push_back(c);
//添加
}
pthread_mutex_unlock(&mClientsLock);
//函数解锁
while (!safeList.empty()) {
/* Pop the first item from the list */
i = safeList.begin();
SocketClient* c = *i;
safeList.erase(i);
// broadcasts are unsolicited and should not include a cmd number
if (c->sendMsg(code, msg, addErrno, false)) {
//遍历,调用SockClient的sendMSg方法发送消息
SLOGW("Error sending broadcast (%s)", strerror(errno));
}
c->decRef();
}
}
关于SockClient的sendMSg方法:
*
int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
return sendMsg(code, msg, addErrno, mUseCmdNum);
}
*
int SocketClient::sendMsg(int code, const char *msg, bool addErrno, bool useCmdNum) {
char *buf;
int ret = 0;
if (addErrno) {
if (useCmdNum) {
ret = asprintf(&buf, "%d %d %s (%s)", code, getCmdNum(), msg, strerror(errno));
} else {
ret = asprintf(&buf, "%d %s (%s)", code, msg, strerror(errno));
}
} else {
if (useCmdNum) {
ret = asprintf(&buf, "%d %d %s", code, getCmdNum(), msg);
} else {
ret = asprintf(&buf, "%d %s", code, msg);
}
}
// Send the zero-terminated message
if (ret != -1) {
ret = sendMsg(buf);
free(buf);
}
return ret;
}
*
int SocketClient::sendMsg(const char *msg) {
// Send the message including null character
if (sendData(msg, strlen(msg) + 1) != 0) {
SLOGW("Unable to send msg '%s'", msg);
return -1;
}
return 0;
}
*
int SocketClient::sendData(const void *data, int len) {
struct iovec vec[1];
vec[0].iov_base = (void *) data;
vec[0].iov_len = len;
pthread_mutex_lock(&mWriteMutex);
int rc = sendDataLockedv(vec, 1);
if (strlen((char *)data) > 0)
SLOGD("SocketClient sendData done: %s", (unsigned char *)data);
pthread_mutex_unlock(&mWriteMutex);
return rc;
}
*
int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) {
...
for (;;) {
ssize_t rc = TEMP_FAILURE_RETRY(
writev(mSocket, iov + current, iovcnt - current));
//写入信息
...
}
...
}
调用sendMsg方法经过层层跳转,到sendDataLockedv方法中,往Socket中写入信息,而现在就能想到将由MountService来处理socket中的数据。
3、与Android框架的交互——MountService接收Vold的挂载消息
MountService作为SystemServer中的一个Binder服务,它的作用是让用户进程通过它的接口对存储设备进行各种操作,包括mount、unmount、format等,它通过把命令发送到vold进程中,由vold进程来负责完成。MountService也是在SystemServer中启动,它的构造函数及其启动如下:
frameworks\base\services\core\java\com\android\server\MountService.java:
class MountService extends IMountService.Stub
implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
...
/**
* Constructs a new MountService instance
*
* @param context Binder context for this service
*/
public MountService(Context context) {
sSelf = this;
mContext = context;
mCallbacks = new Callbacks(FgThread.get().getLooper());
mLockPatternUtils = new LockPatternUtils(mContext);
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
//获得PackageManagerService的应用
HandlerThread hthread = new HandlerThread(TAG);
//创建消息处理线程
hthread.start();
mHandler = new MountServiceHandler(hthread.getLooper());
...
/*
* Create the connection to vold with a maximum queue of twice the
* amount of containers we'd ever expect to have. This keeps an
* "asec list" from blocking a thread repeatedly.
*/
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
null);
//创建和vold连接的NativeDaemonConnector对象,第一个参数传入回调接口,第二参数指明通信的server端
mConnector.setDebug(true);
mConnector.setWarnIfHeld(mLock);
mConnectorThread = new Thread(mConnector, VOLD_TAG);
//创建一个线程处理NativeDaemonConnector对象和底层的vold进程进行socket通信
...
final IntentFilter userFilter = new IntentFilter();
//监听用户变化的Intent
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
userFilter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
...
}
private void start() {
mConnectorThread.start();
//启动线程
...
}
...
}
NativeDaemonConnector对象用于和底层的vold进程进行socket通信,它的构造方法如下:
frameworks\base\services\core\java\com\android\server\NativeDaemonConnector.java:
*
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
FgThread.get().getLooper());
}
* NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
Looper looper) {
mCallbacks = callbacks;
//MountService对象的引用
mSocket = socket;
//String类型
mResponseQueue = new ResponseQueue(responseQueueSize);
mWakeLock = wl;
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
mLooper = looper;
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
}
NativeDaemonConnector的构造方法对成员变量进行了初始化。这里的mCallbacks是MountService对象的引用,即构造NativeDaemonConnector对象时的“this”;mSocket是一个String类型,构造NativeDaemonConnector对象时传入的参数是“vold”
MountService构造中启动线程的方法,即NativeDaemonConnector类的run()方法:
@Override
* public void run() {
mCallbackHandler = new Handler(mLooper, this);
while (true) {
try {
listenToSocket();
//调用listenToSocket()方法
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
//出现错误即休眠一段时间
}
}
}
run()方法进入了一个无限循环,反复调用listenToSocket()方法。
*
private void listenToSocket() throws IOException {
LocalSocket socket = null;
try {
socket = new LocalSocket();
LocalSocketAddress address = determineSocketAddress();
//得到socket的地址
socket.connect(address);
//连接vold进程中的socket
InputStream inputStream = socket.getInputStream(); //得到input对象
synchronized (mDaemonLock) {
mOutputStream = socket.getOutputStream();
//得到output对象
}
mCallbacks.onDaemonConnected();
//调用MountService的onDaemonConnected()方法
FileDescriptor[] fdList = null;
byte[] buffer = new byte[BUFFER_SIZE];
int start = 0;
while (true) {
//进入一个无限循环
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
//从socket中读取数据,没有数据时线程会挂起
...
//错误处理
// Add our starting point to the count and reset the start.
count += start;
start = 0;
for (int i = 0; i < count; i++) {
if (buffer[i] == 0) {
//每条vold发送的消息都是以0结尾的字符串
// Note - do not log this raw message since it may contain
// sensitive data
final String rawEvent = new String(
buffer, start, i - start, StandardCharsets.UTF_8);
//获取命令
boolean releaseWl = false;
try {
final NativeDaemonEvent event =
NativeDaemonEvent.parseRawEvent(rawEvent, fdList);
//解析命令
log("RCV <- {" + event + "}");
if (event.isClassUnsolicited()) {
// TODO: migrate to sending NativeDaemonEvent instances
if (mCallbacks.onCheckHoldWakeLock(event.getCode())
&& mWakeLock != null) {
//调用MountService的onCheckHoldWakeLock方法来检查处理该消息时是否要禁止系统休眠
mWakeLock.acquire();
//禁止系统休眠
releaseWl = true;
//解除休眠的标志,消息处理完之后会解除休眠
}
Message msg = mCallbackHandler.obtainMessage(
event.getCode(), uptimeMillisInt(), 0, event.getRawEvent());
//如果收到的是底层的通知消息,转发给MountService
if (mCallbackHandler.sendMessage(msg)) {
releaseWl = false;
//没有发生系统休眠,不需要进行解除休眠操作
}
} else {
mResponseQueue.add(event.getCmdNumber(), event);
//如果收到的是返回结果,放到mResponseQueue中
}
} catch (IllegalArgumentException e) {
log("Problem parsing message " + e);
} finally {
if (releaseWl) {
mWakeLock.release();
}
}
start = i + 1;
}
}
...
}
} catch (IOException ex) {
loge("Communications error: " + ex);
throw ex;
} finally {
//执行关闭socket操作
synchronized (mDaemonLock) {
if (mOutputStream != null) {
try {
loge("closing stream for " + mSocket);
mOutputStream.close();
} catch (IOException e) {
loge("Failed closing output stream: " + e);
}
mOutputStream = null;
}
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
loge("Failed closing socket: " + ex);
}
}
}
listenToSocket()调用determineSocketAddress()方法来得到vold中的socket地址,并创建LocalSocketAddress对象用于监听。和Vold进程中的socket连接后,进入一个无限循环,在循环中读取socket中的数据,收到的数据格式是以0结尾的字符串。parseRawEvent()将其解析成NativeDaemonEvent对象。
从vold中收到的消息有两种,一种是从vold进程中主动发送的通知消息,例如这里sdcard挂载的消息;另一种是对MountService发往vold进程消息的回复,也就是发给vold消息的返回结果。对于这两种消息,通过方法isClassUnsolicited()来进行区分,如果是vold主动发送的消息,则通过mCallbackHandler把消息对象发送出去。如果是回复消息,先放到mResponseQueue队列中,在NativeDaemonConnector的execute()方法结束时会把消息作为返回值返回。
mCallbackHandler发送的消息会在NativeDaemonConnector的方法handleMessage()中处理:
@Override
* public boolean handleMessage(Message msg) {
final String event = (String) msg.obj;
final int start = uptimeMillisInt();
final int sent = msg.arg1;
try {
if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {
//调用MountService的onEvent函数进行处理
log(String.format("Unhandled event '%s'", event));
}
} catch (Exception e) {
loge("Error handling '" + event + "': " + e);
} finally {
if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) {
//如果处理的消息是需要禁止系统休眠的,前面已经禁止,这里解禁
mWakeLock.release();
}
final int end = uptimeMillisInt();
if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) {
loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent));
}
if (end > start && end - start > WARN_EXECUTE_DELAY_MS) {
loge(String.format("NDC event {%s} took too long: %dms", event, end - start));
}
}
return true;
}
通过调用MountService的onEvent函数,这样从vold中发送来的消息就传递到了MountService中。
/**
* Callback from NativeDaemonConnector
*/
@Override
*
public boolean onEvent(int code, String raw, String[] cooked) {
synchronized (mLock) {
return onEventLocked(code, raw, cooked);
//调用onEventLocked()函数
}
}
* private boolean onEventLocked(int code, String raw, String[] cooked) {
switch (code) {
case VoldResponseCode.DISK_CREATED: {
//处理DISK_CREATED创建成功事件
Slog.d(TAG, "DISK_CREATED");
if (cooked.length != 3) break;
final String id = cooked[1];
int flags = Integer.parseInt(cooked[2]);
if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
|| mForceAdoptable) {
flags |= DiskInfo.FLAG_ADOPTABLE;
}
mDisks.put(id, new DiskInfo(id, flags));
Slog.d(TAG, "create diskInfo=" + mDisks.get(id));
isDiskInsert = true;
break;
}
...
case VoldResponseCode.VOLUME_CREATED: {
处理VOLUME_CREATED创建成功事件
Slog.d(TAG, "VOLUME_CREATED");
final String id = cooked[1];
final int type = Integer.parseInt(cooked[2]);
final String diskId = TextUtils.nullIfEmpty(cooked[3]);
final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
final DiskInfo disk = mDisks.get(diskId);
final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
mVolumes.put(id, vol);
onVolumeCreatedLocked(vol);
//调用了onVolumeCreatedLocked()方法
Slog.d(TAG, "create volumeInfo=" + mVolumes.get(id));
break;
...
}
}
return true;
}
MountService收到DISK_CREATED消息后,仅会记录DiskInfo;收到VOLUME_CREATED消息后,还需要调用onVolumeCreatedLocked函数作进一步地处理。
*
private void onVolumeCreatedLocked(VolumeInfo vol) {
if (mPms.isOnlyCoreApps()) {
Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
return;
}
Slog.d(TAG, "onVolumeCreatedLocked, volumeInfo=" + vol);
if (vol.type == VolumeInfo.TYPE_EMULATED) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
Slog.d(TAG, "privateVol=" + privateVol);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
&& VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
//handler发送消息
} else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
//handler发送消息
}
} else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
...
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
//handler发送消息
} else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
//handler发送消息
} else {
Slog.d(TAG, "Skipping automatic mounting of " + vol);
}
}
之后走到Handler处理H_VOLUME_MOUNT消息。
*
class MountServiceHandler extends Handler {
public MountServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case H_VOLUME_MOUNT: {
Slog.i(TAG, "H_VOLUME_MOUNT");
final VolumeInfo vol = (VolumeInfo) msg.obj;
if (isMountDisallowed(vol)) {
Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
break;
}
int rc = StorageResultCode.OperationSucceeded;
try {
mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
vol.mountUserId);
//执行mount(挂载)命令
} catch (NativeDaemonConnectorException ignored) {
rc = ignored.getCode();
Slog.w(TAG, "mount volume fail, ignored=" + ignored);
}
if (rc == StorageResultCode.OperationSucceeded) {
VolumeInfo curVol = null;
synchronized (mLock) {
curVol = mVolumes.get(vol.getId());
}
if (isShowDefaultPathDialog(curVol)) {
showDefaultPathDialog(curVol);
}
} else {
// if mount fail, for other volume mount operation
// should not marked as disk insert
isDiskInsert = false;
Slog.w(TAG, "mount volume fail, vol=" + vol
+ ", return code=" + rc);
}
break;
}
...
}
}
}
会调用NativeDaemonConnector的execute方法,经过层层调用,跳转到executeForList方法。
public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException {
return execute(cmd.mCmd, cmd.mArguments.toArray());
}
public NativeDaemonEvent execute(String cmd, Object... args)
throws NativeDaemonConnectorException {
return execute(DEFAULT_TIMEOUT, cmd, args);
}
public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args);
if (events.length != 1) {
throw new NativeDaemonConnectorException(
"Expected exactly one response, but received " + events.length);
}
return events[0];
}
public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException {
return executeForList(cmd.mCmd, cmd.mArguments.toArray());
}
public NativeDaemonEvent[] executeForList(String cmd, Object... args)
throws NativeDaemonConnectorException {
return executeForList(DEFAULT_TIMEOUT, cmd, args);
}
* public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
loge("Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)));
}
final long startTime = SystemClock.elapsedRealtime();
final ArrayList events = Lists.newArrayList();
final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
final int sequenceNumber = mSequenceNumber.incrementAndGet();
makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);
final String rawCmd = rawBuilder.toString();
final String logCmd = logBuilder.toString();
log("SND -> {" + logCmd + "}");
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
//往Socket 输出流写入命令
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
NativeDaemonEvent event = null;
do {
event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
if (event == null) {
loge("timed-out waiting for response to " + logCmd);
throw new NativeDaemonTimeoutException(logCmd, event);
}
if (VDBG) log("RMV <- {" + event + "}");
events.add(event);
} while (event.isClassContinue());
final long endTime = SystemClock.elapsedRealtime();
if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
}
if (event.isClassClientError()) {
throw new NativeDaemonArgumentException(logCmd, event);
}
if (event.isClassServerError()) {
throw new NativeDaemonFailureException(logCmd, event);
}
return events.toArray(new NativeDaemonEvent[events.size()]);
}
往Socket写入输出流之后,Vold中FrameWorkListener的onDataAvailable会收到。
4、与Android框架的交互——FrameWorkListener接收MountService的消息命令
Vold进程在main函数中创建出了CommandListener,然后调用了CommandListener的startListener函数。
CommandListener的构造函数:
system\vold\CommandListener.cpp:
*
CommandListener::CommandListener() :
FrameworkListener("vold", true) {
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new FstrimCmd());
registerCmd(new AppFuseCmd());
#ifndef MTK_EMULATOR_SUPPORT
registerCmd(new USBCmd());
#endif
}
在CommandListener的构造函数中,调用了父类的构造函数,同时利用其父类的registerCmd函数创建并注册了一些Cmd对象。
system\core\libsysutils\src\FrameworkListener.cpp:
*
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
init(socketName, withSeq);
}
*
void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
mCommands = new FrameworkCommandCollection();
errorRate = 0;
mCommandCount = 0;
mWithSeq = withSeq;
mSkipToNextNullByte = false;
}
*
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
mCommands->push_back(cmd);
//将注册的Command保存到列表中
}
与之前分析NetlinkManager一样,CommandListener最终继承自SocketListener。不过与NetlinkManager不同的是,CommandListener传入到SocketListener的mListen参数为true,这意味着CommandListener中的socket将作为服务端存在。从FrameworkListener的registerCmd函数来看,FrameworkListener仅仅是保存了新创建的Cmd对象。这里采用了设计模式中的Command模式,每个命令的处理函数都是runCommand。
当Vold进程创建出CommandListener后,同样调用了CommandListener的startListener函数。根据继承关系,最终将会调用到SocketListener的startListener函数。在分析NetlinkManager时,已经分析过SocketListener的startListener函数。在startListener函数中将启动一个工作线程,以监听对应socket的数据。
此处CommandListener监听的是init进程创建出Vold进程后,Vold进程创建的名为“vold”的socket,并且该socket是作为服务端存在的。当服务端收到注册请求后,将生成对应的SocketClient对象。然后,工作线程就可以监听SocketClient是否有数据到来。“vold”的客户端是MountService。与之前分析的一样,当工作线程收到客户端数据时,将调用子类的onDataAvailable函数进行处理。
此时SocketListener的子类是FrameworkListener:
*
bool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[CMD_BUF_SIZE];
int len;
len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
//读取socket消息
if (len < 0) {
SLOGE("read() failed (%s)", strerror(errno));
return false;
} else if (!len) {
return false;
} else if (buffer[len-1] != '\0') {
SLOGW("String is not zero-terminated");
android_errorWriteLog(0x534e4554, "29831647");
c->sendMsg(500, "Command too large for buffer", false);
mSkipToNextNullByte = true;
return false;
}
int offset = 0;
int i;
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {
/* IMPORTANT: dispatchCommand() expects a zero-terminated string */
if (mSkipToNextNullByte) {
mSkipToNextNullByte = false;
} else {
dispatchCommand(c, buffer + offset);
//根据消息内容,派发命令
}
offset = i + 1;
}
}
mSkipToNextNullByte = false;
return true;
}
在onDataAvailable方法里会先读取Socket消息,然后分发命令。
*
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
...
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
//分发命令
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand())) {
//匹配命令
if (c->runCommand(cli, argc, argv)) {
//执行命令
SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
...
}
dispatchCommand会匹配相应的命令然后再执行,最后调用了FrameworkCommand的runCommand方法,之前在CommandListener的构造方法里注册的这些指令,就是FrameWorkCommand类型。这里插入SD卡是挂载指令,即VolumeCmd指令,会进入到VolumeCmd的runCommand方法。
*
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
...
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard lock(vm->getLock());
// TODO: tease out methods not directly related to volumes
std::string cmd(argv[1]);
static bool isFirstResetCommand = true;
if (cmd == "reset") {
...
} else if (cmd == "mount" && argc > 2) {
// mount [volId] [flags] [user]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
//通过VolumeManager获取到volumebase实例
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);
//设置flags
vol->setMountUserId(mountUserId);
//设置userId
static bool isMountSecondaryStorageWhenBoot = true;
if (isMountSecondaryStorageWhenBoot && !(mountFlags & android::vold::VolumeBase::MountFlags::kPrimary)) {
isMountSecondaryStorageWhenBoot = false;
std::thread(&do_mount_secondary_volume_when_boot, id, cli).detach();
return 0;
}
int res = vol->mount();
//执行真正的挂载操作
if (res) {
char auto_format_intsd[PROPERTY_VALUE_MAX] ;
property_get("persist.vold.auto_format_intsd", auto_format_intsd, "1");
SLOGI("persist.vold.auto_format_intsd=%s", auto_format_intsd);
if (!strcmp(auto_format_intsd, "1")) {
auto disk = vm->findDisk(vol->getDiskId());
if (disk != nullptr) {
if ((major(disk->getDevice()) == android::vold::Disk::kMajorBlockMmc &&
minor(disk->getDevice()) == kMinorBlockEMMC)||
(major(disk->getDevice()) == android::vold::Disk::kMajorBlockLoop &&
minor(disk->getDevice()) == android::vold::Disk::kMinorBlockFon)) {
SLOGI("*** The internal sd is not formatted yet. Try to format it");
if(!vol->format("auto")) {
property_set("persist.vold.auto_format_intsd", "0");
res = vol->mount();
}
}
}
}
}
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
return sendGenericOkFail(cli, res);
//发送应答消息给MountService
}
...
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
获取到volumebase会执行其中的实际的mount操作。
*
status_t VolumeBase::mount() {
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";
return -EBUSY;
}
setState(State::kChecking);
status_t res = OK;
LOG(WARNING) << getId() << " VolumeManager::Instance()->mSkipUmountForResetCommand: " << VolumeManager::Instance()->mSkipUmountForResetCommand;
if (isMountpointMounted(getPath().c_str())) {
LOG(WARNING) << getId() << " mPath: " << mPath << " is mounted. skip doMount()";
setInternalPath(mInternalPath);
setPath(mPath);
}
else {
res = doMount();
//由子类doMount实现实际挂载操作
}
if (res == OK) {
setState(State::kMounted);
createRemoveStorageTypeSettings(true);
} else {
setState(State::kUnmountable);
if (mStorageType == StorageType::kExternalSD) {
power_control_for_external_sd(MSDC_SD_POWER_OFF);
}
}
return res;
}
最后子类doMount实现实际挂载操作。
*
status_t PublicVolume::doMount() {
// TODO: expand to support mounting other filesystems
LOG(VERBOSE) << "PublicVolume::doMount()";
readMetadata();
LOG(VERBOSE) << getId() << " mFsType: " << mFsType;
if (mFsType != "vfat" && mFsType != "exfat" && mFsType != "ntfs") {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
if (mFsType == "vfat")
if (vfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
if (mFsType == "exfat") {
if (!exfat::IsSupported()) {
PLOG(ERROR) << "exfat is not supported on this system";
return -EIO;
}
if (exfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
}
if (mFsType == "ntfs") {
if (!ntfs::IsSupported()) {
PLOG(ERROR) << "ntfs is not supported on this system";
return -EIO;
}
if (ntfs::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
}
// Use UUID as stable name, if available
std::string stableName = getId();
if (!mFsUuid.empty()) {
stableName = mFsUuid;
}
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
setInternalPath(mRawPath);
if (getMountFlags() & MountFlags::kVisible) {
setPath(StringPrintf("/storage/%s", stableName.c_str()));
} else {
setPath(mRawPath);
}
if (isMountpointMounted(getPath().c_str())) {
PLOG(ERROR) << "skip mount";
return OK;
}
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create mount points";
return -errno;
}
if (mFsType == "ntfs") {
if (ntfs::Mount(mDevPath, mRawPath, false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
PLOG(ERROR) << getId() << " ntfs: failed to mount " << mDevPath;
return -EIO;
}
else
LOG(VERBOSE) << "ntfs: mount succeed " << mDevPath;
}
else if (mFsType == "exfat") {
if (exfat::Mount(mDevPath, mRawPath, false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
PLOG(ERROR) << getId() << " exfat: failed to mount " << mDevPath;
return -EIO;
}
else
LOG(VERBOSE) << "exfat: mount succeed " << mDevPath;
}
else if (mFsType == "vfat") {
if (vfat::Mount(mDevPath, mRawPath, false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
PLOG(ERROR) << getId() << " vfat: failed to mount " << mDevPath;
return -EIO;
}
}
if (getMountFlags() & MountFlags::kPrimary) {
initAsecStage();
}
if (!(getMountFlags() & MountFlags::kVisible)) {
// Not visible to apps, so no need to spin up FUSE
return OK;
}
if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create FUSE mount points";
return -errno;
}
dev_t before = GetDevice(mFuseWrite);
if (!(mFusePid = fork())) {
if (getMountFlags() & MountFlags::kPrimary) {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
"-U", std::to_string(getMountUserId()).c_str(),
"-w",
mRawPath.c_str(),
stableName.c_str(),
NULL)) {
PLOG(ERROR) << "Failed to exec";
}
} else {
/* 360OS begin */
/* add for cts */
char value[PROPERTY_VALUE_MAX];
property_get("persist.qiku.ctstest", value, "0");
if (atoi(value) == 1) {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
"-U", std::to_string(getMountUserId()).c_str(),
mRawPath.c_str(),
stableName.c_str(),
NULL)) {
PLOG(ERROR) << "Failed to exec";
}
} else {
/* 360OS end */
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
"-U", std::to_string(getMountUserId()).c_str(),
/* 360OS begin */
/* add for grant write permission to app */
"-w",
/* 360OS end */
mRawPath.c_str(),
stableName.c_str(),
NULL)) {
PLOG(ERROR) << "Failed to exec";
}
/* 360OS begin */
/* add for cts */
}
/* 360OS end */
}
LOG(ERROR) << "FUSE exiting";
_exit(1);
}
if (mFusePid == -1) {
PLOG(ERROR) << getId() << " failed to fork";
return -errno;
}
while (before == GetDevice(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
}
return OK;
}
至此,挂载操作完成。