`
yanwenjinhaha
  • 浏览: 16459 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

android vold架构详解(2)_Kernel层向上发送消息处理流程

 
阅读更多
学习罗老师,先上一张Kernel层向上发送消息处理流程的序列图,下面一点一点分析。



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层向下发送消息处理流程
  • 大小: 480 KB
分享到:
评论

相关推荐

    android-vold.rar_android_android vold_vold

    在`android vold.pdf`这个文档中,可能会详细阐述`vold`的工作流程、关键函数解析、如何处理不同的设备类型以及在不同Android版本中的变化。这份资料可能是对`vold`源码的分析,帮助开发者理解如何自定义`vold`行为...

    Android 9.0 Vold 挂载流程分析

    通过kernel–&gt;vold–&gt;StorageManagerService这样的架构去逐级上报热插拔事件。 一、Vold 入口 --&gt; /system/vold/main.c int main(int argc, char** argv) { atrace_set_tracing_enabled(false); setenv(ANDROID...

    android vold模块详解

    在深入了解Android Vold模块之前,我们有必要先了解udev和NetLink的基础知识,因为Vold是在Android系统中基于udev功能和NetLink机制的一个实现。udev是一个Linux内核中的功能,用于在2.6版本之后替代旧的devfs,成为...

    android中Vold进程详解

    "Android中Vold进程详解" Vold进程是Android系统中管理和控制外部存储设备的核心组件之一。它接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等。 Vold进程...

    USB之android Vold分析 storage分析 高清版

    USB之android_Vold分析,分析了linux udev与android vold的关系由来,vold的功能、架构,使用netlink的通信过程。kernel的uevent发送,framework层的处理、磁盘的挂载等等。

    android-vold.rar_android

    《Android系统Vold深度解析》 在Android操作系统中,Vold(Volume Daemon)是一个至关重要的组件,它负责管理设备的存储系统,包括内部存储、外部SD卡以及各种类型的USB存储设备。Vold作为系统服务运行在特权用户...

    Android-vold源码分析

    2. **vold**:接收到来自内核的uevent消息后,vold根据设备类型和状态进行相应的处理,如格式化、挂载或卸载等。 3. **Framework**:Framework通过与vold的交互,控制vold执行具体的磁盘管理命令,如挂载SD卡。 4. *...

    Android vold 多U盘多分区挂载实现

    在Android系统中,`vold`(Volume Daemon)是一个关键的系统服务,它负责管理设备上的存储设备,包括内部存储、外部SD卡以及USB设备。本文将深入探讨如何在Android系统上实现对多个U盘及多分区的挂载,基于描述中的...

    android系统vold透析.pdf

    2. **CommandListener**:监听并处理来自Framework层的命令请求。 3. **SocketListener**:用于与Framework层建立socket连接,接收命令并发送响应。 4. **VolumeManager**:管理所有类型的存储卷,包括自动挂载和...

    android-vold架构[收集].pdf

    Android Vold(Volume Daemon)是Android系统中的一个重要组件,它主要负责管理移动设备上的外部存储设备,如SD卡和USB存储设备。Vold作为一个本地服务,监控并响应这些存储设备的插入、移除和其他相关操作,确保...

    USB之android_Vold分析.pdf

    ### USB之android_Vold分析 #### 1. Vold简介 Vold,即Volume Daemon,是Android系统中用于管理外部存储设备(如USB、SD卡等)的核心组件。它的功能涵盖了设备的检测、挂载、卸载以及状态监控等多个方面。Vold的...

    android系统挂载之vold详细分析

    vold接收到这些事件后,通过其内部架构的处理流程来执行相关的命令和功能。 vold在Android系统中扮演的角色不仅仅是管理存储设备,它还要处理存储设备的挂载和卸载,以及在设备状态变化时提供反馈给系统和应用层。...

    USB之android_Vold_分析

    ### USB之android_Vold_分析 #### 一、引言 在深入探讨Android系统中Vold的基本原理及其与USB相关的实现细节之前,我们先来简要回顾一下Vold的背景和重要性。Vold(Volume Daemon)是Android操作系统中一个重要的...

    [Hasen图示系列]android中vold机制

    当有外部存储设备插入或拔出时,Uevent会向用户空间进程发送消息,通知这些事件的发生,Vold将监听这些Uevent事件并作出相应的处理。 Vold机制在Android平台中的工作流程可以分为几个主要步骤: 1. 系统启动时,...

    android系统vold透析

    **Vold**(Volume Daemon)是Android系统中用于管理外部存储设备的核心组件之一,它负责处理与USB存储设备、SD卡等相关的任务。Vold的功能类似于Linux系统中的**udev**,即用于设备管理的守护进程,但它更适应...

    android代码VOLD代码分析

    VOLD在Android设备中扮演着非常重要的角色,尤其是在处理存储设备连接与断开、文件系统挂载、权限控制等场景中。而udev则是Linux系统中负责设备文件管理的一个工具,被VOLD借鉴了核心机制和设计理念。 udev是Linux...

    vold_android.pdf.tar.gz_android

    《Android系统中的Vold服务详解》 在Android操作系统中,Vold(Volume Daemon)是一个至关重要的组件,它主要负责管理设备的存储系统,包括内部存储和外部存储卡。Vold这个名字来源于“Volume Daemon”,意为“卷...

    android vold

    android 对插入设备后产生的反应,诉说连接的响应与挂载

Global site tag (gtag.js) - Google Analytics