学习罗老师,先上一张Kernel层向上发送消息处理流程的序列图,下面一点一点分析。
Step.17以前都在上一篇分析文章里,不在说明了。从Step.17开始分析。
Step.17 在main方法中,nm->start()方法里,开启Socket,监听Kernel层向上发送的消息
Step.18~26 NetlinkHandler的继承关系,NetlinkHandler→NetlinkListener→SocketListener。依次创建NetlinkHandler、NetlinkListener、SocketListener的实例
NetlinkHandler的构造函数
NetlinkListener的构造函数
SocketListener的构造函数
最后实例化了一个SocketClientCollection。
Step.27 接着看看start()方法都干了什么。
NetlinkHandler.start
Step.28 SocketListener的startListener()方法
Step.32 SocketListener的threadStart方法
Strp.33 runListener()方法
Step.34 取到Kernel的消息后,接下来处理该消息
NetlinkListener的onDataAvailable方法
Step.35 NetlinkHandler的onEvent方法,将消息解析后,传给ValumeManager来处理
Step.36~41
消息经过各种Check后,将消息发到vold Socket中.
Library层接受到Kernel层消息,到发送到Application Framework层的处理就到这里了。
后面是Application Framework层如何获取到这个消息
MountService实例化时,创建了一个用来监听vold Socket的Connector
NativeDaemonConnector的run方法中调用了listenToSocket方法,开始监听vold Socket
mCallbacks就是NativeDaemonConnector实例化时传递进来的,
它其实就是MountService。所以回到MountService的onEvent方法
OK!!! 这里就开始分发处理各种消息了。
明天开始FrameWork层向下发送消息处理流程
Step.17以前都在上一篇分析文章里,不在说明了。从Step.17开始分析。
Step.17 在main方法中,nm->start()方法里,开启Socket,监听Kernel层向上发送的消息
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; // 创建协议族为PF_NETLINK,类型为SOCK_DGRAM的socket,返回该socket套接字的文件描述符 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; } mHandler = new NetlinkHandler(mSock); if (mHandler->start()) { SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); return -1; } return 0; }
Step.18~26 NetlinkHandler的继承关系,NetlinkHandler→NetlinkListener→SocketListener。依次创建NetlinkHandler、NetlinkListener、SocketListener的实例
NetlinkHandler的构造函数
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) { }
NetlinkListener的构造函数
NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII; }
SocketListener的构造函数
SocketListener::SocketListener(int socketFd, bool listen) { mListen = listen; mSocketName = NULL; mSock = socketFd; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection(); }
最后实例化了一个SocketClientCollection。
Step.27 接着看看start()方法都干了什么。
NetlinkHandler.start
int NetlinkHandler::start() { // 调用父类startListener()方法 return this->startListener(); }
Step.28 SocketListener的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; } } // 将mSock套接字(NetlinkManager::start()中创建的)变为被连接套接口, // 使得一个进程可以接受其它进程的请求,从而成为一个服务器进程 if (mListen && listen(mSock, 4) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) // 创建SocketClient实例,并添加到前面构造函数中实例化的SocketClientCollection中 mClients->push_back(new SocketClient(mSock, false)); // 建立管道,得到管道的读取端和写入端 if (pipe(mCtrlPipe)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } // 启动线程,指定线程的开始执行的函数threadStart,并进入该方法,继续分析 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; }
Step.32 SocketListener的threadStart方法
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); // 继续调用自己的runListener()方法, // 马上进入最最重要的部分 me->runListener(); pthread_exit(NULL); return NULL; }
Strp.33 runListener()方法
void SocketListener::runListener() { // 创建一个SocketClientCollection,用来保存待处理的SocketClient,其实就是接受到Kernel层消息的SocketClient。 SocketClientCollection *pendingList = new SocketClientCollection(); // 开始while循环,时刻监听kernel的消息 while(1) { SocketClientCollection::iterator iterator; 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) { int fd = (*it)->getSocket(); FD_SET(fd, &read_fds); if (fd > max) max = fd; } pthread_mutex_unlock(&mClientsLock); 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); } 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)) { // 如果有消息,将当前SocketClient添加到pendingList中 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 */ // 遍历pendingList,判断是否不为空。 // 不为空表示,有kernel层发送过来的消息需要处理 // 调用onDataAvailable处理消息 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) { /* 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; }
Step.34 取到Kernel的消息后,接下来处理该消息
NetlinkListener的onDataAvailable方法
bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); ssize_t count; count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_recv(socket, mBuffer, sizeof(mBuffer))); if (count < 0) { SLOGE("recvmsg failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count, mFormat)) { SLOGE("Error decoding NetlinkEvent"); } else { // 开始处理从kernel层接受到的消息 onEvent(evt); } delete evt; return true; }
Step.35 NetlinkHandler的onEvent方法,将消息解析后,传给ValumeManager来处理
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); } }
Step.36~41
消息经过各种Check后,将消息发到vold Socket中.
---------------------------- 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) { 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 } } ---------------------------- ---------------------------- int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if (!strncmp(dp, *it, strlen(*it))) { /* 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); } } 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; } ---------------------------- ---------------------------- 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; } // FUJITSU TEN:2014-01-14 #55703 start snprintf(mDevPath, 1024, "/sys/%s", evt->findParam("DEVPATH")); // FUJITSU TEN:2014-01-14 #55703 end char msg[255]; int partmask = 0; int i; for (i = 1; i <= mDiskNumParts; i++) { partmask |= (1 << i); } mPendingPartMap = partmask; 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 partitions (mask 0x%x)", mDiskNumParts, mPendingPartMap); #endif setState(Volume::State_Pending); } snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); } ---------------------------- ---------------------------- void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { pthread_mutex_lock(&mClientsLock); SocketClientCollection::iterator i; for (i = mClients->begin(); i != mClients->end(); ++i) { if ((*i)->sendMsg(code, msg, addErrno)) { SLOGW("Error sending broadcast (%s)", strerror(errno)); } } pthread_mutex_unlock(&mClientsLock); } ---------------------------- ---------------------------- int SocketClient::sendMsg(int code, const char *msg, bool addErrno) { char *buf; const char* arg; const char* fmt; char tmp[1]; int len; if (addErrno) { fmt = "%.3d %s (%s)"; arg = strerror(errno); } else { fmt = "%.3d %s"; arg = NULL; } /* Measure length of required buffer */ len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg); /* Allocate in the stack, then write to it */ buf = (char*)alloca(len+1); snprintf(buf, len+1, fmt, code, msg, arg); /* Send the zero-terminated message */ return sendMsg(buf); } int SocketClient::sendMsg(const char *msg) { if (mSocket < 0) { errno = EHOSTUNREACH; return -1; } // 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) { int rc = 0; const char *p = (const char*) data; int brtw = len; if (len == 0) { return 0; } pthread_mutex_lock(&mWriteMutex); while (brtw > 0) { rc = write(mSocket, p, brtw); if (rc > 0) { p += rc; brtw -= rc; continue; } if (rc < 0 && errno == EINTR) continue; pthread_mutex_unlock(&mWriteMutex); if (rc == 0) { SLOGW("0 length write :("); errno = EIO; } else { SLOGW("write error (%s)", strerror(errno)); } return -1; } pthread_mutex_unlock(&mWriteMutex); return 0; } ----------------------------
Library层接受到Kernel层消息,到发送到Application Framework层的处理就到这里了。
后面是Application Framework层如何获取到这个消息
MountService实例化时,创建了一个用来监听vold Socket的Connector
public MountService(Context context) { ...... /* * 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. */ // 创建用来监听vold Socket的Connector mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG); mReady = false; // 启动mConnector,NativeDaemonConnector的run方法中调用了listenToSocket方法, // 开始监听这个vold Socket Thread thread = new Thread(mConnector, VOLD_TAG); thread.start(); ...... }
NativeDaemonConnector的run方法中调用了listenToSocket方法,开始监听vold Socket
private void listenToSocket() throws IOException { LocalSocket socket = null; try { ...... while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); if (count < 0) 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) { String event = new String(buffer, start, i - start); if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event)); String[] tokens = event.split(" ", 2); try { int code = Integer.parseInt(tokens[0]); if (code >= ResponseCode.UnsolicitedInformational) { // 发送消息到Handler中 mCallbackHandler.sendMessage( mCallbackHandler.obtainMessage(code, event)); } else { try { mResponseQueue.put(event); } catch (InterruptedException ex) { Slog.e(TAG, "Failed to put response onto queue", ex); } } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); } start = i + 1; } } ...... } } ...... }
public boolean handleMessage(Message msg) { String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { Slog.w(TAG, String.format( "Unhandled event '%s'", event)); } } catch (Exception e) { Slog.e(TAG, String.format( "Error handling '%s'", event), e); } return true; }
mCallbacks就是NativeDaemonConnector实例化时传递进来的,
它其实就是MountService。所以回到MountService的onEvent方法
/** * Callback from NativeDaemonConnector */ public boolean onEvent(int code, String raw, String[] cooked) { ...... if (code == VoldResponseCode.VolumeStateChange) { ...... } else if ((code == VoldResponseCode.VolumeDiskInserted) || (code == VoldResponseCode.VolumeDiskRemoved) || (code == VoldResponseCode.VolumeBadRemoval)) { ...... } else { return false; } return true; }
OK!!! 这里就开始分发处理各种消息了。
明天开始FrameWork层向下发送消息处理流程
发表评论
-
android vold架构详解(3)_两个Socket
2014-12-04 15:15 1413Vold架构最最重要的其实是两个Socket的创建和监听 1 ... -
android vold架构详解(1)
2014-12-01 18:30 1120首先上一张整体的结构 ... -
Android 安全架构及权限控制机制剖析
2014-11-20 18:19 456http://www.ibm.com/developerwor ... -
理解 Android Build 系统
2014-11-20 15:53 406http://www.ibm.com/developerwor ... -
Android Zygote进程和SystemServer进程启动过程
2014-10-05 21:11 640Android Zygote进程和SystemServer进程 ... -
AIDL用法总结
2014-09-18 19:47 774AIDL其实并没有多么复杂。 它是用来方便我们开发者编程的一个 ...
相关推荐
在`android vold.pdf`这个文档中,可能会详细阐述`vold`的工作流程、关键函数解析、如何处理不同的设备类型以及在不同Android版本中的变化。这份资料可能是对`vold`源码的分析,帮助开发者理解如何自定义`vold`行为...
通过kernel–>vold–>StorageManagerService这样的架构去逐级上报热插拔事件。 一、Vold 入口 --> /system/vold/main.c int main(int argc, char** argv) { atrace_set_tracing_enabled(false); setenv(ANDROID...
在深入了解Android Vold模块之前,我们有必要先了解udev和NetLink的基础知识,因为Vold是在Android系统中基于udev功能和NetLink机制的一个实现。udev是一个Linux内核中的功能,用于在2.6版本之后替代旧的devfs,成为...
"Android中Vold进程详解" Vold进程是Android系统中管理和控制外部存储设备的核心组件之一。它接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等。 Vold进程...
USB之android_Vold分析,分析了linux udev与android vold的关系由来,vold的功能、架构,使用netlink的通信过程。kernel的uevent发送,framework层的处理、磁盘的挂载等等。
《Android系统Vold深度解析》 在Android操作系统中,Vold(Volume Daemon)是一个至关重要的组件,它负责管理设备的存储系统,包括内部存储、外部SD卡以及各种类型的USB存储设备。Vold作为系统服务运行在特权用户...
2. **vold**:接收到来自内核的uevent消息后,vold根据设备类型和状态进行相应的处理,如格式化、挂载或卸载等。 3. **Framework**:Framework通过与vold的交互,控制vold执行具体的磁盘管理命令,如挂载SD卡。 4. *...
在Android系统中,`vold`(Volume Daemon)是一个关键的系统服务,它负责管理设备上的存储设备,包括内部存储、外部SD卡以及USB设备。本文将深入探讨如何在Android系统上实现对多个U盘及多分区的挂载,基于描述中的...
2. **CommandListener**:监听并处理来自Framework层的命令请求。 3. **SocketListener**:用于与Framework层建立socket连接,接收命令并发送响应。 4. **VolumeManager**:管理所有类型的存储卷,包括自动挂载和...
Android Vold(Volume Daemon)是Android系统中的一个重要组件,它主要负责管理移动设备上的外部存储设备,如SD卡和USB存储设备。Vold作为一个本地服务,监控并响应这些存储设备的插入、移除和其他相关操作,确保...
### USB之android_Vold分析 #### 1. Vold简介 Vold,即Volume Daemon,是Android系统中用于管理外部存储设备(如USB、SD卡等)的核心组件。它的功能涵盖了设备的检测、挂载、卸载以及状态监控等多个方面。Vold的...
vold接收到这些事件后,通过其内部架构的处理流程来执行相关的命令和功能。 vold在Android系统中扮演的角色不仅仅是管理存储设备,它还要处理存储设备的挂载和卸载,以及在设备状态变化时提供反馈给系统和应用层。...
### USB之android_Vold_分析 #### 一、引言 在深入探讨Android系统中Vold的基本原理及其与USB相关的实现细节之前,我们先来简要回顾一下Vold的背景和重要性。Vold(Volume Daemon)是Android操作系统中一个重要的...
当有外部存储设备插入或拔出时,Uevent会向用户空间进程发送消息,通知这些事件的发生,Vold将监听这些Uevent事件并作出相应的处理。 Vold机制在Android平台中的工作流程可以分为几个主要步骤: 1. 系统启动时,...
**Vold**(Volume Daemon)是Android系统中用于管理外部存储设备的核心组件之一,它负责处理与USB存储设备、SD卡等相关的任务。Vold的功能类似于Linux系统中的**udev**,即用于设备管理的守护进程,但它更适应...
VOLD在Android设备中扮演着非常重要的角色,尤其是在处理存储设备连接与断开、文件系统挂载、权限控制等场景中。而udev则是Linux系统中负责设备文件管理的一个工具,被VOLD借鉴了核心机制和设计理念。 udev是Linux...
《Android系统中的Vold服务详解》 在Android操作系统中,Vold(Volume Daemon)是一个至关重要的组件,它主要负责管理设备的存储系统,包括内部存储和外部存储卡。Vold这个名字来源于“Volume Daemon”,意为“卷...
android 对插入设备后产生的反应,诉说连接的响应与挂载