转自:http://blog.sina.com.cn/s/blog_6100a4f10101ee40.html
一 storage功能相关模块
base/services/java/com/android/server/MountService.java
- PackageManagerService.java
base/services/java/com/android/server/pm/PackageManagerService.java
base/core/java/android/os/storage/StorageManager.java
- DefaultContainerService.java
base/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
- Settings—storage/application
packages/apps/Settings/src/com/android/settings
system/vold
二 StorageManager
2.1 方法/类/变量
package
android.os.storage
class
StorageManager
MountServiceBinderListener [StorageManager]
ObbActionListener [StorageManager]
ObbListenerDelegate [StorageManager]
ObbStateChangedStorageEvent [StorageManager]
StorageEvent [StorageManager]
UmsConnectionChangedStorageEvent [StorageManager]
StorageStateChangedStorageEvent [StorageManager]
ListenerDelegate [StorageManager]
field
TAG [StorageManager]
PROP_SD_DEFAULT_PATH [StorageManager]
PROP_SD_INTERNAL_PATH [StorageManager]
PROP_SD_EXTERNAL_PATH [StorageManager]
ICS_STORAGE_PATH_SD1 [StorageManager]
ICS_STORAGE_PATH_SD2 [StorageManager]
STORAGE_PATH_SD1 [StorageManager]
STORAGE_PATH_SD2 [StorageManager]
mMTKExternalCacheDir [StorageManager]
mMountService [StorageManager]
mTgtLooper [StorageManager]
mBinderListener [StorageManager]
mListeners [StorageManager]
mNextNonce [StorageManager]
mObbActionListener [StorageManager]
mListeners [StorageManager.ObbActionListener]
mObbEventListenerRef [StorageManager.ObbListenerDelegate]
mHandler [StorageManager.ObbListenerDelegate]
nonce [StorageManager.ObbListenerDelegate]
path [StorageManager.ObbStateChangedStorageEvent]
state [StorageManager.ObbStateChangedStorageEvent]
EVENT_UMS_CONNECTION_CHANGED [StorageManager.StorageEvent]
EVENT_STORAGE_STATE_CHANGED [StorageManager.StorageEvent]
EVENT_OBB_STATE_CHANGED [StorageManager.StorageEvent]
mMessage [StorageManager.StorageEvent]
available [StorageManager.UmsConnectionChangedStorageEvent]
path [StorageManager.StorageStateChangedStorageEvent]
oldState [StorageManager.StorageStateChangedStorageEvent]
newState [StorageManager.StorageStateChangedStorageEvent]
mStorageEventListener [StorageManager.ListenerDelegate]
mHandler [StorageManager.ListenerDelegate]
method
onUsbMassStorageConnectionChanged [StorageManager.MountServiceBinderListener]
onStorageStateChanged [StorageManager.MountServiceBinderListener]
onObbResult [StorageManager.ObbActionListener]
addListener [StorageManager.ObbActionListener]
getNextNonce [StorageManager]
ObbListenerDelegate [StorageManager.ObbListenerDelegate]
getListener [StorageManager.ObbListenerDelegate]
sendObbStateChanged [StorageManager.ObbListenerDelegate]
ObbStateChangedStorageEvent [StorageManager.ObbStateChangedStorageEvent]
StorageEvent [StorageManager.StorageEvent]
getMessage [StorageManager.StorageEvent]
UmsConnectionChangedStorageEvent [StorageManager.UmsConnectionChangedStorageEvent]
StorageStateChangedStorageEvent [StorageManager.StorageStateChangedStorageEvent]
ListenerDelegate [StorageManager.ListenerDelegate]
getListener [StorageManager.ListenerDelegate]
sendShareAvailabilityChanged [StorageManager.ListenerDelegate]
sendStorageStateChanged [StorageManager.ListenerDelegate]
from [StorageManager]
StorageManager [StorageManager]
registerListener [StorageManager]
unregisterListener [StorageManager]
enableUsbMassStorage [StorageManager]
disableUsbMassStorage [StorageManager]
isUsbMassStorageConnected [StorageManager]
isUsbMassStorageEnabled [StorageManager]
mountObb [StorageManager]
unmountObb [StorageManager]
isObbMounted [StorageManager]
getMountedObbPath [StorageManager]
getVolumeState [StorageManager]
getVolumeList [StorageManager]
getVolumePaths [StorageManager]
getPrimaryVolume [StorageManager]
getPrimaryVolume [StorageManager]
getDefaultPath [StorageManager]
setDefaultPath [StorageManager]
getMTKExternalCacheDir [StorageManager]
getExternalStoragePath [StorageManager]
getInternalStoragePath [StorageManager]
2.2 工作流程
应用PhoneStatusBarPolicy.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
调用StorageManager的监听注册函数,将监听的StorageEventListener注册到StorageManager中,当有状态变化时,会调用该类的对应函数。通常在具体需要storage状态变化的场景会定义一个新类,继承于StorageEventListener。下面注册到StorageManager的listener就是继承于StorageEventListener。
// storage
mStorageManager=(StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
mStorageManager.registerListener(new com.android.systemui.usb.StorageNotification(context));
com.android.systemui.usb.StorageNotification就是继承于StorageEventListener。
1) registerListener
public void registerListener(StorageEventListener listener) {
if (listener == null) {
return;
}
synchronized (mListeners) {
if (mBinderListener == null ) {
try {
mBinderListener = new MountServiceBinderListener();
mMountService.registerListener(mBinderListener);
} catch (RemoteException rex) {
Log.e(TAG, "Register mBinderListener failed");
return;
}
}
mListeners.add(new ListenerDelegate(listener));
}
}
2) StorageManager的registerListener有两个功能,一个是接收其他应用过来的申请,将他们的StorageEventListener,转换成ListenerDelegate 对象,然后保存在mListeners 这个数组中。
private List<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
mListeners.add(new ListenerDelegate(listener));
另外一个功能就是向mountService注册listener,StorageManager也是个中间者,拿不到一手信息,需要从上线拿到资源,所以它需要向mountService注册listener。
mBinderListener = new MountServiceBinderListener();
mMountService.registerListener(mBinderListener);
注册进去的类型为MountServiceBinderListener,是MountServiceListener的实现。
特别注意:在mountService中,对注册进来的MountServiceBinderListener又做了一层处理,恶心的是两个类是同一个名字。
MountServiceBinderListener bl = new MountServiceBinderListener(listener);
参数listener的类型是上面蓝色的,从StorageManager传过来,红色的是mountService中的类,类似于StorageManager中的ListenerDelegate。实现如下:
private final class MountServiceBinderListener implements IBinder.DeathRecipient {
final IMountServiceListener mListener;
MountServiceBinderListener(IMountServiceListener listener) {
mListener = listener;
}
StorageManager和MountService都有一个用来记录外边注册进来的listener的数组mListeners,但是使用的类型都是自己包中定义的类,都对传进来的进行了处理。
3) 从底向上的触发
MountService的onEvent会收到底层的调用,进而触发相应的动作,例如调用updatePublicVolumeState,这里边就会调用注册进来的listener的成员函数; bl.mListener.onStorageStateChanged。这样就进入到了StorageManager,其中的listener,MountServiceBinderListener的onStorageStateChanged会被触发。进而依次触发每一个注册到StorageManager的listener,sendStorageStateChanged,发出EVENT_STORAGE_STATE_CHANGED消息。在每个listener注册到StorageManager时,通过ListenerDelegate进行过一次打包,在其构造函数中对每个listener创建了一个handler,不停的接收消息并处理。当接收到EVENT_STORAGE_STATE_CHANGED后就调用注册进来的listener的onStorageStateChanged方法。如上即为com.android.systemui.usb.StorageNotification的onStorageStateChanged函数,所以该类的onStorageStateChanged方法需要重载。
以上内容参考了这篇文章:usb状态相关处理
2.3 功能调用
上面介绍的是上层如何获取系统及底层信息的中断通知的方式,除了这种被动通知状态改变的行为以外,更多的则是应用主动的获取系统的storage信息。这个功能就相对简单、直白了,可以直接调用StorageManager的成员方法。
1) ums功能的使能/禁能/状态查询
2)obb的挂载/卸载及查询
3)获取分区的所有信息:分区列表/挂载点状态/主分区路径等
4) 应用的默认存储路径的管理及内外置卡的路径获取
JB的挂载路径较ics做了更新:
private static final String ICS_STORAGE_PATH_SD1 = "/mnt/sdcard";
private static final String ICS_STORAGE_PATH_SD2 = "/mnt/sdcard2";
private static final String STORAGE_PATH_SD1 = "/storage/sdcard0";
private static final String STORAGE_PATH_SD2 = "/storage/sdcard1";
JB版本以后,为了兼容ICS,将/mnt/sdcard链接到/storage/sdcard0。
2.4 使用方法
mStorageManager=(StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
mStorageManager.functions;
2.5 StorageManager总结
如果外界需要知道系统的storage信息,直接调用StorageManager的方法。那么如果需要实时的知道状态的改变,就需要派一个信使驻扎在StorageManager家里,当有状态变化时,StorageManager会通知驻扎在他家的信使,listener。这就是为什么要安排驻京人员,能够及时的拿到一手信息。
三 MountService
3.1 MountService与StorageManager的交互
紧接上面的StorageManager,MountService是为framework层和StorageManager服务的,StorageManager为应用程序服务。
-----------------------下面来自网友总结
MountService是运行在SystemService这个进程中,所以上层应用无法直接访问,StorageManager就是提供给应用层来访问存储服务的,它通过Binder机制与MountService所在进程进行通信,将使用者的请求转发进MountService中进行处理。目前StorageManager中支持的方法有enableUsbMassStorage,disableUsbMassStorage,isUsbMassStorageConnected,isUsbMassStorageConnected。在StorageManager的构造函数中,还通过调用MountService中的registerListener函数来注册listener到MountService,同时,它自己也提供了registerListener函数供其它应用来注册listener,这样,当MountService知道存储设备状态变更时,会调用StorageManager中listener的方法,而StorageManager又会继续回调上去,上层应用也就可以做相应的操作,比如图示的更新等。
MountService是一个服务类,在ServiceManager中注册为系统服务,提供对外部存储设备的管理、查询等服务,并在存储设备状态变更时发出通知。MountService起到了一个承上启下的作用,向上公开方法供上层对存储设备进行操作(enable/disable/mount…),并在存储设备状态变更时发出通知。向下接收Vold发来的事件(设备状态变更,设备插入,设备移除等),同时也会将命令发送给Vold,进行更底层的操作。
------------------
3.2 工作流程
工作流程有几个:首先是构造函数的准备工作、一些接口的被调用、以及监听回调。
1) 构造函数
Mediatek/custom/mt8389_tablet_a3v2/resource_overlay/generic/frameworks/base/core/res/res/xml/
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/storage/sdcard0"
android:storageDescription="@string/storage_usb"
android:allowMassStorage="true"
android:mtpReserve="10485760"
android:primary="true" />
<storage android:mountPoint="/storage/sdcard1"
android:storageDescription="@string/storage_sd_card"
android:removable="true"
android:allowMassStorage="true"
android:mtpReserve="10485760"
android:primary="false" />
<storage android:mountPoint="/mnt/usbotg"
android:storageDescription="@string/storage_external_usb"
android:removable="true"
android:primary="false" />
</StorageList>
但是vold 中关于外部存储器的挂载路径是在
mediatek /config/mt8389_tablet_a3v2/vold.fstab文件中指定的,
dev_mount sdcard /storage/sdcard0 emmc@fat /devices/platform/goldfish_mmc.0
/devices/platform/mtk-msdc.0/mmc_host
dev_mount sdcard2 /storage/sdcard1 auto /devices/platform/goldfish_mmc.1
/devices/platform/mtk-msdc.1/mmc_host
dev_mount usbotg /mnt/usbotg auto /devices/platform/mt_usb
/devices/platform/musbfsh_hdrc
所以这个xml和vold.fstab的路径必须统一。
readStorageList函数通过解析xml,丰富了系统的分区信息。mVolumes、mVolumeMap和mPrimaryVolume。
2) intent 接收处理
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
String action = intent.getAction();
通过在构造函数中注册intentfilter,接收系统发出的intent,执行相应的动作。
3) Callback from NativeDaemonConnector
MountService注册到NativeDaemonConnector 的两个回调函数:onDaemonConnected和onEvent。在构造函数创建NativeDaemonConnector时,将MountService植入进了NativeDaemonConnector。
onDaemonConnected在NativeDaemonConnector线程开始运行,创建socket监听时,执行一次。onEvent是在listenToSocket每次读取socket信息,然后通过mCallbackHandler发送消息,随后在handleMessage中调用onEvent。
当vold发生动作时,通过NativeDaemonConnector完成向上的通知。
NativeDaemonConnector和vold使用的是socket连接,大概使用流程如下:
{
LocalSocket socket = null;
socket = new LocalSocket();//创建socket
//创建目的地的socket地址
LocalSocketAddress address = new LocalSocketAddress(mSocket,
LocalSocketAddress.Namespace.RESERVED);//mSocketà "vold"
socket.connect(address);//连接目的socket
InputStream inputStream = socket.getInputStream()//获取inputStream
inputStream.read(buffer, start, BUFFER_SIZE - start);//读取socket数据
}
在init.rc中,vold服务启动时,创建与framework通讯的socket
service vold /system/bin/vold
class core
socket vold stream 0660 root mount
ioprio be 2
3)功能调用
如setUsbMassStorageEnabled,有其他功能直接调用。
mountVolume----àdoMountVolume-------àmConnector.execute(cmd);
3.3 使用方法
1)定义变量
private IMountService mMountService;
2)获取实例
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
3)调用功能
mMountService.registerListener(mBinderListener);
3.4 MountService总结
MountService是一个核心处理功能,承上启下。他的具体功能通过他提供的各种方法来体现。如何工作上面的工作流程已经涵盖。
四 volume demo
参考文档:
http://terryblog.blog.51cto.com/1764499/826656
android系统vold透析
这两篇文章已经讲的很好,下面只是部分功能点的说明。
4.1 vold/kernel简介
----------网友
kernel层能检测到有新的设备接入,加载相应的驱动,但如何通知用户层呢?这就是sysfs的工作,内核中的sysfs机制要求当有新的驱动加载时给用户层发送相应的event.但这些event只尽告知的义务,具体怎么处理,这就是vold的事了。
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事件的数据。
Vold.fstab文件中的设备路径是设备在sys下的路径,并不是kernel为该设备创建的节点:
dev_mount sdcard /storage/sdcard0 emmc@fat /devices/platform/goldfish_mmc.0
/devices/platform/mtk-msdc.0/mmc_host
#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################
Kernel 创建完设备节点后又再sys下创建了相关的内容,进而发出了uevent,让vold中的socket,NetLinkManager.cpp来处理,进而根据vold.fstab的配置挂载到指定的目录。那么kernel是如何将sys下创建的目录对象和具体的设备对应起来的呢?todo:sys
4.2 vold 代码流程
1)入口:System/vold/main.c
a)创建3个vold框架使用的对象
VolumeManager *vm;
CommandListener *cl; 接收上层MountService的命令,分析后转给volumeManager,处理后返给MountService或者交给volume执行具体操作。
NetlinkManager *nm; 创建与内核通讯的socket,接收底层的信息,交给volumeManager
b)解析/etc/vold.fstab
process_config
2)netlinkManager
3)commandListener
4)volumeManager
分区管理类,volume.cpp代理人。真正的分区动作都在volume.cpp来完成。
5)其他文件
Fat.cpp/bicr.cpp/Ext4.cpp
这些都是volume等配套的具体功能文件,最后一个环节。
2013-7-31: vold和kernel配合工作的流程:首先vold在开始执行时,通过解析vold.fstab得知了该设备用户层最终需要管理的存储设备分区信息,针对需要挂载的分区信息,创建对应的DirectVolume,放入VolumeManager中进行管理。解析vold.fstab时如果是emmc是要从/proc/emmc中获取信息的,以防止vold.fstab写的信息有误。所以上面这部分工作只是准备工作,意思是当有对应的分区设备在内核空间出现时,用户空间应该如何去处理,挂载还是不挂载,挂载点是哪里。那么当内核空间的设备创建时通过uevent机制传递到netlinkManager时,会调用到netlinkHandler.cpp的onEvent,进入调用VolumeManager的handleBlockEvent,意思是处理块设备变化,由于开始时已经将vold.fstab中的分区信息创建对应的DirectVolume添加到了VolumeManager容器中,然后找出容器中的某个DirectVolume执行handleBlockEvent。