Android vold启下篇(NetlinkHandler)

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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值