Android的USB系统之二 (Vold和mountservice分析)

1Vold功能分析

1.1Vold的主要作用

Android系统中为了统一管理磁盘而引入Vold 负责磁盘的挂载等。

vold是一个中间层,负责来连接上层以及驱动层。其实vold主要抓住两点:一是在CommandListener.cpp中处理上层发下来的命令,二是在NetlinkHandler.cpp中处理底层发送上来的各种信息。

vold与上层之间是通过DomainSocket来通讯的,与下层之间是通过NetLinkSocket和sysfs来实现通讯的,即通过NetLinkSocket来截取usb驱动和mmc发送上来的uevent事件。主要处理subsys= block的uevent,即block设备的添加、移除等。

有关磁盘管理部分其他文章分析。


1.2Vold启动

Vold是在init进程中启动的,在init进程中将解析 init.rc 文件,在该文件中有启动Vold的配置。在这里将启动 Vold ,并且创建一个 socket。这socket 主要是为了与 framework 层通信。 如下面所示:

servicevold/system/bin/vold

class core

socket vold stream 0660 root mount

ioprio be 2

1.3Vold通信

由于它负责两方面的通信,所以他有一共有两条socket:

1)Domainsocket: 负责vold与framework层的信息传递;

Domainsocket是在init进程启动Vold时创建的,这是一个用于和framework层通信的 socket,在android系统中有个封装类Localsocket。

在framework层的MountService类中调用下面

mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "vold", 10,VOLD_TAG,25);

MountService通过NativeDaemonConnector和Vold中的CommandListener建立socket通信。其中 mSocket值为“vold”表示要获得 socket的名字,该 socket如上所述,是在vold被 init的时候创建的,并且保存为全局变量。

NavtiveDaemonConnector位于frameworks\base\services\java\com\android\server目录下,他会开启一个线程不停的监听来自vold的消息,所以这里有可能消息堵塞。NavtiveDaemonConnector   类封装实例化一个 LocalSocket 来与 vold 通信。LocalSocket 里面有一个类 LocalSocketImpl  ,该类部分函数时通过 JNI实现的。

2)Netlinksocket: 负责接受kernel的信息;

Netlinksocket是在NetLinkManager的start()中创建的。

1.4事件处理

这里通过对两个连结的监听,完成对动态事件的处理,以及对上层应用操作的响应。我们来具体分析一下代码过程。

1)kernel发出 uevent

NetLinkManager 检测 kernel 发出的 uevent,经过解析后,调用NetLinkHandler::onEvent()。如下所示:

void NetlinkHandler::onEvent(NetlinkEvent *evt) {

   VolumeManager *vm = VolumeManager::Instance();

   constchar*subsys = evt->getSubsystem();

   if(!subsys) {

           SLOGW("No subsystem found innetlinkevent");

           return;

   }

if(!strcmp(subsys,"block")) {

     vm->handleBlockEvent(evt);

}elseif(!strcmp(subsys,"usb")|| !strcmp(subsys,"scsi_device")) {

     SLOGW("subsystem found innetlinkevent");

    MiscManager *mm = MiscManager::Instance(); 

   mm->handleEvent(evt);

}

}

对于不同的时间类型分别处理。“block”事件由 VolumeManager的 handleBlockEvent(evt)处理,最终调用的是DirectVolume的 handleBlockEvent(evt)。block主要指对 volume的一些操作的事件,如插入,拔掉外接存储设备。

vm->handleBlockEvent(evt)->DirectVolume::handleBlockEvent(NetlinkEvent *evt).

DirectVolume::handleBlockEvent这个方法就是具体负责拔插操作的方法。

“scsi_device"”事件由MiscManager处理。现在一般是处理3G DONGLE热拔插设备。

2)framework层发出命令

和上面过程正好相反,CommandListener检测到framework层的命令,调用VolumeManager的函数,VolumeManager遍历Volume清单找出对应的volume, 调用volume的函数。 而volume类中的相关调用,最终调用到Linux库函数,完成相关操作。

代码位于CommandListener.cpp中:

if(!strcmp(argv[1],"list")) {

   returnvm->listVolumes(cli);

}elseif(!strcmp(argv[1],"mount")) {

   if(argc != 3) {

         cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume mount ",false);

       return 0;

    }

    rc = vm->mountVolume(argv[2]);

}elseif(!strcmp(argv[1],"unmount"))

......

1.5Uevent简介

Uevent 由内核发出,通过netlink sokect 来传递给 vold,在 kobject 被创建的时候,就会发生uevent的传递。 对于未传递的uevent, 会在kset下产生uevent文件, 这是供用户态触发uevent使用的,通过向uevent 档写入 action(add,remove 等) ,可以触发一个 uevent,这些 uevent

可以被vold 捕获,从而完成未完成的 vold 处理。在系统启动的时候,vold 未启动的时候,这些 uevent 写入了 uevent 檔,vold 启动后,会扫描 sys 目录查找 uevent,然后触发它们,来完成之前未完成的事宜。uevent文件的内容,就是uevent 事件的数据。

1.6APP2SD

1.6.1APP2SD简介

App2SD的功能是将apk安装在外部存储器上,而不是内部data分区,这样可以节省内部data分区。从Gingerbread之后就开始支持这个功能,具体的方法是在apk的AndroidManifest.xml中声明要安装的位置。

android:installLocation="preferExternal"    ... >

1.6.2APP2SD实现简单分析

app2sd的实现,需要vold里面asec相关操作支持才能完成,否则安装到外部存储器的apk在机器重启后就会消失。

PM在判断akp是安装在内部还是外部之后,会调用createAsec(...bool isExternal)来创建用来存放apk数据的一个Fat或者Ext4的文件系统。

具体调用流程如下:PackageHelper::createSdDir()--->mountService.createSecureContainer(cid, sizeMb, "fat", sdEncKey, uid, isExternal);---CommandListener-->VolumeManager::createAsec(const char *id, ...bool isExternal)

其中创建asec的流程请详细分析代码,其中主要思路是在/mnt/secure/asec/id.asec这路径下创建一个loop设备,然后把这个loop设备挂载到/mnt/asec/目录下。此时如果vold没有创建/mnt/secure/asec的话,这个目录就是在根文件系统中的一个临时文件,在重启后就会消失。具体看代码VolumeManager.cpp中有关asec和obb部分的实现。

1.6.3/mnt/secure/asec/的由来

在Volume.cpp中的mountVol()函数中,如果是flash挂载就按照如下流程处理:

1).把flash设备挂载在/mnt/secure/staging

2).创建/mnt/secure/staging/.android_secure文件夹

3).Bind mount /mnt/secure/staging/.android_secure -> /mnt/secure/asec //一个文件系统

4).Mount a read-only, zero-sized tmpfs  on /android_secure

5).把/mnt/secure/staging move到mountpoint

这样子看来其实/mnt/secure/asec/是flash中的一个文件夹.android_secure被挂载成了一个fat的文件系统,这样就保证在里面创建的文件不会丢失。

挂载成功后在mount命令中可以看到如下信息:

/dev/block/vold/31:9 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec........

/dev/block/vold/31:9 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev............

1.6.4判断是否支持APP2SD

Android上层代码中判断是否支持APP2SD的方法一般是判断主分区是否是虚拟的,如果不是虚拟的就要实现APP2SD。

public static boolean isExternalStorageEmulated() {

   final StorageVolume primary = getPrimaryVolume();

   return (primary != null && primary.isEmulated());

}

2MountService简介


2.1MountService功能介绍:

MountService是一个服务类,在ServiceManager中注册为系统服务,提供对外部存储设备的管理、查询等服务,并在存储设备状态变更时发出通知。MountService起到了一个承上启下的作用,向上公开方法供上层对存储设备进行操作(enable/disable/mount…),并在存储设备状态变更时发出通知。向下接收Vold发来的事件(设备状态变更,设备插入,设备移除等),同时也会将命令发送给Vold,进行更底层的操作。

MountService中的主要方法如下表所示:


2.2MountService同Vold的交互

MountService通过NativeDaemonConnector来和Vold传递信息, NativeDaemonConnector是一个继承自 Runnable 的类,它的构造函数中需要传入一个回调接口,在它的 run 函数里会创建 socket 并一直监听,当收到需要上层处理的信息时,会调用传入接口中的 onEvent。NativeDaemonConnector中也提供了 doCommond方法向 socket 另一端发送信息。 MountService 会在构造函数中创建一个 NativeDaemonConnector的实例,把自身作为参数传递进去用以回调,然后开启这个线程,这样就创建了同 Vold 通信的 socket 并监听来自vold的消息。 这些消息包括: VolumeStateChange, ShareAvailabilityChange, VolumeDiskInserted,VolumeDiskRemoved,VolumeBadRemoval,收到消息后回调 onEvent 做处理。MountService也能通过调用 doCommond向 Vold发送消息。一个简单的发送命令的代码:

public int mountSecureContainer(String id, String key,intownerUid) {

  int rc = StorageResultCode.OperationSucceeded;

  try{

        mConnector.execute("asec","mount", id,newSensitiveArg(key),ownerUid);

  }catch(NativeDaemonConnectorException e) {

     int code = e.getCode();

     if(code != VoldResponseCode.OpFailedStorageBusy) {

           rc = StorageResultCode.OperationFailedInternalError;

      }

  }

returnrc;

}

2.3MountService同StroageManager的交互

MountService 是运行在 SystemService 这个进程中,所以上层应用无法直接访问,StorageManager就是提供给应用层来访问存储服务的,它通过Binder 机制与 MountService所在进程进行通信,将使用者的请求转发进MountService 中进行处理。 目前StorageManager中支持的方法有enableUsbMassStorage, disableUsbMassStorage,isUsbMassStorageConnected,isUsbMassStorageConnected。在 StorageManager 的构造函数中,还通过调用 MountService中的 registerListener 函数来注册 listener 到 MountService,同时,它自己也提供了registerListener 函数供其它应用来注册 listener,这样,当 MountService 知道存储设备状态变更时,会调用 StorageManager中 listener的方法,而 StorageManager又会继续回调上去上层应用也就可以做相应的操作。

2.4MountService同PackageManagerService的交互

PackageManagerService 是一个用于管理设备中所有 apk的服务。 当外部存储设备被挂载或卸除时,会通知 PackagemanagerService 更新状态。然后 PackageManagerService 通过PackageHelper调用MountService中 secure container相关方法。比如app 安装在外部存储上,当外部存储状态变化就会通知应用更新。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容