Android的存储系统(二)

回顾:前贴主要分析了Android存储系统的架构和原理图,简要的介绍了整个从Kernel-->Vold-->上层MountService之间的数据传输流程,在这样的基础上,我们开始今天的源码分析!

【源码分析】

1. Vold的main函数

  Vold也是通过init进程启动,它在init.rc中的定义如下:

 service vold /system/bin/vold
     class core
      root mount
     ioprio be 

  Vold服务放到了core分组,这就意味着系统启动时,它就会被init进程启动。这里定义的一个socket,主要用语Vold和Java层的MountService通信。

   Vold模块的源代码位于system/vold,我们看看入口函数main(),代码如下:

1 int main() {
2     VolumeManager *vm;
3     CommandListener *cl;
4     NetlinkManager *nm;
5
6     SLOGI("Vold 2.1 (the revenge) firing up");
7
8     mkdir();                 // 创建vold目录
9
10    klog_set_level();
11
12    if (!(vm = VolumeManager::Instance())) {        // 创建VolumeManager对象
13        exit();
14    };
15
16    if (!(nm = NetlinkManager::Instance())) {       // 创建NetlinkManager对象
17        exit();
18    };
19
22    cl = new CommandListener();                     // 创建CommandListener对象
23    vm->setBroadcaster((SocketListener *) cl);      // 建立vm和cl的联系
24    nm->setBroadcaster((SocketListener *) cl);      // 建立nm和cl的联系
25
26    if (vm->start()) {                              // 启动VolumeManager
27        exit();
28    }
29
30    if (process_config(vm)) {                       // 创建文件/fstab.xxx中定义的Volume对象
31        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
32    }
33
34    cryptfs_pfe_boot();
35
36    if (nm->start()) {                              // 启动NetlinkManager,会调用NetlinkManager的start()方法,它创建PF_NETLINK socket,并开启线程从此socket中读取数据
37        exit();
38    }
39
40    coldboot("/sys/block");                         // 冷启动,创建/sys/block下的节点文件
41
42    if (cl->startListener()) {                      // 开始监听Framework的socket
43        exit();
44    }
45
46    ) {                                      // 进入循环
47        sleep();                                // 主线程进入休眠
48    }
4950    SLOGI("Vold exiting");
51    exit();
52 }

  main函数的主要工作是创建3个对象:VolumeManager、NetlinkManager和CommandListener,同时将CommandListener对象分别设置到了VolumeManager对象和NetlinkManager对象中。

  从前贴的架构图中可以发现,CommandListener对象用于和Java层的NativeDaemonConnector对象进行socket通信,因此,无论是VolumeManager对象还是NetlinkManager对象都需要拥有CommandListener对象的引用。

2. 监听驱动发出的消息—Vold的NetlinkManager对象

  NetlinkManager对象的主要工作是监听驱动发出的uevent消息。

  main()函数中调用NetlinkManager类的静态函数Instance()来创建NetlinkManager对象,代码如下:

 NetlinkManager *NetlinkManager::Instance() {
       if (!sInstance)
           sInstance = new NetlinkManager();      // NetlinkManager对象通过静态变量sInstance来引用,这意味着vold进程中只有一个NetlinkManager对象。
       return sInstance;
 }

  看下NetlinkManager的构造函数,代码如下:

 NetlinkManager::NetlinkManager() {
       mBroadcaster = NULL;
 }

  NetlinkManager的构造函数只是对mBroadcaster进行了初始化。我们可以发现main()函数中通过调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。

nm->setBroadcaster((SocketListener *) cl);

  main()函数还调用了NetlinkManager的start()函数,我们观察一下NetlinkManager中的start()方法,代码如下:

 int NetlinkManager::start() {
      struct sockaddr_nl nladdr;
       * ;
      ;

      memset(&nladdr, , sizeof(nladdr));
      nladdr.nl_family = AF_NETLINK;
      nladdr.nl_pid = getpid();
      nladdr.nl_groups = 0xffffffff;
      /*创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件*/
      ) {
          SLOGE("Unable to create uevent socket: %s", strerror(errno));
          ;
      }
      /*设置缓冲区大小为64KB*/
      ) {
          SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
          goto out;
      }
      /*设置允许 SCM_CREDENTIALS 控制消息的接收*/
      ) {
          SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
          goto out;
      }
      /*绑定 socket 地址*/
      ) {
          SLOGE("Unable to bind uevent socket: %s", strerror(errno));
          goto out;
      }
      /*利用新创建的socket实例化一个NetlinkHandler类对象用于监听socket,NetlinkHandler继承了类NetlinkListener,NetlinkListener又继承了类SocketListener*/
      mHandler = new NetlinkHandler(mSock);
       if (mHandler->start()) {                                               // 启动NetlinkHandler,调用NetlinkHandler的start()函数
           SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
           goto out;
      }

      ;

 out:
      close(mSock);
      ;
 }

  我们看一下NetlinkManager的家族关系,如下图:

  上面的虚线为启动时的调用流程:

  (1) class NetlinkManager(在其start函数中创建了NetlinkHandler对象,并把创建的socket作为参数)

  (2)class NetlinkHandler: public NetlinkListener(实现了onEvent)

  (3) class NetlinkListener : public SocketListener(实现了onDataAvailable)

  (4) class SocketListener(实现了runListener,在一个线程中通过select查看哪些socket有数据,通过调用onDataAvailable来读取数据)。

总结:此贴主要分析了Vold的main()函数和NetlinkManager对象的源码,通过源码了解对象的创建时机和函数调用流程,下一贴会继续从NetlinkHandler的start()方法深入分析,继续源码的学习,很快会与大家见面,欢迎大家批评指正,我们互相学习。

Android 7.0 存储系统—Vold与MountService分析(二)(转 Android 9.0 分析)的更多相关文章

  1. Android 7.0 存储系统—Vold与MountService分析(三)(转 Android 9.0 分析)

    Android的存储系统(三) 回顾:前帖分析了Vold的main()函数和NetlinkManager的函数调用流程,截止到NetlinkHandler的创建和start()调用,本帖继续分析源码 ...

  2. Android 7.0 存储系统—Vold与MountService分析(一)(转 Android 9.0 分析)

    Android的存储系统(一) 看了很长时间Vold存储模块的相关知识,也死扣了一段时间的Android源码,发现Android存储系统所涉及的函数调用,以及Kernel与上层之间的Socket传输真 ...

  3. 【Android Studio安装部署系列】三十二、Android模拟器Genymotion安装使用教程详解

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 一.注册\登录 打开Genymotion官网,https://www.genymotion.com/ ,首先点击右上角的Sign in进行 ...

  4. [ipsec][strongswan] strongswan源码分析-- (二)rekey/reauth机制分析

    目录 strongwan sa分析(二) 名词约定 rekey/reauth 机制分析 1 概述 2 reauth 3 CHILD SA rekey 4 IKE SA rekey 5 其他 stron ...

  5. 深入浅出 - Android系统移植与平台开发(十二)- Android JNI机制

    第五章.JNI机制 4.1 JNI概述 由前面基础知识可知,Android的应用层由Java语言编写,Framework框架层则是由Java代码与C/C++语言实现,之所以由两种不同的语言组合开发框架 ...

  6. 【Android开发日记】之基础篇(二)——Android的动画效果

          什么是动画,动画的本质是通过连续不断地显示若干图像来产生“动”起来的效果.比如说一个移动的动画,就是在一定的时间段内,以恰当的速率(起码要12帧/秒以上,才会让人产生动起来的错觉)每隔若干 ...

  7. 【Android Studio安装部署系列】四十二、Android Studio使用Eclipse中的keystore为App签名

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 从eclipse迁移到AndroidStudio,要用原Eclipse的签名文件,这样才能保证转到AndroidStudio后更新的 ...

  8. Android 7.0 启动篇 — init原理(二)(转 Android 9.0 分析)

    ========================================================          ================================== ...

  9. Activity的绘制流程简单分析(基于android 4.0源码进行分析)

    要明白这个流程,我们还得从第一部开始,大家都知道 在activity里面 setcontentview 调用结束以后 就可以看到程序加载好我们的布局文件了,从而让我们在手机上看到这个画面. 那么我们来 ...

随机推荐

  1. 【转】H.264RTP封包原理

    原文地址:H.264RTP封包原理   作者:cnp11 1.  引言  随着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面 ...

  2. 解读2017之Service Mesh:群雄逐鹿烽烟起

    https://mp.weixin.qq.com/s/ur3PmLZ6VjP5L5FatIYYmg 在过去的2016年和2017年,微服务技术得以迅猛普及,和容器技术一起成为这两年中最吸引眼球的技术热 ...

  3. Android 众多的布局属性详解

    http://www.open-open.com/lib/view/open1328686184311.html Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了 ...

  4. java集合的contains(obj)方法的实现

    在实际项目中我们通常会有一个需求就是:想知道在一个列表中是否包含某一个对象 这里ArrayList表.HashSet表和HashMap表都提供了一个contains(obj)方法, 下面说一下两个列表 ...

  5. Centos下部署Flask

    尝试在Centos6.5下部署Flask应用并成功,记录一下步骤,参数为什么这样配置还需要再研究uwsgi和Nginx才能回答. Python版本升级2.7 测试机器centos6.5默认自带的pyt ...

  6. Pygame常用方法

    '''import pygame# 初始化pygame库,让计算机硬件准备pygame.init()# ----------窗口相关操作-----------# 创建窗口window = pygame ...

  7. Centos6离线安装MySQL5.5.55-1(附带安装包及Perl依赖包)

    资源包下载https://pan.baidu.com/s/1U3myYp4GSmDUfZocMWI9FA 密码:xdac 资源包所带有的资源截图 1.上传MySQL-client-5.5.55-1.l ...

  8. 利用Django进行Web开发

    Web就是用来表示Internet主机上供外界访问的资源的.网页也统称为web资源.Internet上供外界访问的Web资源主要分为如下两类: 静态web资源:指web页面中供人们浏览的数据始终是不变 ...

  9. IO流系列一:输入输出流的转换

    输入流转字节数组的原理1.读取输入流,每一小段 读一次,取出 byteArray .2.将该一小段byteArray写入到字节输出流ByteOutStream.直到不能从输入流再读出字节为止.3.将字 ...

  10. Tiny4412模式跳转

    ARM体系的CPU有以下7种工作模式: 1.用户模式(Usr):用于正常执行程序: 2.快速中断模式(FIQ):用于高速数据传输: 3.外部中断模式(IRQ):用于通常的中断处理: 4.管理模式(sv ...