Android4.4----Vold挂载管理分析USB挂载(二)
来源:互联网 发布:苹果录屏用什么软件 编辑:程序博客网 时间:2024/04/30 03:20
在上一篇Android4.4----Vold挂载管理分析(一)文章中我们大概的介绍了一下外挂设备的挂载流程,这里我们以USB的挂载为例,具体详细的分步骤分析!
一:kernel发出USB插入的uevent
这里我推荐一篇文章Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)是关于kernel如何检测USB设备的插入并通过Socket向上层发送uevent的,主要就是循环检测port端口,然后通过Socket向上层发送uevent的,这里我就不详细介绍了。
这里主要介绍Vold如何接受来自kernel层的uevent,然后传递给VolumeManager的,这就主要涉及到NetlinkManager了!
二:NetlinkManager
从Vold的主函数system\vold\main.cpp开始
NetlinkManager *nm;........ if (!(nm = NetlinkManager::Instance())) { SLOGE("Unable to create NetlinkManager"); exit(1); };...........nm->setBroadcaster((SocketListener *) cl);//用于命令交互.................. if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); }.............这里就是NetlinkManager的构造函数,new了一个NetlinkManager,然后调用nm->start()函数
在/system/vold/NetlinkManager.cpp中:
int NetlinkManager::start() { struct sockaddr_nl nladdr;//使用Netlink套接字与kerner通信 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; //创建 类型为 PF_NETLINK的套接字 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; } //绑定socket地址 if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { SLOGE("Unable to bind uevent socket: %s", strerror(errno)); goto out; } SLOGD("Javen.tang NetlinkManager.cpp mSock=%d\n",mSock); //传入创建的socket的标识构造一个NetlinkHandler实例 mHandler = new NetlinkHandler(mSock); if (mHandler->start()) {//开启socket监控 SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); goto out; } return 0;out: close(mSock); return -1;}
这里使用的是Netlink套接字,Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口,结构定义:
看看NetlinkHandler的构造函数
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) {}NetlinkHandler继承自NetlinkListener,然后看看NetlinkListener的构造函数
NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII;}NetlinkListener又继承自SockerListener,注意这里传递进去的参数是一个int型的socket和false,最后可以看到代码执行到
SocketListener::SocketListener(int socketFd, bool listen) { init(NULL, socketFd, listen, false);}所以继承关系是:NetlinkHandler——>NetlinkListener——>SocketListener!
接着我们看看mHandler->start(),直接就掉到SockerListener的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; } 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){ mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); SLOGD("Javen.tang mClients->push_back\n"); } 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;}根据前面init值的情况,这里真正执行的地方只有mClients->push_back(new SockClient(mSock, false, mUseCmdNum)); 根据传递过来的mSock,new了一个SocketClient,然后push到mClients这个SocketClientCollection中,然后开启threadStart线程。
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); SLOGD("Javen.tang SocketListener::threadStart\n"); me->runListener(); pthread_exit(NULL); return NULL;}在threadStart线程中,执行到runListener()
void SocketListener::runListener() { SocketClientCollection *pendingList = new SocketClientCollection();//新建一个SocketClientCollection用于保存从NetlinkManager传递过来Socket的SocketClient while(1) {//循环检测 SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds);//清空文件描述符集.......................... for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); SLOGD("Javen.tang fd=%d\n",fd); FD_SET(fd, &read_fds);//遍历mClients,把传递过来的Socket加到文件描述符集中 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) {//监听.......................... pendingList->clear(); pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) {//判断fd是否在read_fds文件描述符中,如果是则加到pendingList中SLOGD("Javen.tang pendingList->push_back fd=%d\n",fd); pendingList->push_back(*it); } } pthread_mutex_unlock(&mClientsLock);.................................. 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) {//最后就会调用到这里的onDataAvailable(c),而这里的c就是从NetlinkManager传递过来Socket的SocketClient /* 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); break; } } pthread_mutex_unlock(&mClientsLock); /* Remove our reference to the client */ c->decRef(); }................................也就是说最后会调用到NetlinkListener::onDataAvailable(SocketClient *cli)中
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的buffer SLOGD("Javen.tang NetlinkListener.cpp onDataAvailable socket=%d, count=%d, mBuffer=%s\n", socket, count, mBuffer); 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)) {//交给NetlinkEent 实例解析buffer,保存参数 SLOGE("Error decoding NetlinkEvent"); } else { onEvent(evt);//虚函数~传递evt给子类NetlinkHandler实现 } delete evt; return true;}这里我们可以看看当我们插上U盘后,解析出来的buffer数据是什么
D/NetlinkListener( 984): Javen.tang NetlinkListener.cpp onDataAvailable socket=7, count=275, mBuffer=add@/devices/platform/Mstar-xhci-1.0/usb1/1-1/1-1:1.0add@devices/platform/Mstar-xhci-1.0/usb1/1-1/1-1:1.0就是buffer的数据,然后通过evt->decode()函数来解析
bool NetlinkEvent::decode(char *buffer, int size, int format) { if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { return parseBinaryNetlinkMessage(buffer, size); } else { return parseAsciiNetlinkMessage(buffer, size); }}
bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { const char *s = buffer; const char *end; int param_idx = 0; int i; int first = 1;.....................const char* a; if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { SLOGD("Javen.tang NetlinkEvent.cpp a=%s\n",a); if (!strcmp(a, "add")) mAction = NlActionAdd;//在这里根据获取buffer的数据来添加属性,这里是add else if (!strcmp(a, "remove")) mAction = NlActionRemove; else if (!strcmp(a, "change")) mAction = NlActionChange; } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { mSeq = atoi(a); } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { mSubsystem = strdup(a); } else if (param_idx < NL_PARAMS_MAX) { mParams[param_idx++] = strdup(s); }接着执行onEvent
void NetlinkHandler::onEvent(NetlinkEvent *evt) { VolumeManager *vm = VolumeManager::Instance(); const char *subsys = evt->getSubsystem(); SLOGD("Javen.tang onEvent subsys=%s\n",subsys); if (!subsys) { SLOGW("No subsystem found in netlink event"); return; } if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt); }查看打印信息
D/Vold ( 981): Javen.tang onEvent subsys=block然后通过vm->handleBlockEvent(evt),这样就真正把kernel中的event传递到Vold中来了,然后让VolumeManager来进行处理!
0 0
- Android4.4----Vold挂载管理分析USB挂载(二)
- Android4.4----Vold挂载管理分析USB挂载(三)
- Android4.4----Vold挂载管理分析USB挂载(四)
- Android4.4----Vold挂载管理分析(一)
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析---vold处理内核消息
- android usb挂载分析---FrameWork层处理vold消息
- android usb挂载分析---vold处理内核消息
- android usb挂载分析---vold处理内核消息
- vold挂载管理
- vold挂载管理
- Android—— 4.2 Vold挂载管理_CommandListener (二)
- Android4.0 USB挂载内核驱动层流程分析(二)
- Android4.0 USB挂载内核驱动层流程分析(二)
- android usb挂载分析---FrameWork层处理收到的vold消息
- Ubuntu 下切换到root账号
- JKS证书转换成PFX证书
- iOS开发学习之触摸事件和手势识别(转)
- 网页中加入VLC的播放RTSP流的控件
- 收集android上开源的酷炫的交互动画和视觉效果
- Android4.4----Vold挂载管理分析USB挂载(二)
- 如何把VMware Player中的VM克隆一份
- 在iOS开发中使用FMDB
- jvm内存调优
- StageFright框架(二)和OpenMAX的運作
- HPUoj题目1062 能量项链(区间dp)
- Android Studio简单设置
- HDU1087(最长上升子序列DP)
- ANDROID内存优化(大汇总——全)