Android vold启下篇(NetlinkHandler)
2016-06-28 15:37
399 查看
在文章Android
Vold实现总览中我们以代码和数据流图的方式介绍了vold的整个主流程。
而这篇文章主要分析vold贴近底层内核的代码,所以在文章标题中有启下两个字。在这里为方便引出相关代码,我们再次贴上主流程的代码:
第5行的NetlinkManager的nm变量及相关操作,就是我们在本章要研究的问题。
一、由NetlinkManager开启整个过程
1.1、在上面的代码中,我们可以看到有关键代码:nm->start();进入到该函数,有如下两段关键代码:
1.2、关于NetlinkHandler
1.3、关于NetlinkListener,如下:
在startListener函数中,有创建一个threadStart线程,该函数的实现如下:
该函数中,有如下两段关键代码:
第二段是将消息传递到onEvent函数,该onEvent函数我们在2.2节中贴出来了,通过代码可知,消息传递到了VolumeManager中。
关于vold和linux内核交互已经结束,下篇讲解消息传递到VolumeManager中的处理过程。
Vold实现总览中我们以代码和数据流图的方式介绍了vold的整个主流程。
而这篇文章主要分析vold贴近底层内核的代码,所以在文章标题中有启下两个字。在这里为方便引出相关代码,我们再次贴上主流程的代码:
int main() { VolumeManager *vm; //管理volume CommandListener *cl;//和Framework进行通讯 NetlinkManager *nm;//接收内核消息 SLOGI("Vold 2.1 (the revenge) firing up"); mkdir("/dev/block/vold", 0755);//创建设备节点 /* For when cryptfs checks and mounts an encrypted filesystem */ klog_set_level(6); /* Create our singleton managers */ if (!(vm = VolumeManager::Instance())) { SLOGE("Unable to create VolumeManager"); exit(1); }; if (!(nm = NetlinkManager::Instance())) { SLOGE("Unable to create NetlinkManager"); exit(1); }; cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl); if (vm->start()) {//啥也没干 SLOGE("Unable to start VolumeManager (%s)", strerror(errno)); exit(1); } if (process_config(vm)) {//根据配置文件/etc/vold.fstab,初始化VolumeManager SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno)); } if (nm->start()) {//启动内核监听 SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); } coldboot("/sys/block");//触发内核sysfs发送uevent事件 // coldboot("/sys/class/switch"); /* * Now that we're up, we can respond to commands */ if (cl->startListener()) {//启动对Framework的监听 SLOGE("Unable to start CommandListener (%s)", strerror(errno)); exit(1); } // Eventually we'll become the monitoring thread while(1) { sleep(1000); } SLOGI("Vold exiting"); exit(0); }
第5行的NetlinkManager的nm变量及相关操作,就是我们在本章要研究的问题。
一、由NetlinkManager开启整个过程
1.1、在上面的代码中,我们可以看到有关键代码:nm->start();进入到该函数,有如下两段关键代码:
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { SLOGE("Unable to create uevent socket: %s", strerror(errno)); return -1; }
mHandler = new NetlinkHandler(mSock); if (mHandler->start()) { SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); goto out; }第一段代码创建了以PF_NETLINK标识的socket,第二段代码以该socket创建了NetlinkHandler对象;
1.2、关于NetlinkHandler
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) { } NetlinkHandler::~NetlinkHandler() { } int NetlinkHandler::start() { return this->startListener(); } int NetlinkHandler::stop() { return this->stopListener(); } 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); } }由以上代码可知,NetlinkHandler的start函数调用了父类函数的 startListener,启动了对内核的监听,并实现了父类的onEvent函数。
1.3、关于NetlinkListener,如下:
NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII; } #endif NetlinkListener::NetlinkListener(int socket, int format) : SocketListener(socket, false), mFormat(format) { } 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)); 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)) { SLOGE("Error decoding NetlinkEvent"); } else { onEvent(evt); } delete evt; return true; }由上可知NetlinkListener继承自SocketListener,1.2节中NetlinkHandler的start函数调用的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)); 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; }该函数中的套接字mSock是在2.1中创建并通过构造函数参数的方式传递到了SocketListener类中。
在startListener函数中,有创建一个threadStart线程,该函数的实现如下:
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL; }该函数中调用了SocketListener的runListener函数,而该函数正是接收硬件消息的地方,代码太多,截取关键部分如下:
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 */ 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(); } } }该函数中将收到信息的SocketClient对象指针传递到了onDataAvailable函数中,这样流程跑到了2.3节中的第一段代码的NetlinkListener::onDataAvailable函数,
该函数中,有如下两段关键代码:
count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv( socket, mBuffer, sizeof(mBuffer), &uid));
onEvent(evt);第一段代码是从socket中读取linux内核发来的消息;
第二段是将消息传递到onEvent函数,该onEvent函数我们在2.2节中贴出来了,通过代码可知,消息传递到了VolumeManager中。
关于vold和linux内核交互已经结束,下篇讲解消息传递到VolumeManager中的处理过程。
相关文章推荐
- Linux socket 初步
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件