Android—— 4.2 Vold挂载管理_CommandListener (二)

Android7.0 Vold 进程工作机制分析之整体流程 Android7.0 Vold 进程工作机制分析之整体流程 一、Vold简介 Vold是Volume Daemon的缩写,负责管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等。它是通过init进程解析init.rc脚本所启动的进程.它处于Native层. 二、基础架构 这里引用Gityuan博客的一张图。 SystermServer进程和Vol 阅读详情

 在前一篇博客中介绍了个大体结构 Android—— 4.2 Vold挂载管理_主体构建 (一) ,按照代码的顺序结构来依次分析,这里来看看CommandListener这个类做了什么。


                                                                                                   
                                                                                        撰写不易,转载请注明出处:http://blog.youkuaiyun.com/jscese/article/details/38434263

一:CommandListener构造

在/system/vold/main.cpp的main函数中构建实例:


cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);

...

/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
   SLOGE("Unable to start CommandListener (%s)", strerror(errno));
   exit(1);
}

源码位于/system/vold/CommandListener.cpp,构造函数如下:

CommandListener::CommandListener() :
                 FrameworkListener("vold", true) {
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ObbCmd());
    registerCmd(new StorageCmd());
    registerCmd(new XwarpCmd());
    registerCmd(new CryptfsCmd());
}

构造一个父类FrameworkListener的实例

先看FrameworkListener的构造:

FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
                            SocketListener(socketName, true, withSeq) {
    init(socketName, withSeq);
}

..

void FrameworkListener::init(const char *socketName, bool withSeq) {
    mCommands = new FrameworkCommandCollection();
    errorRate = 0;
    mCommandCount = 0;
    mWithSeq = withSeq;
}

可以看到传进去的"vold" 没在这个类里面起作用,是为了更高一层的构造,接着看/system/core/libsysutils/src/SocketListener.cpp中:


SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
    init(socketName, -1, listen, useCmdNum);
}

void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
    mListen = listen;
    mSocketName = socketName;
    mSock = socketFd;
    mUseCmdNum = useCmdNum;
    pthread_mutex_init(&mClientsLock, NULL);
    mClients = new SocketClientCollection();
}
初始化线程锁mClientsLock,new 了一个SocketClient的容器mClients。

继承关系: CommandListener——>FrameworkListener——>SocketListener



二:Command注册

上面的CommandListener的构造函数中调用父类的注册函数register, 注册commad到FrameworkListener的mCommands容器中。

/system/core/libsysutils/src/FrameworkListener.cpp注册如下:

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands->push_back(cmd);
}

可以看到这里的行参是FrameworkCommand 类型,

因为这几个command类的继承关系: VolumeCmd——>VoldCommand——>FrameworkCommand


我们这里以VolumeCmd 为例子学习:

CommandListener::VolumeCmd::VolumeCmd() :
                 VoldCommand("volume") {
}

VoldCommand::VoldCommand(const char *cmd) :
              FrameworkCommand(cmd)  {
}

FrameworkCommand::FrameworkCommand(const char *cmd) {
    mCommand = cmd;
}

将volume这个command注册到mCommands这个容器中之后,目的是当FrameworkListerer从SlocketListener接收到command的时候,

会依据mCommands 中的command进行解析筛选判断分发,调用对应的command执行类。



三:CommandListener运作

CommandListener所起到的作用,简单来说就是沟通Framwork和Vold,我画的一张简单的结构图,大体的运作如下:

                    



开启CommandListener的监听cl->startListener()

CommandListener和FrameworkListener都没有重写这个方法,直接调用父类SocketListener的:

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) {//获取socket的文件描述符,这里是获取Vold这个socket的
            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)//是否正常监听socket
        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;
}

往下新开了一个线程用于监听:

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);//threadStart为static函数,上面开线程创建的时候传了this,这里需要转换一个一样bit位的SocketListener指针

    me->runListener();//SocketListener真正的执行函数
    pthread_exit(NULL);
    return NULL;
}

下面就是对Socket的监听处理:

void SocketListener::runListener() {

    SocketClientCollection *pendingList = new SocketClientCollection();//暂存mClients中的SocketClient

    while(1) {
        SocketClientCollection::iterator it;
        fd_set read_fds;
        int rc = 0;
        int max = -1;

        FD_ZERO(&read_fds);//清空文件描述符集read_fds 

        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);//如果正常的监听,这里就把之前获得的vold的文件描述符添加进去
        }

        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) {//遍历mClients,获取fd 添加到read_fds
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);//解锁
        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);

//linux下socket编程的select,这里检测read_fds集合里面是否有可读的,也就是有没有数据过来,没有数据的文件描述符会从read_fds中被剔除,这里的select设置time out为NULL,阻塞操作,直到read_fds集合中描述符有变化
        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR)
                continue;
            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
            sleep(1);
            continue;
        } else if (!rc)
            continue;

        if (FD_ISSET(mCtrlPipe[0], &read_fds))//如果匿名管道有数据可读,就退出
            break;
        if (mListen && FD_ISSET(mSock, &read_fds)) {//如果是正常监听的 mListen 为true,然后mSock这个描述符有可读数据,就创建链接,新建异步处理的SocketClient加入到mClients容器,这里的mSock 是vold这个套接字的描述符
            struct sockaddr addr;
            socklen_t alen;
            int c;

            do {
                alen = sizeof(addr);
                c = accept(mSock, &addr, &alen);
                SLOGV("%s got %d from accept", mSocketName, c);
            } 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, mUseCmdNum));
            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) {//把上面有请求建立链接的Client加入到pendingList 容器中,后面处理
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                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 */
        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) {//调用到FrameworkListener 中onDataAvailable处理Socket事件
                /* 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);//处理完成之后,从容器中移除这次的监听到的SocketClient
                        break;
                    }
                }
                pthread_mutex_unlock(&mClientsLock);
                /* Remove our reference to the client */
                c->decRef();
            }
        }
    }
    delete pendingList;
}

这个函数是SocketListener的核心所在,真正的处理函数是onDataAvailable,这个是纯虚函数,/system/core/include/sysutils/SocketListener.h:

    virtual bool onDataAvailable(SocketClient *c) = 0;

在其子类 FrameworkListener.cpp中实现:

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[255];
    int len;

    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));//读Socket 内容保存到buffer
    if (len < 0) {
        SLOGE("read() failed (%s)", strerror(errno));
        return false;
    } else if (!len)
        return false;

    int offset = 0;
    int i;

    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {//一次传入一个字符串
            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
            dispatchCommand(c, buffer + offset);
            offset = i + 1;
        }
    }
    return true;
}

调用同类命令执行函数 dispatchCommand:

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
    FrameworkCommandCollection::iterator i;
    int argc = 0;
    char *argv[FrameworkListener::CMD_ARGS_MAX];
    char tmp[255];

...//解析判断command buffer

    for (i = mCommands->begin(); i != mCommands->end(); ++i) {//遍历之前register到FrameworkListener中的FrameworkCommand容器
        FrameworkCommand *c = *i;

        if (!strcmp(argv[0], c->getCommand())) {//其中有注册“Volume”,如果这里是Volume开头的command,那么就调用,Volume构造的时候所构造的父类FrameworkCommand中的runCommand函数
            if (c->runCommand(cli, argc, argv)) {
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
            }
            goto out;
        }
    }

}


同时/system/core/include/sysutils/FrameworkCommand.h:

    virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;

实现在子类中,还是以Volume这个runcommand为例 /system/vold/CommandListener.cpp中:


int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
    dumpArgs(argc, argv, -1);

    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }

    VolumeManager *vm = VolumeManager::Instance();//获取已经存在的VolumeManager实例

...

else if (!strcmp(argv[1], "mount")) {//判断command 内容
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
            return 0;
        }
        rc = vm->mountVolume(argv[2]);//交给VolumeManager来对Volume进行操作
    }

...

}


对CommandListener的分析就到这里,主要是怎么接收到的Socket,执行相对应的command,最后是怎么传递给VolumeManager,与上层MountService的交互后续分析,后续分析VolumeManager的初始化!





原生安卓 vold 流程及框架 前言: 由于谷歌AndroidContainers 中将Vold中的某些模块和代码进行了重写,通过mojom借道chromiumOS间接和内核进行通讯和操作,所以我们需要研究原生安卓中的vold的流程以作参考。为我们分析和实现AC中的vold理清思路。 Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程。其功能主要包括:SD卡的插拔事件检测、SD卡挂载、卸载、格式化等。 模块架构: ... 阅读详情

相关推荐

Android-vold源码分析之卸载SD卡(9)

作者:gzshun. 原创作品,转载请标明出处! 来源:http://blog.csdn.net/gzshun 本文分析卸载sd卡的源码,这些涉及的内容比较少,走过就行。在Android系统,系统设置里面, 提供了挂载,卸载与格式化的功能。在这里,我们可以回忆一下,Android在挂载sd卡有几个途径, 卸载又是有几种方法? 一、挂载sd卡,有2种方式: 1.用户自己挂载sd卡;

gzshun 1万+

Android vold通讯篇(CommandListener)

前一篇文章:Androidvold核心篇,介绍了vold接收到NetlinkManager发来的内核消息进行对应的处理后(包含挂载卸载等),将处理后的结果发送到FrameWrok,具体是怎么发送的,以及怎么接收从Framework发来的消息,在本文解析。 一、CommandListener类的实现 我们回到Main.cpp的主函数main中,里面有定义一个变量如下: CommandListe

dengziliang001的专栏 2363

手把手教你用Python实现ITRS与GCRS坐标转换(附完整代码)

本文详细介绍了如何使用Python的Astropy库实现ITRS与GCRS坐标转换。文章从环境配置、坐标对象构建入手,深入解析了transform_to方法背后的转换矩阵与地球定向参数管理,并通过卫星地面轨迹计算实战案例,帮助开发者掌握高精度空间坐标转换的核心技术与工程实践。

weixin_28335283的博客 79

卷起来,关于利用MongoDB的CommandListener命令行实现Mongo在Cat中埋点监控

为了实现 使用 dianping CAT组件监控标准化埋点,经过长期实践已经完成了对大部分组件埋点的支持,并实现了整个链路的串通,而对MongoDB的支持一直是个难点,曾几何时做了多次尝试,也未能成功,因为从网上根本找不到方法。或许鉴于用CAT的不多,没有人贡献这类的思路, 近段时间一直在MongoDB上折腾,从客户端的角度记录MongoDB一直是个缺失。以至于出现问题时没办法快速看到相关采集的数据指标。 活不多说,这次终于最终搞定也是源自Opentracing对Mongo做Tracing监

ankeway的博客 2168

Python对接海康威视机器视觉工业相机

工业相机只允许单条连接,也就是说MVS如果连接了相机,python代码就无法获取数据,此时必须。相机工具类(读者直接复制)HKCamera_class.py。博主这里出现了一个警告:获取不到相机参数。四、使用Pycharm打开Python代码示例文件夹。三、找到MVS示例代码(代码在MVS的安装位置)二、解压并安装MVS客户端。一、下载MVS客户端。安装一下opencv。

Good Luck 2万+

将外部电磁近场数据导入 ANSYS HFSS

本博客介绍了如何将电磁近场数据导入 ANSYS HFSS。用户可能需要导入字段,无论是通过分析计算、测量、由其他工具生成还是从提供商处接收的字段,并将其用作实际激励来执行不同类型的分析。以下是导入过程的简要概述,视频链接中提供了完整的演示。为了定义简单基元近场源,HFSS 使用两种外部数据文件。首先,实际位置/字段数据以 .nfd 格式存储。其次,Ansys Near field Descriptor 文件(.and 文件)存储 .nfd 数据的一般几何信息和路径。

jkh920184196的博客 2323

守护进程框架简单分析 (基于NetD)

守护进程框架简单分析 (基于NetD)Main.cpp CommandListener对象,用于接收Framework层通过socket传下来的指令。 NetlinkManager对象,创建与底层通信的Netlink Socket。 MDnsSDListener对象 CommandListener.cpp 继承自FrameworkListener–SocketListener 传进Ne

大象杂货 4416

上汽CPMP开发流程与A、B、C、D样

也叫验收样件或设计样件,是根据A样试制结果优化后的样件,外观、功能达到设计要求,B样可以是手工样件或者模具件,B样件的全维度产品功能和尺寸参数已经固化下来,并需要和最终的量产产品保持一致。为批量样件或生产样件、展示样件,是在A/B的基础上完善结果,此时的产品状态已经完全定型,并能够满足客户和市场提出的各类需求。预试生产(Pre-Production)----------------------------------------------------------------------→D样。

weixin_43602865的博客 3711

Vold学习笔记

本文主要参考学习了老邓的Vold章节。平台:android4.0 场景:客户要求系统默认对NTFS的SD卡支持识别。 时间:2012.7.28Android系统默认支持FAT文件系统,不支持NTFS,EXFAT。其原因不在于技术方面,而是版权。 在全志的平台上,以上文件系统都是支持的。所以在做分析时,也参考了全志平台的做法。vold是Volume Daemon的简称,其是用于管理和控制andr

a87636764的专栏 1468

保姆级教程:手把手教你用记事本修改DNF私服PVF,打造毕业级自定义装备

本文提供了一份详细的DNF私服PVF文件修改教程,教你如何使用记事本轻松打造毕业级自定义装备。从PVF文件结构解析到基础属性修改,再到高级特效设置,手把手教你实现装备属性的全方位定制,无需编程基础即可完成。

weixin_42525385的博客 1192

高通平台Android稳定性调试笔记:手把手教你用T32、Crash Utility分析Kernel Panic与RAM Dump

本文详细介绍了高通平台Android内核崩溃的分析方法,包括使用T32 Simulator和Crash Utility工具链解析Kernel Panic与RAM Dump。从环境配置、dump文件预处理到高级调试技巧,手把手教你如何定位和解决Android系统崩溃问题,特别适用于MSM/SA8155平台的开发者。

weixin_42543046的博客 526

Android Framework 存储子系统(01)vold守护进程

系列文章解读&说明: Android Framework 存储子系统 的分析主要分为以下部分: Android Framework 存储子系统(01)vold守护进程 Android Framework 存储子系统(02)MountService服务 本模块分享的内容:vold守护进程 本章关键点总结 & 说明: 导图是不断迭代的,这里主要关注➕ vold 守护进程...

wangdsh的博客 1402

RK3568下GPIO模拟串口

在嵌入式开发中,硬件 UART 资源可能被其他外设占用。此时,通过 GPIO 模拟 UART(软串口)成为一种灵活的解决方案。本文基于 RK3568 平台,结合 Linux 内核模块,实现高精度软串口通信,并深入分析关键技术细节。可以看到已经接收到数据了,可以自己创建自定义的设备文件到/dev下,也可以按照串口设备的标准创建一个设备,后面有时间我写一篇和标准串口设备结合的gpio模拟串口文章。RK3568 GPIO 模拟串口(软串口)实现详解。将编译好的驱动放到板子上运行。再写个Makefile。

文石_2009的博客 364

vold挂载管理

看了很长时间Vold存储模块的相关知识,也深入的研究一段时间的Android源码,打算把自己看过的经验之贴、参考资料和自己的一些见解,以帖子的形式发出来,供有兴趣的同仁们参考,有不对的地方请指正,我们相互交流。 1.1 vold的原理与机制分析 1.1.1 Vold 架构 从上图中可知: ·  Vold中的NetlinkManager模块接收来自Linux内核的ueve

sdkdlwk的博客 911

PCL:读写pcd点云的两种方式

本文介绍了PCL读写点云的两种方式:PCDReader,PCDWriter;loadPCDFile,savePCDFile.

孙悟空 1万+

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

android vold 挂载读写,Android——Vold磁盘挂载_主体构建(一)

这段时间为了把mmc的一个block当成sdcard内置,学习了下android的vold磁盘挂载模块,记录一下(android 4.2.2)。一:Vold的编译及启动vold的源码位置在android根目录 /system/vold文件下,先看这下面的android.mk:common_src_files := VolumeManager.cpp CommandListener....

weixin_35733151的博客 912

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android 7.0 Vold工作流程

Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程。其功能主要包括:SD卡的插拔事件检测、SD卡挂载、卸载、格式化等。

橡果生长记的博客 1万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android Volume 挂载、存储流程

Android Volume 存储流程。

dnfkr的博客 3168

Android -- Vold机制简要分析

Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SD卡的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。 Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是: NetlinkManager:用于从kernel中获取SD卡插拔的

我就是我的博客 3655

Android7.0 Vold 进程

一、Vold简介 Vold是VolumeDaemon的缩写,负责管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等。它是通过init进程解析init.rc脚本所启动的进程.它处于Native层. Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是: NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息 VolumeManager:管理模块,.

ngRoom 1074

Android vold进程一 Vold启动和NetlinkManager数据获取

一、vold简介: vold进程接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;当外部设备发生变化时,内核通过Netlink发送uEvent格式的消息给用户空间程序,Netlink 是一种基于异步通信机制,在内核与用户应用间进行双向数据传输的特殊 socket,用户态应用使用标准的socket API 就可以使用 netlin

frank_zyp的博客 2194

vold

一、Vold工作机制Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程。其功能主要包括:SD卡的插拔事件检测、SD卡挂载、卸载、格式化等。如上图所示,Vold中的NetlinkManager模块接收来自Linux Kernel的uevent消息。NetlinkManager将这些消息转发给VolumeMa...

xlnaan的博客 4820

浅谈Android Vold

一、首先看Vold的作用:     Vold:Volume Daemon,用于管理和控制Android平台外部存储设备的后台程序,例如SD卡的挂载、卸载、格式化,以及拔插事件的检查等。     Vold的实现在JNI层,Java层与它打交道的模块是MountService。MountService一方面接收来自Vold的消息,例如SD卡的拔插事件;一方面向Vold发送控制命令,例如挂载和卸

zengdaquan007的专栏 1249

Android—— 4.2 Vold挂载管理_主体构建main (一)

这段时间为了把mmc的一个block当成sdcard内置,学习了下android的vold磁盘挂载模块,记录一下(android 4.2.2)。 一:Vold的编译及启动 vold的源码位置在android根目录 /system/vold文件下,先看这下面的android.mk:

jscese 6318

vold 架构分析

Vold 框架分析 main.cpp,vold的入口函数,系统起来会只执行vold的可执行文件,调到这个main函数中。NetlinkManager.cpp位于源码位置/system/vold/NetlinkManager.cpp。该类的主要通过引用NetlinkHandler类中的onEvent()方法来接收...

weixin_33910385的博客 541
上一篇: Android—— 4.2 Vold挂载管理_主体构建main (一)
下一篇: Android—— 4.2 Vold挂载管理_VolumeManager (三)
南丶烟
博客等级 码龄14年 569粉丝 98原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值