Android vold启下篇(NetlinkHandler)

来源:互联网 发布:汽车pp2000软件下载 编辑:程序博客网 时间:2024/06/05 05:41

在文章Android 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;}#endifNetlinkListener::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中的处理过程。






0 0