看了很长时间Vold存储模块的相关知识,也深入的研究一段时间的Android源码,打算把自己看过的经验之贴、参考资料和自己的一些见解,以帖子的形式发出来,供有兴趣的同仁们参考,有不对的地方请指正,我们相互交流。
1.1 vold的原理与机制分析
1.1.1 Vold 架构
从上图中可知:
· Vold中的NetlinkManager模块接收来自Linux内核的uevent消息。例如SD卡的插拔等动作都会引起Kernel向NM发送uevent消息。
· NetlinkManager将这些消息转发给VolumeManager模块。VolumeManager会对应做一些操作,然后把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相关的处理命令给VolumeManager做进一步的处理。例如待SD卡插入后,VolumeManager会将来自NetlinkManager的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”指令给Vold,指示它挂载这个SD卡。
· CommandListener模块内部封装了一个Socket用于跨进程通信。它在Vold进程中属于监听端(即是服务端),而它的连接端(即客户端)则是MountService。它一方面接收来自MountService的控制命令(例如卸载存储卡、格式化存储卡等),另一方面VolumeManager和NetlinkManager模块又会通过它,将一些信息发送给MountService。
1.1.2初识Vold
下面来初步的认识Vold,代码在system\vold\main.cpp
int main() {
mkdir("/dev/block/vold", 0755); //创建一个目录/dev/block/vold
//创建一个VolumeManager对象,该对象为单例模式
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
exit(1);
};
//创建一个NetlinkManager对象,该对象为单例模式
if (!(nm = NetlinkManager::Instance())) {
SLOGE("Unable to create NetlinkManager");
exit(1);
};
//创建一个CommandListener对象
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
//启动VolumeManager
if (vm->start()) {
SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
exit(1);
}
//根据fstab配置文件初始化VolumeManager
if (process_config(vm)) {
SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
}
//启动NetlinkManager对象
if (nm->start()) {
SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
//通过往/sys/block目录下对应的uevent文件写“add\n”来触发内核发送Uevent消息
coldboot("/sys/block");
//启动CommandListener
if (cl->startListener()) {
SLOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
}
1.2 NetlinkManager模块的分析
1.2.1 NetlinkManager架构流程图
1.2.2 start的分析
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
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;
// 创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件
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_RECBUFFORCE option: %s", strerror(errno));
return -1;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
return -1;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
return -1;
}
// 利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,
// NetlinkListener又继承了类SocketListener
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) { //启动NetlinkHandler
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
return -1;
}
return 0;
}
NetlinkHandler构造NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
继承父类NetlinkListener::NetlinkListener(int socket) :
SocketListener(socket, false) {
mFormat = NETLINK_FORMAT_ASCII;
}
接着调用的start()函数,也是最终实现在SockListener的startListener()。
int NetlinkHandler::start() {
return this->startListener();
}
int SocketListener::startListener() {
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;
}
}
if (mListen && listen(mSock, 4) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
mClients->push_back(new SocketClient(mSock, false));
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;
}
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
void SocketListener::runListener() {
SocketClientCollection *pendingList = new SocketClientCollection();
while(1) { // 死循环,一直监听
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
int max = -1;
FD_ZERO(&read_fds); //清空文件描述符集read_fds
if (mListen) {
max = mSock;
FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds
}
FD_SET(mCtrlPipe[0], &read_fds); //添加管道的读取端文件描述符到read_fds
if (mCtrlPipe[0] > max)
max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock); //对容器mClients的操作需要加锁
for (it = mClients->begin(); it != mClients->end(); ++it) {
int fd = (*it)->getSocket();
FD_SET(fd, &read_fds); ////遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds
if (fd > max)
max = fd;
}
pthread_mutex_unlock(&mClientsLock);
// 等待文件描述符中某一文件描述符或者说socket有数据到来
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
SLOGE("select failed (%s)", strerror(errno));
sleep(1);
continue;
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds))
break;
if (mListen && FD_ISSET(mSock, &read_fds)) { //监听套接字处理
struct sockaddr addr;
socklen_t alen;
int c;
do {
alen = sizeof(addr);
c = accept(mSock, &addr, &alen); //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器
} 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));
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) {
int fd = (*it)->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pendingList->push_back(*it);
}
}
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 and our sockets are
* connection-based, remove and destroy it */
// ****** onDataAvailable在NetlinkListener中实现*********
if (!onDataAvailable(c) && mListen) {
/* Remove the client from our array */
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
if (*it == c) {
mClients->erase(it);
break;
}
}
pthread_mutex_unlock(&mClientsLock);
/* Remove our reference to the client */
c->decRef();
}
}
}
delete pendingList;
}
SocketListener::runListener是线程真正执行的函数:mListen成员用来判定是否监听套接字,Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用函数onDataAvailable读取数据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)); //从socket中读取event信息
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)) { //调用NetlinkEvent解析event
SLOGE("Error decoding NetlinkEvent");
} else {
onEvent(evt); //传递event给子类NetlinkHandler处理
}
delete evt;
return true;
}
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")) { //EVENT为block类型
int action = evt->getAction();
vm->updatePullOutState(evt);
vm->setHotPlug(true);
vm->handleBlockEvent(evt); //把event交给<span style="font-family: Arial; line-height: 26px;">VolumeManager处理</span>
vm->setHotPlug(false);
}
1.2.3 NM模块的总结
1.3 VolumeManager模块的分析
1.3.1 Vold使用VM模块的流程
调用Instance创建一个VM对象。
调用setBroadcaster设置CL对象
调用start启动VM。
调用process_config配置VM。
1.3.2 VM的创建
VolumeManager *VolumeManager::Instance() {
if (!sInstance)
sInstance = new VolumeManager();
return sInstance;
}
VolumeManager::VolumeManager() {
mDebug = false;
mVolumes = new VolumeCollection(); //一个容器,保存<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 15px; line-height: 35px;">Volume的集合</span>
mActiveContainers = new AsecIdCollection();
mBroadcaster = NULL; //指向socketlisten,用于发送挂载事件
mUmsSharingCount = 0;
mSavedDirtyRatio = -1;
mUmsDirtyRatio = dirtyRatio();
mVolManagerDisabled = 0;
mIsHotPlug= false;
mUseBackupContainers =false;
mIsFirstBoot = false;
mIpoState = State_Ipo_Start;
}
1.3.3 VM的启动
int VolumeManager::start() {
return 0; //<span style="font-family: Arial; font-size: 14px; line-height: 26px;">VM的启动什么也没有做</span>
}
1.3.4 process_config分析
static int process_config(VolumeManager *vm)
{
char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
fstab = fs_mgr_read_fstab(fstab_filename); //读取fstab文件
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);
if (dv->addPath(fstab->recs[i].blk_device)) {
SLOGE("Failed to add devpath %s to volume %s",
fstab->recs[i].blk_device, fstab->recs[i].label);
goto out_fail;
}
vm->addVolume(dv); //添加到volumemanager容器
}
}
}
fstab配置文件# Android fstab file.
#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags>
# The filesystem that contains the filesystem checker binary (typically /system) cannot
# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK
/devices/platform/mtk-msdc.0/mmc_host auto vfat defaults voldmanaged=sdcard0:emmc@fat,noemulatedsd
/devices/platform/mtk-msdc.1/mmc_host auto vfat defaults voldmanaged=sdcard1:auto
1.3.5 DirectVolume分析
DirectVolume::DirectVolume(VolumeManager *vm,const char *label,
const char*mount_point, int partIdx) :
Volume(vm, label, mount_point) {//初始化基类
/*
注意其中的参数:
label为”sdcard”,mount_point为”/mnt/sdcard”,partIdx为1
*/
mPartIdx = partIdx;
//PathCollection定义为typedef android::List<char *> PathCollection
//其实就是一个字符串list
mPaths= new PathCollection();
for(int i = 0; i < MAX_PARTITIONS; i++)
mPartMinors[i] = -1;
mPendingPartMap = 0;
mDiskMajor = -1; //存储设备的主设备号
mDiskMinor = -1; //存储设备的次设备号,一个存储设备将由主次两个设备号标识。
mDiskNumParts = 0;
//设置状态为NoMedia
setState(Volume::State_NoMedia);
}
//再来看addPath函数,它主要目的是添加设备在sysfs中的路径,
int DirectVolume::addPath(const char *path) {
mPaths->push_back(strdup(path));
return0;
}
addPath把和某个存储卡接口相关的设备路径与这个DirectVolume绑定到一起,并且这个设备路径和Uevent中的DEVPATH是对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。当然手机上目前只有一个存储卡接口,所以Vold也只有一个DirectVolume。1.3.6 VM与NM交互
void VolumeManager::handleBlockEvent(NetlinkEvent*evt) {
constchar *devpath = evt->findParam("DEVPATH");
/*
前面在process_config中构造的DirectVolume对象保存在了mVolumes中,它的定义如下:
typedef android::List<Volume *>VolumeCollection,也是一个列表。
注意它保存的是Volume指针,而我们的DirectVolume是从Volume派生的
*/
VolumeCollection::iterator it;
boolhit = false;
for (it = mVolumes->begin(); it !=mVolumes->end(); ++it) {
//调用每个Volume的handleBlockEvent事件,实际上将调用
//DirectVolume的handleBlockEvent函数。
if(!(*it)->handleBlockEvent(evt)) {
hit = true;
break;
}
}
}
int DirectVolume::handleBlockEvent(NetlinkEvent*evt) {
constchar *dp = evt->findParam("DEVPATH");
PathCollection::iterator it;
//将Uevent的DEVPATH和addPath添加的路径进行对比,判断属不属于自己管理的范围。
for(it = mPaths->begin(); it != mPaths->end(); ++it) {
if(!strncmp(dp, *it, strlen(*it))) {
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)) {
......
}
if (!strcmp(devtype, "disk")) {
handleDiskAdded(dp, evt);//添加一个磁盘
} else {
/*
对于有分区的SD卡,先收到上面的“disk”消息,然后每个分区就会收到
一个分区添加消息。
*/
handlePartitionAdded(dp,evt);
}
} else if (action == NetlinkEvent::NlActionRemove) {
......
} else if (action == NetlinkEvent::NlActionChange) {
......
}
......
return 0;
}
}
errno= ENODEV;
return-1;
}
1.4 commandlisten模块分析
1.4.1 commandlisten构造
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
...
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
SLOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
构造函数/system/vold/CommandListener.cppCommandListener::CommandListener() :
FrameworkListener("vold", true) {
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new XwarpCmd());
registerCmd(new CryptfsCmd());
registerCmd(new FstrimCmd());
//M{
#ifndef MTK_EMULATOR_SUPPORT
registerCmd(new USBCmd());
#endif
registerCmd(new CDROMCmd());
//}M
#if defined (ENG_BUILD_ENG)
registerCmd(new SilkRoad());
#endif
}
构造一个父类FrameworkListenerFrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
init(socketName, withSeq);
}
void FrameworkListener::init(const char *socketName, bool withSeq) {
mCommands = new FrameworkCommandCollection();
errorRate = 0;
mCommandCount = 0;
mWithSeq = withSeq;
}
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
init(socketName, -1, listen, useCmdNum);
}
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();
}
1.4.2 Command注册
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
mCommands->push_back(cmd);
}
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
}
VoldCommand::VoldCommand(const char *cmd) :
FrameworkCommand(cmd) {
}
FrameworkCommand::FrameworkCommand(const char *cmd) {
mCommand = cmd;
}
将volume这个command注册到mCommands这个容器中之后,目的是当FrameworkListerer从SlocketListener接收到command的时候,会依据mCommands 中的command进行解析筛选判断分发,调用对应的command执行类
1.4.3 startListener的分析和数据处理
int SocketListener::startListener() {
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) {//获取socket的文件描述符,这里是获取Vold这个socket的
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, 4) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)//是否正常监听socket
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;
}
开启线程用于监听void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);//threadStart为static函数,上面开线程创建的时候传了this,这里需要转换一个一样bit位的SocketListener指针
me->runListener();//SocketListener真正的执行函数
pthread_exit(NULL);
return NULL;
}
对socket监听处理void SocketListener::runListener() {
SocketClientCollection *pendingList = new SocketClientCollection();//暂存mClients中的SocketClient
while(1) {
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
int max = -1;
FD_ZERO(&read_fds);//清空文件描述符集read_fds
if (mListen) {
max = mSock;
FD_SET(mSock, &read_fds);//如果正常的监听,这里就把之前获得的vold的文件描述符添加进去
}
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) {//遍历mClients,获取fd 添加到read_fds
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);
//linux下socket编程的select,这里检测read_fds集合里面是否有可读的,也就是有没有数据过来,没有数据的文件描述符会从read_fds中被剔除,这里的select设置time out为NULL,阻塞操作,直到read_fds集合中描述符有变化
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))//如果匿名管道有数据可读,就退出
break;
if (mListen && FD_ISSET(mSock, &read_fds)) {//如果是正常监听的 mListen 为true,然后mSock这个描述符有可读数据,就创建链接,新建异步处理的SocketClient加入到mClients容器,这里的mSock 是vold这个套接字的描述符
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) {//把上面有请求建立链接的Client加入到pendingList 容器中,后面处理
int fd = (*it)->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pendingList->push_back(*it);
}
}
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 and our sockets are
* connection-based, remove and destroy it */
if (!onDataAvailable(c) && mListen) {//调用到FrameworkListener 中onDataAvailable处理Socket事件
/* Remove the client from our array */
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
if (*it == c) {
mClients->erase(it);//处理完成之后,从容器中移除这次的监听到的SocketClient
break;
}
}
pthread_mutex_unlock(&mClientsLock);
/* Remove our reference to the client */
c->decRef();
}
}
}
delete pendingList;
}
SocketListener的核心处理函数是onDataAvailablebool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[255];
int len;
len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));//读Socket 内容保存到buffer
if (len < 0) {
SLOGE("read() failed (%s)", strerror(errno));
return false;
} else if (!len)
return false;
int offset = 0;
int i;
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {//一次传入一个字符串
<span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: rgb(240, 247, 254);"> //分发命令,最终会调用对应命令对象的runCommand进行函数处理。</span>
dispatchCommand(c, buffer + offset);
offset = i + 1;
}
}
return true;
} </span>
调用dispatchcommandvoid FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
FrameworkCommandCollection::iterator i;
int argc = 0;
char *argv[FrameworkListener::CMD_ARGS_MAX];
char tmp[255];
...//解析判断command buffer
for (i = mCommands->begin(); i != mCommands->end(); ++i) {//遍历之前register到FrameworkListener中的FrameworkCommand容器
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand())) {//其中有注册“Volume”,如果这里是Volume开头的command,那么就调用,Volume构造的时候所构造的父类FrameworkCommand中的runCommand函数
if (c->runCommand(cli, argc, argv)) {
SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
}
以Volume这个runcommand为例
/system/vold/CommandListener.cpp中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();//获取已经存在的VolumeManager实例
...
else if (!strcmp(argv[1], "mount")) {//判断command 内容
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
return 0;
}
rc = vm->mountVolume(argv[2]);//交给VolumeManager来对Volume进行操作
}
...
}
1.4.4 commandlisten 数据处理流程图
1.5 mountservice模块的介绍
1.5.1 mountservice构造
public MountService(Context context) {
mContext = context;
synchronized (mVolumesLock) {
readStorageListLocked(); // 解析/frameworks/base/core/res/res/xml/storage_list.xml保存volume到 MountService的list :mVolumes中
}
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
mHandlerThread = new HandlerThread("MountService");
mHandlerThread.start();
mHandler = new MountServiceHandler(mHandlerThread.getLooper());//新建消息处理handler
// Watch for user changes
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);//注册广播接收
// Watch for USB changes on primary volume
final StorageVolume primary = getPrimaryPhysicalVolume();
if (primary != null && primary.allowMassStorage()) {
mContext.registerReceiver(
mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
}
// Add OBB Action Handler to MountService thread.
mObbActionHandler = new ObbActionHandler(mHandlerThread.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);//创建 vold 的监听接收,用于接收system中Vold的socket消息
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();//启动线程,NativeDaemonConnector实现了Runnable接口,实现在 run中
// Add ourself to the Watchdog monitors if enabled.
if (WATCHDOG_ENABLE) {
Watchdog.getInstance().addMonitor(this);
}
}
1.5.2构造了NativeDaemonConnector用来接收来自下层的socket消息
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize) {
mCallbacks = callbacks; //回调
mSocket = socket; // socket名称
mResponseQueue = new ResponseQueue(responseQueueSize);//构建一个响应队列
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
}
开启监测线程的run方法public void run() {
HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); //TAG 为 VoldConnector,这里新建一个名为VoldConnector.CallbackHandler的消息处理线程,用于下面接收到vold 的socket之后的处理
thread.start();
mCallbackHandler = new Handler(thread.getLooper(), this); //创建handler 用于分发消息
while (true) {
try {
listenToSocket();// while 循环 监听socket
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
}
private void listenToSocket() throws IOException {
LocalSocket socket = null;
try {
socket = new LocalSocket(); //创建本地socket
LocalSocketAddress address = new LocalSocketAddress(mSocket,
LocalSocketAddress.Namespace.RESERVED);//获得服务端vold socket的地址
socket.connect(address);//连接
InputStream inputStream = socket.getInputStream();
synchronized (mDaemonLock) {
mOutputStream = socket.getOutputStream();
}//获取输入输出流
mCallbacks.onDaemonConnected();//回调,在MountService中执行,初始化一些Volume状态信息
byte[] buffer = new byte[BUFFER_SIZE];
int start = 0;
while (true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取数据到buffer
if (count < 0) {//连接断开,跳出当前while ,外部while循环 重新调用该函数连接
loge("got " + count + " reading with start = " + start);
break;
}
// 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) {
final String rawEvent = new String(
buffer, start, i - start, Charsets.UTF_8);
log("RCV <- {" + rawEvent + "}");
try {
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
rawEvent); //解析成event 保存
if (event.isClassUnsolicited()) { //判断event的code范围 code >= 600 && code < 700
// TODO: migrate to sending NativeDaemonEvent instances
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( //发送消息,把event交给handle来分发处理
event.getCode(), event.getRawEvent()));
} else {
mResponseQueue.add(event.getCmdNumber(), event);//加入到响应队列
}
} catch (IllegalArgumentException e) {
log("Problem parsing message: " + rawEvent + " - " + e);
}
start = i + 1;
}
}
在NativeDaemonConnector中的handle处理为:public boolean handleMessage(Message msg) {
String event = (String) msg.obj;
try {
if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { //回调到MountService 的onEent函数
log(String.format("Unhandled event '%s'", event));
}
} catch (Exception e) {
loge("Error handling '" + event + "': " + e);
}
return true;
}
MountService中onEventpublic 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) { //根据 Vold的Code 执行
/*
* 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.VolumeDiskInserted) ||
(code == VoldResponseCode.VolumeDiskRemoved) ||
(code == VoldResponseCode.VolumeBadRemoval))
...
if (code == VoldResponseCode.VolumeDiskInserted) { //如果接收到的是插入disk的消息,则执行挂载操作
new Thread() {
@Override
public void run() {
try {
int rc;
if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
}
} catch (Exception ex) {
Slog.w(TAG, "Failed to mount media on insertion", ex);
}
}
}.start();
}
}
1.5.3 MountService下发command
private int doMountVolume(String path) {
int rc = StorageResultCode.OperationSucceeded;
final StorageVolume volume;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
}
if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
try {
mConnector.execute("volume", "mount", path);// 调用到NativeDaemonConnector中的execute
}
NativeDaemonConnector的executepublic NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
throws NativeDaemonConnectorException {
final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final int sequenceNumber = mSequenceNumber.incrementAndGet();
final StringBuilder cmdBuilder =
new StringBuilder(Integer.toString(sequenceNumber)).append(' ');
final long startTime = SystemClock.elapsedRealtime();
makeCommand(cmdBuilder, cmd, args); //转换制作成标准的Command
final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */
log("SND -> {" + logCmd + "}");
cmdBuilder.append('\0');
final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //通过在listenToSocket中获取的输出流,写入转换好的sentCmd
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
}