前面六篇文章从底向上分析了SD卡挂载的流程,前面五篇文章主要是从底层往上,而第六篇文章则反其道而行之,从上层的设置界面开始往下分析,那么本篇文章会是一个引爆点,也就是说,这篇文章是从下往上和从上往下的一个交接处。因为过了段时间了,我们需要总结一下前面的文章,权当复习吧。哈哈,还是先祭处我们的老老图(T_T...)如下:
这是SD卡挂载的整个流程图,首先插入SD卡后,触发硬件中断,Kernel发出uevent;其次通过NetLinkManager初步处理接收到的uevent然后往上传递处理之后的事件信息;然后VolumeManager接着处理经过初步处理之后的时间信息并将信息进行更细致的划分和处理并传递给上层;最后上层接收到SD卡挂载后的信息并显示在界面上。
以上就是整个SD卡挂载的大致流程,下面是大致的流程图:
废话不多说,从这张图大家应该可以理解SD卡的挂载了吧。那么前面五篇博文从底向上,从Kernel发出的uevent一直到Vold,而第六篇博文则是从Setting开始一直到MountService,那么本文主要则描述底层信息最后是如何传递到上层的。如果大家遗忘了的话,还请看看前面的文章。
在第五篇博文中,我们分析到了MountService中的private void updatePublicVolumeState(String path, String state)方法,在该方法中我们当时只分析到了:
- synchronized(mListeners){
- for(inti=mListeners.size()-1;i>=0;i--){
- MountServiceBinderListenerbl=mListeners.get(i);
- try{
- bl.mListener.onStorageStateChanged(path,oldState,state);
- }catch(RemoteExceptionrex){
- Slog.e(TAG,"Listenerdead");
- mListeners.remove(i);
- }catch(Exceptionex){
- Slog.e(TAG,"Listenerfailed",ex);
- }
- }
- }
在第六篇博文中,我们知道了SD卡挂载的消息是通过注册StorageManager的存储设备状态变更监听器来实现的,如下代码:
- if(mStorageManager==null){
- mStorageManager=(StorageManager)getSystemService(Context.STORAGE_SERVICE);
- mStorageManager.registerListener(mStorageListener);
- }
那么也就是说,如果要通知到上层改变SD卡的挂载状态,底层的信息一定会触发上层注册的监听器,那么我就开始我们的旅程吧!
1.踏上征程
我们先继续查看MountService中的private void updatePublicVolumeState(String
path, String state)方法中的同步块中的方法:
- MountServiceBinderListenerbl=mListeners.get(i);
该方法是从ArrayList<MoutServiceBinderListener>中获取之前存储的bl对象,如果大家忘记了我们存储bl的地方的话,可以回头看一下上一篇博文的讲解,实际上是在MountService.java中的registerListener()方法中通过mListeners.add(bl);方法添加的。
我们接着看:
- bl.mListener.onStorageStateChanged(path,oldState,state);
我们在第五篇博文《Android 2.3 SD卡挂载流程浅析(五)》的最后,分析到了这句代码,但是只能卡在那里。但我们经过第六篇博文《Android 2.3 SD卡挂载流程浅析(六)》的讲解之后,我们应该能够顺利进行了。
这里我们跟踪mListener到MountServiceBinderListener这个类中:
- privatefinalclassMountServiceBinderListenerimplementsIBinder.DeathRecipient{
- finalIMountServiceListenermListener;
- MountServiceBinderListener(IMountServiceListenerlistener){
- mListener=listener;
- }
- publicvoidbinderDied(){
- if(LOCAL_LOGD)Slog.d(TAG,"AnIMountServiceListenerhasdied!");
- synchronized(mListeners){
- mListeners.remove(this);
- mListener.asBinder().unlinkToDeath(this,0);
- }
- }
- }
这里我们看到mListener=listener;因为我们前面已讲过,IMountServiceListener是一个接口,不可能实例化对象,因此传递的参数可以肯定是实现了它的类的对象。那么我们跟踪这里的MountServieBinderListener(IMountServiceListener listener)看传递进来的参数是什么:
- publicvoidregisterListener(IMountServiceListenerlistener){
- synchronized(mListeners){
- MountServiceBinderListenerbl=newMountServiceBinderListener(listener);
- try{
- listener.asBinder().linkToDeath(bl,0);
- mListeners.add(bl);
- }catch(RemoteExceptionrex){
- Slog.e(TAG,"Failedtolinktolistenerdeath");
- }
- }
- }
在MountService中的registerListener()方法中我们找到了它的影子,但是一看代码就知道,这里也只是一个中转站,但是看过前面文章的朋友因该想起来了吧。对,没错,这就是我前面提到过经过AIDL之后,最终调用的registerListener()方法。
那么这里MountService中的MountServiceBinderListener类中的mListener对象,是从StorageManager中的MountServiceBinderListener转换来的,转换过程前面已经有阐述这里不多讲。也就是说这里的mListener可以当作StorageManager中的MountServiceBinderListener的对象,那么这里bl.mListener.onStorageStateChanged(path,
oldState, state);的方法实际上也是StorageManager中的MountServiceBinderListener的方法。所以我们找到StorageManager中的MountServiceBinderListener类:
- privateclassMountServiceBinderListenerextendsIMountServiceListener.Stub{
- publicvoidonUsbMassStorageConnectionChanged(booleanavailable){
- finalintsize=mListeners.size();
- for(inti=0;i<size;i++){
- mListeners.get(i).sendShareAvailabilityChanged(available);
- }
- }
- publicvoidonStorageStateChanged(Stringpath,StringoldState,StringnewState){
- finalintsize=mListeners.size();
- for(inti=0;i<size;i++){
- mListeners.get(i).sendStorageStateChanged(path,oldState,newState);
- }
- }
- }
果然其中有我们寻找的onStrageStateChanged()方法,那么我们就继续分析吧。
2.披荆斩棘,直捣黄龙
- publicvoidonStorageStateChanged(Stringpath,StringoldState,StringnewState){
- finalintsize=mListeners.size();
- for(inti=0;i<size;i++){
- mListeners.get(i).sendStorageStateChanged(path,oldState,newState);
- }
- }
首先看到mListeners.get(i)这个方法我们直接就回联想到ArrayList,那么这个是这个ArrayList中存放到底是什么对象呢?如果大家对上一篇文章有影响的话应该不会陌生,这里的存放的是ListenerDelegate的对象。好了我们继续跳转到sendStorageStateChanged()方法中去:
- voidsendStorageStateChanged(Stringpath,StringoldState,StringnewState){
- StorageStateChangedStorageEvente=newStorageStateChangedStorageEvent(path,oldState,newState);
- mHandler.sendMessage(e.getMessage());
- }
那么继续跟踪StroageStateChangedStorageEvent();这个构造方法:
- privateclassStorageStateChangedStorageEventextendsStorageEvent{
- publicStringpath;
- publicStringoldState;
- publicStringnewState;
- publicStorageStateChangedStorageEvent(Stringp,StringoldS,StringnewS){
- super(EVENT_STORAGE_STATE_CHANGED);
- path=p;
- oldState=oldS;
- newState=newS;
- }
- }
在这个类中的构造方法中,我们可以看到它通过super掉了父类的构造方法,我们继续跟踪该super方法:
- privateclassStorageEvent{
- staticfinalintEVENT_UMS_CONNECTION_CHANGED=1;
- staticfinalintEVENT_STORAGE_STATE_CHANGED=2;
- staticfinalintEVENT_OBB_STATE_CHANGED=3;
- privateMessagemMessage;
- publicStorageEvent(intwhat){
- mMessage=Message.obtain();
- mMessage.what=what;
- mMessage.obj=this;
- }
- publicMessagegetMessage(){
- returnmMessage;
- }
- }
哈哈,原来是封装了一个Message,这里的what值是2。那么我们回到:
- voidsendStorageStateChanged(Stringpath,StringoldState,StringnewState){
- StorageStateChangedStorageEvente=newStorageStateChangedStorageEvent(path,oldState,newState);
- mHandler.sendMessage(e.getMessage());
- }
我们接着看mHandler.sendMessage(e.getMessage());方法,通过前面的代码,我们可以看到,e.getMessage()返回的是一个Message对象,正好这里通过mHandler发送给出去。
可能这里有朋友要问了,我怎么知道发送给谁呢?谁来接收呢?别急,我们回忆一下,在上一篇博文中,我们通过从上往下分析,最后我们分析到ListenerDelegate这个类中,发现了其中的handleMessage()方法,这里我把这个类贴出来:
- privateclassListenerDelegate{
- finalStorageEventListenermStorageEventListener;
- privatefinalHandlermHandler;
- ListenerDelegate(StorageEventListenerlistener){
- mStorageEventListener=listener;
- mHandler=newHandler(mTgtLooper){
- @Override
- publicvoidhandleMessage(Messagemsg){
- StorageEvente=(StorageEvent)msg.obj;
- if(msg.what==StorageEvent.EVENT_UMS_CONNECTION_CHANGED){
- UmsConnectionChangedStorageEventev=(UmsConnectionChangedStorageEvent)e;
- mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
- }elseif(msg.what==StorageEvent.EVENT_STORAGE_STATE_CHANGED){
- StorageStateChangedStorageEventev=(StorageStateChangedStorageEvent)e;
- mStorageEventListener.onStorageStateChanged(ev.path,ev.oldState,ev.newState);
- }else{
- Log.e(TAG,"Unsupportedevent"+msg.what);
- }
- }
- };
- }
- StorageEventListenergetListener(){
- returnmStorageEventListener;
- }
- voidsendShareAvailabilityChanged(booleanavailable){
- UmsConnectionChangedStorageEvente=newUmsConnectionChangedStorageEvent(available);
- mHandler.sendMessage(e.getMessage());
- }
- voidsendStorageStateChanged(Stringpath,StringoldState,StringnewState){
- StorageStateChangedStorageEvente=newStorageStateChangedStorageEvent(path,oldState,newState);
- mHandler.sendMessage(e.getMessage());
- }
- }
哈哈,handleMessage()远在天边近在眼前啊。
那我们赶紧继续吧。我们在handleMessage()中找到如下方法:
- StorageStateChangedStorageEventev=(StorageStateChangedStorageEvent)e;
- mStorageEventListener.onStorageStateChanged(ev.path,ev.oldState,ev.newState);
这里的mStorageEventListener,是通过ListenerDelegate(StorageEventListener listener)的构造方法传递的StorageEventListener对象,因此这里也就是去调用StorageEventListener中的onStorageStateChanged()方法,传递的参数:ev.path,ev.oldState,ev.newState
这些参数都是从MountService那里传送过来的。
3.胜利在望
现在我们回到Memory.java中,这里为什么要回到Memory.java中呢?如果我们直接去StorageEventListener这个类中会发现实际山该类只是一个接口,其中只有空方法。我们回到Memory.java中可以看到:
- StorageEventListenermStorageListener=newStorageEventListener(){
- @Override
- publicvoidonStorageStateChanged(Stringpath,StringoldState,StringnewState){
- Log.i(TAG,"Receivedstoragestatechangednotificationthat"+
- path+"changedstatefrom"+oldState+
- "to"+newState);
- updateMemoryStatus();
- }
- };
在Memory.java中,我们可以看到通过匿名内部类的方法,实现了StorageEventListener中的onStorageStateChanged()方法,因此,最终的调用这里的onStorageStateChanged()方法。这样SD卡挂载的消息我们可以通过抓取这里的log来看到。
接下来分析updateMemoryStatus():
- privatevoidupdateMemoryStatus(){
- Stringstatus=Environment.getExternalStorageState();
- StringreadOnly="";
- if(status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)){
- status=Environment.MEDIA_MOUNTED;
- readOnly=mRes.getString(R.string.read_only);
- }
- if(status.equals(Environment.MEDIA_MOUNTED)){
- if(!Environment.isExternalStorageRemovable()){
- if(mSdMountToggleAdded){
- mSdMountPreferenceGroup.removePreference(mSdMountToggle);
- mSdMountToggleAdded=false;
- }
- }
- try{
- Filepath=Environment.getExternalStorageDirectory();
- StatFsstat=newStatFs(path.getPath());
- longblockSize=stat.getBlockSize();
- longtotalBlocks=stat.getBlockCount();
- longavailableBlocks=stat.getAvailableBlocks();
- mSdSize.setSummary(formatSize(totalBlocks*blockSize));
- mSdAvail.setSummary(formatSize(availableBlocks*blockSize)+readOnly);
- mSdMountToggle.setEnabled(true);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
- }catch(IllegalArgumentExceptione){
- status=Environment.MEDIA_REMOVED;
- }
- }else{
- mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
- mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
- if(!Environment.isExternalStorageRemovable()){
- if(status.equals(Environment.MEDIA_UNMOUNTED)){
- if(!mSdMountToggleAdded){
- mSdMountPreferenceGroup.addPreference(mSdMountToggle);
- mSdMountToggleAdded=true;
- }
- }
- }
- if(status.equals(Environment.MEDIA_UNMOUNTED)||
- status.equals(Environment.MEDIA_NOFS)||
- status.equals(Environment.MEDIA_UNMOUNTABLE)){
- mSdMountToggle.setEnabled(true);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
- }else{
- mSdMountToggle.setEnabled(false);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
- }
- }
- Filepath=Environment.getDataDirectory();
- StatFsstat=newStatFs(path.getPath());
- longblockSize=stat.getBlockSize();
- longavailableBlocks=stat.getAvailableBlocks();
- findPreference("memory_internal_avail").setSummary(formatSize(availableBlocks*blockSize));
- }
分析到这里我们的目的已经实现了。如果忘记了我们的目的那我这里重申一次:从SD卡插入一直到SD卡挂载信息显示到系统设置界面的过程分析。
总结:先说一下分析SD卡挂载流程这件事情的起因。因为工作原因,接触到了Android,但是在检测SD卡挂载着一块始终有些问题,多方搜索后无果,那我就自己硬着头皮啃吧。一开始找起点,怎么找呢?发现系统设置里面有SD卡挂载的相关信息,那么就开始从Android系统设置的源码开始找,逐渐的发现,越深入越复杂。对于我这个新手来说很多东西不懂,经过不断的搜索,以及查询相关资料,最终奋战了2个星期将SD卡的挂载流程大致分析清楚了。因为自己也是新手,所以很多东西分析得不一定都对,所以还望读者指出错误。
经过本次源码分析,学习到了很多知识,这些知识其实在书本上也有提到,但需要真正理解其意思的话,必须要通过实践。
分享到:
相关推荐
Android23SD卡挂载流程浅析.docx
Android23SD卡挂载流程浅析.doc
本文档基于android4.2平台,sd卡热插拔在android层是如何传递消息
主要介绍了Android2.3实现SD卡与U盘自动挂载的方法,较为详细的分析了Android2.3实现SD卡与U盘自动挂载的具体步骤与相关技巧,需要的朋友可以参考下
但是每款定制过的android 系统的外置SD卡的路径都不一样,那我们怎么才能去获取这个路径呢,我们可以想其它的办法,我这里提供了一个类可以获取外置SD卡或内置SD卡的 label(名称),path(路径),mount_point(挂载点)...
本文实例讲述了Android判断SD卡是否已经挂载的方法。分享给大家供大家参考。具体如下: 提供一个监听方法BroadcastReceiver 设置IntentFilter为: Intent.ACTION_MEDIA_MOUNTED Intent.ACTION_MEDIA_EJECT Intent....
AndroidStudio编写
SD卡任意挂载工具
SD卡挂载高歌好用
android 内部存储 sd卡app私有文件 等
android读取sd卡中MP3文件
在ubuntu系统中1、 查看sd卡名字,2、挂在sd卡,3、 查看sd卡内容,
这是一个修改自内核的SD driver 模块 :linux3.4.2 SD/MMC/TF卡挂载问题的解决
android 读取和存储sd卡一个例子,欢迎下载!
Android手机SD卡文件浏览器:遍历出手机Sd卡中的文件。
android浏览SD卡目录文件,实现音频播放
android 读取外置和内置存储卡路径和大小,亲测好使,项目中以运用