Android Service之MountService源码分析

本文深入探讨了Android系统的存储设备管理框架,特别是MountService与Vold进程之间的交互机制。介绍了MountService如何创建线程处理消息,以及如何通过socket与Vold通信以实现设备挂载与卸载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 存储设备管理框架

android之VOLD进程启动源码分析一文中介绍了存储设备的管控中心Vold进程,Vold属于native后台进程,通过netlink方式接收kernel的uevent消息,并通过socket方式将uevent消息发送给MountService,同时实时接收MountService的命令消息,MountService,Vold,Kernel三者的关系如下图所示:


android之VOLD进程启动源码分析一文中介绍了NetlinkManager模块在启动过程中,创建了一个socket监听线程,用于监听kernel发送过来的uevent消息;CommandListener模块在启动时同样创建了一个socket监听线程,不同的是该线程用于监听MountServcie的连接,接收MountService向Vold发送的命令消息;MountService要接收来自kernel的uevent消息,必定也需要创建一个socket监听线程,在接下来将对该socket监听线程进行详细讲解。

Android MountService框架设计

MountService作为Android的Java服务之一,在SystemServer进程启动的第二阶段创建并注册到ServiceManager中,同时长驻于SystemServer进程中,MountService创建及注册过程如下:

  1. MountService mountService = null;  
  2. if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {  
  3.     try {  
  4.         /* 
  5.          * NotificationManagerService is dependant on MountService, 
  6.          * so we must start MountService first. 
  7.          */  
  8.         Slog.i(TAG, "Mount Service");  
  9.         mountService = new MountService(context);  
  10.         //注册到ServiceManager中   
  11.         ServiceManager.addService("mount", mountService);  
  12.     } catch (Throwable e) {  
  13.         reportWtf("starting Mount Service", e);  
  14.     }  
  15. }  
MountService mountService = null;
if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
	try {
		/*
		 * NotificationManagerService is dependant on MountService,
		 * so we must start MountService first.
		 */
		Slog.i(TAG, "Mount Service");
		mountService = new MountService(context);
		//注册到ServiceManager中
		ServiceManager.addService("mount", mountService);
	} catch (Throwable e) {
		reportWtf("starting Mount Service", e);
	}
}

MountService各个类关系图:


构造MountService对象实例:

  1. public MountService(Context context) {  
  2.     mContext = context;   
  3.     //从xml中读取存储设备列表   
  4.     readStorageList();  
  5.   
  6.     if (mPrimaryVolume != null) {  
  7.         mExternalStoragePath = mPrimaryVolume.getPath();  
  8.         mEmulateExternalStorage = mPrimaryVolume.isEmulated();  
  9.         if (mEmulateExternalStorage) {  
  10.             Slog.d(TAG, "using emulated external storage");  
  11.             mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);  
  12.         }  
  13.     }  
  14.       
  15.     //add mount state for inernal storage in NAND   
  16.     if (Environment.getSecondStorageType() == Environment.SECOND_STORAGE_TYPE_NAND) {  
  17.         mVolumeStates.put(Environment.getSecondStorageDirectory().getPath(), Environment.MEDIA_MOUNTED);  
  18.     }  
  19.     // 查询PackageManagerService服务   
  20.     mPms = (PackageManagerService) ServiceManager.getService("package");  
  21.     IntentFilter filter = new IntentFilter();  
  22.     filter.addAction(Intent.ACTION_BOOT_COMPLETED);  
  23.     // don't bother monitoring USB if mass storage is not supported on our primary volume   
  24.     if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {  
  25.         filter.addAction(UsbManager.ACTION_USB_STATE);  
  26.     }  
  27.     //注册开机完成及USB状态变化广播接收器   
  28.     mContext.registerReceiver(mBroadcastReceiver, filter, nullnull);  
  29.     //创建并启动一个带消息循环的MountService工作线程   
  30.     mHandlerThread = new HandlerThread("MountService");  
  31.     mHandlerThread.start();  
  32.     //为MountService工作线程创建一个Handler   
  33.     mHandler = new MountServiceHandler(mHandlerThread.getLooper());  
  34.   
  35.     //为MountService工作线程创建一个ObbActionHandler   
  36.     mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());  
  37.   
  38.     /* 
  39.      * Create the connection to vold with a maximum queue of twice the 
  40.      * amount of containers we'd ever expect to have. This keeps an 
  41.      * "asec list" from blocking a thread repeatedly. 
  42.      */  
  43.     mConnector = new NativeDaemonConnector(this"vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);  
  44.     //创建并启动一个socket连接监听线程   
  45.     Thread thread = new Thread(mConnector, VOLD_TAG);  
  46.     thread.start();  
  47.   
  48.     // Add ourself to the Watchdog monitors if enabled.   
  49.     if (WATCHDOG_ENABLE) {  
  50.         Watchdog.getInstance().addMonitor(this);  
  51.     }  
  52. }  
public MountService(Context context) {
	mContext = context; 
	//从xml中读取存储设备列表
	readStorageList();

	if (mPrimaryVolume != null) {
		mExternalStoragePath = mPrimaryVolume.getPath();
		mEmulateExternalStorage = mPrimaryVolume.isEmulated();
		if (mEmulateExternalStorage) {
			Slog.d(TAG, "using emulated external storage");
			mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
		}
	}
	
	//add mount state for inernal storage in NAND
	if (Environment.getSecondStorageType() == Environment.SECOND_STORAGE_TYPE_NAND) {
		mVolumeStates.put(Environment.getSecondStorageDirectory().getPath(), Environment.MEDIA_MOUNTED);
	}
	// 查询PackageManagerService服务
	mPms = (PackageManagerService) ServiceManager.getService("package");
	IntentFilter filter = new IntentFilter();
	filter.addAction(Intent.ACTION_BOOT_COMPLETED);
	// don't bother monitoring USB if mass storage is not supported on our primary volume
	if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {
		filter.addAction(UsbManager.ACTION_USB_STATE);
	}
	//注册开机完成及USB状态变化广播接收器
	mContext.registerReceiver(mBroadcastReceiver, filter, null, null);
    //创建并启动一个带消息循环的MountService工作线程
	mHandlerThread = new HandlerThread("MountService");
	mHandlerThread.start();
	//为MountService工作线程创建一个Handler
	mHandler = new MountServiceHandler(mHandlerThread.getLooper());

	//为MountService工作线程创建一个ObbActionHandler
	mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());

	/*
	 * Create the connection to vold with a maximum queue of twice the
	 * amount of containers we'd ever expect to have. This keeps an
	 * "asec list" from blocking a thread repeatedly.
	 */
	mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
    //创建并启动一个socket连接监听线程
	Thread thread = new Thread(mConnector, VOLD_TAG);
	thread.start();

	// Add ourself to the Watchdog monitors if enabled.
	if (WATCHDOG_ENABLE) {
		Watchdog.getInstance().addMonitor(this);
	}
}

在开始构造MountService前,首先读取frameworks/base/core/res/res/xml/storage_list.xml文件,该文件以XML方式保存了所有存储设备的参数,文件内容如下所示:

  1. <StorageList xmlns:android="http://schemas.android.com/apk/res/android">  
  2.     <!-- removable is not set in nosdcard product -->  
  3.     <storage android:mountPoint="/mnt/sdcard"  
  4.                  android:storageDescription="@string/storage_usb"  
  5.                  android:primary="true" />  
  6. </StorageList>  
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- removable is not set in nosdcard product -->
    <storage android:mountPoint="/mnt/sdcard"
                 android:storageDescription="@string/storage_usb"
                 android:primary="true" />
</StorageList>

该文件的读取这里不在介绍,读者自行研究,使用XML解析器读取该XML的文件内容,根据读取到的存储设备参数来构造StorageVolume对象,并将构造的所有StorageVolume对象存放到列表mVolumes中。通过源码清晰地知道,在构造MountService时,注册了一个广播接收器,用于接收开机完成广播及USB状态广播,当开机完成时自动挂载存储设备,在大容量设备存储有效情况下,当USB状态变化也自动地挂载存储设备。创建了两个工作线程,MountService线程用于消息循环处理,为什么要开启一个异步消息处理线程呢?我们知道大量的Java Service驻留在SystemServer进程中,如果所有的服务消息都发送到SystemServer的主线程中处理的话,主线程的负荷很重,消息不能及时得到处理,因此需为每一个Service开启一个消息处理线程,专门处理本Service的消息。如下图所示:



MountService服务的线程模型


从上图可以清晰地看出SystemServer主线程启动MountService服务,该服务启动时会创建一个MountService带有消息循环的工作线程,用于处理MountServiceHandle和ObbActionHandler分发过来的消息;同时创建一个用于连接Vold服务端socket的VoldConnector线程,该线程在进入闭环运行前会创建一个带有消息循环的VoldConnector.CallbackHandler线程,用于处理native层的Vold进程发送过来的uevent事件消息;然后向服务端Vold发送连接请求,得到socket连接后,从该socket中循环读取数据以接收来之服务端Vold的uevent消息,当读取的数据长度为0时,向服务端重新发起连接,如此循环,保证客户端MountService与服务端Vold一直保持正常连接。当成功连接到服务端Vold时,VoldConnector线程会创建一个MountService#onDaemonConnected线程,用于处理本次连接请求响应。

1.MountService线程创建

  1. mHandlerThread = new HandlerThread("MountService");  
  2. mHandlerThread.start();  
  3. mHandler = new MountServiceHandler(mHandlerThread.getLooper());  
  4.   
  5. // Add OBB Action Handler to MountService thread.   
  6. mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());  
        mHandlerThread = new HandlerThread("MountService");
        mHandlerThread.start();
        mHandler = new MountServiceHandler(mHandlerThread.getLooper());

        // Add OBB Action Handler to MountService thread.
        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
MountServiceHandler消息处理:
  1. public void handleMessage(Message msg) {  
  2.     switch (msg.what) {  
  3.     case H_UNMOUNT_PM_UPDATE: {  
  4.         UnmountCallBack ucb = (UnmountCallBack) msg.obj;  
  5.         mForceUnmounts.add(ucb);  
  6.         // Register only if needed.   
  7.         if (!mUpdatingStatus) {  
  8.         if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");  
  9.         mUpdatingStatus = true;  
  10.         mPms.updateExternalMediaStatus(falsetrue);  
  11.         }  
  12.         break;  
  13.     }  
  14.     case H_UNMOUNT_PM_DONE: {  
  15.         mUpdatingStatus = false;  
  16.         int size = mForceUnmounts.size();  
  17.         int sizeArr[] = new int[size];  
  18.         int sizeArrN = 0;  
  19.         // Kill processes holding references first   
  20.         ActivityManagerService ams = (ActivityManagerService)  
  21.         ServiceManager.getService("activity");  
  22.         for (int i = 0; i < size; i++) {  
  23.         UnmountCallBack ucb = mForceUnmounts.get(i);  
  24.         String path = ucb.path;  
  25.         boolean done = false;  
  26.         if (!ucb.force) {  
  27.             done = true;  
  28.         } else {  
  29.             int pids[] = getStorageUsers(path);  
  30.             if (pids == null || pids.length == 0) {  
  31.             done = true;  
  32.             } else {  
  33.             // Eliminate system process here?   
  34.             ams.killPids(pids, "unmount media"true);  
  35.             // Confirm if file references have been freed.   
  36.             pids = getStorageUsers(path);  
  37.             if (pids == null || pids.length == 0) {  
  38.                 done = true;  
  39.             }  
  40.             }  
  41.         }  
  42.         if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {  
  43.             // Retry again   
  44.             Slog.i(TAG, "Retrying to kill storage users again");  
  45.             mHandler.sendMessageDelayed(mHandler.obtainMessage(H_UNMOUNT_PM_DONE,ucb.retries++),RETRY_UNMOUNT_DELAY);  
  46.         } else {  
  47.             if (ucb.retries >= MAX_UNMOUNT_RETRIES) {  
  48.             Slog.i(TAG, "Failed to unmount media inspite of " +  
  49.                 MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");  
  50.             }  
  51.             sizeArr[sizeArrN++] = i;  
  52.             mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,ucb));  
  53.         }  
  54.         }  
  55.         // Remove already processed elements from list.   
  56.         for (int i = (sizeArrN-1); i >= 0; i--) {  
  57.         mForceUnmounts.remove(sizeArr[i]);  
  58.         }  
  59.         break;  
  60.     }  
  61.     case H_UNMOUNT_MS: {  
  62.         UnmountCallBack ucb = (UnmountCallBack) msg.obj;  
  63.         ucb.handleFinished();  
  64.         break;  
  65.     }  
  66.     }  
  67. }  
public void handleMessage(Message msg) {
    switch (msg.what) {
	case H_UNMOUNT_PM_UPDATE: {
	    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
	    mForceUnmounts.add(ucb);
	    // Register only if needed.
	    if (!mUpdatingStatus) {
		if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
		mUpdatingStatus = true;
		mPms.updateExternalMediaStatus(false, true);
	    }
	    break;
	}
	case H_UNMOUNT_PM_DONE: {
	    mUpdatingStatus = false;
	    int size = mForceUnmounts.size();
	    int sizeArr[] = new int[size];
	    int sizeArrN = 0;
	    // Kill processes holding references first
	    ActivityManagerService ams = (ActivityManagerService)
	    ServiceManager.getService("activity");
	    for (int i = 0; i < size; i++) {
		UnmountCallBack ucb = mForceUnmounts.get(i);
		String path = ucb.path;
		boolean done = false;
		if (!ucb.force) {
		    done = true;
		} else {
		    int pids[] = getStorageUsers(path);
		    if (pids == null || pids.length == 0) {
			done = true;
		    } else {
			// Eliminate system process here?
			ams.killPids(pids, "unmount media", true);
			// Confirm if file references have been freed.
			pids = getStorageUsers(path);
			if (pids == null || pids.length == 0) {
			    done = true;
			}
		    }
		}
		if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
		    // Retry again
		    Slog.i(TAG, "Retrying to kill storage users again");
		    mHandler.sendMessageDelayed(mHandler.obtainMessage(H_UNMOUNT_PM_DONE,ucb.retries++),RETRY_UNMOUNT_DELAY);
		} else {
		    if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
			Slog.i(TAG, "Failed to unmount media inspite of " +
				MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
		    }
		    sizeArr[sizeArrN++] = i;
		    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,ucb));
		}
	    }
	    // Remove already processed elements from list.
	    for (int i = (sizeArrN-1); i >= 0; i--) {
		mForceUnmounts.remove(sizeArr[i]);
	    }
	    break;
	}
	case H_UNMOUNT_MS: {
	    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
	    ucb.handleFinished();
	    break;
	}
    }
}


MountServiceHandler分别对H_UNMOUNT_PM_UPDATE,H_UNMOUNT_PM_DONE,H_UNMOUNT_MS
  1. public void handleMessage(Message msg) {  
  2.     switch (msg.what) {  
  3.     case OBB_RUN_ACTION: {  
  4.         final ObbAction action = (ObbAction) msg.obj;  
  5.         // If a bind was already initiated we don't really   
  6.         // need to do anything. The pending install   
  7.         // will be processed later on.   
  8.         if (!mBound) {  
  9.         // If this is the only one pending we might   
  10.         // have to bind to the service again.   
  11.         if (!connectToService()) {  
  12.             Slog.e(TAG, "Failed to bind to media container service");  
  13.             action.handleError();  
  14.             return;  
  15.         }  
  16.         }  
  17.         mActions.add(action);  
  18.         break;  
  19.     }  
  20.     case OBB_MCS_BOUND: {  
  21.         if (msg.obj != null) {  
  22.         mContainerService = (IMediaContainerService) msg.obj;  
  23.         }  
  24.         if (mContainerService == null) {  
  25.         for (ObbAction action : mActions) {  
  26.             // Indicate service bind error   
  27.             action.handleError();  
  28.         }  
  29.         mActions.clear();  
  30.         } else if (mActions.size() > 0) {  
  31.         final ObbAction action = mActions.get(0);  
  32.         if (action != null) {  
  33.             action.execute(this);  
  34.         }  
  35.         } else {  
  36.         // Should never happen ideally.   
  37.         Slog.w(TAG, "Empty queue");  
  38.         }  
  39.         break;  
  40.     }  
  41.     case OBB_MCS_RECONNECT: {  
  42.         if (mActions.size() > 0) {  
  43.         if (mBound) {  
  44.             disconnectService();  
  45.         }  
  46.         if (!connectToService()) {  
  47.             Slog.e(TAG, "Failed to bind to media container service");  
  48.             for (ObbAction action : mActions) {  
  49.             // Indicate service bind error   
  50.             action.handleError();  
  51.             }  
  52.             mActions.clear();  
  53.         }  
  54.         }  
  55.         break;  
  56.     }  
  57.     case OBB_MCS_UNBIND: {  
  58.         // Delete pending install   
  59.         if (mActions.size() > 0) {  
  60.         mActions.remove(0);  
  61.         }  
  62.         if (mActions.size() == 0) {  
  63.         if (mBound) {  
  64.             disconnectService();  
  65.         }  
  66.         } else {  
  67.         // There are more pending requests in queue.   
  68.         // Just post MCS_BOUND message to trigger processing   
  69.         // of next pending install.   
  70.         mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);  
  71.         }  
  72.         break;  
  73.     }  
  74.     case OBB_FLUSH_MOUNT_STATE: {  
  75.         final String path = (String) msg.obj;  
  76.         synchronized (mObbMounts) {  
  77.         final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();  
  78.         final Iterator<Entry<String, ObbState>> i =mObbPathToStateMap.entrySet().iterator();  
  79.         while (i.hasNext()) {  
  80.             final Entry<String, ObbState> obbEntry = i.next();  
  81.             if (obbEntry.getKey().startsWith(path)) {  
  82.             obbStatesToRemove.add(obbEntry.getValue());  
  83.             }  
  84.         }  
  85.   
  86.         for (final ObbState obbState : obbStatesToRemove) {  
  87.             removeObbStateLocked(obbState);  
  88.             try {  
  89.             obbState.token.onObbResult(obbState.filename, obbState.nonce,  
  90.                 OnObbStateChangeListener.UNMOUNTED);  
  91.             } catch (RemoteException e) {  
  92.             Slog.i(TAG, "Couldn't send unmount notification for  OBB: "+ obbState.filename);  
  93.             }  
  94.         }  
  95.         }  
  96.         break;  
  97.     }  
  98.     }  
  99. }  
public void handleMessage(Message msg) {
    switch (msg.what) {
	case OBB_RUN_ACTION: {
	    final ObbAction action = (ObbAction) msg.obj;
	    // If a bind was already initiated we don't really
	    // need to do anything. The pending install
	    // will be processed later on.
	    if (!mBound) {
		// If this is the only one pending we might
		// have to bind to the service again.
		if (!connectToService()) {
		    Slog.e(TAG, "Failed to bind to media container service");
		    action.handleError();
		    return;
		}
	    }
	    mActions.add(action);
	    break;
	}
	case OBB_MCS_BOUND: {
	    if (msg.obj != null) {
		mContainerService = (IMediaContainerService) msg.obj;
	    }
	    if (mContainerService == null) {
		for (ObbAction action : mActions) {
		    // Indicate service bind error
		    action.handleError();
		}
		mActions.clear();
	    } else if (mActions.size() > 0) {
		final ObbAction action = mActions.get(0);
		if (action != null) {
		    action.execute(this);
		}
	    } else {
		// Should never happen ideally.
		Slog.w(TAG, "Empty queue");
	    }
	    break;
	}
	case OBB_MCS_RECONNECT: {
	    if (mActions.size() > 0) {
		if (mBound) {
		    disconnectService();
		}
		if (!connectToService()) {
		    Slog.e(TAG, "Failed to bind to media container service");
		    for (ObbAction action : mActions) {
			// Indicate service bind error
			action.handleError();
		    }
		    mActions.clear();
		}
	    }
	    break;
	}
	case OBB_MCS_UNBIND: {
	    // Delete pending install
	    if (mActions.size() > 0) {
		mActions.remove(0);
	    }
	    if (mActions.size() == 0) {
		if (mBound) {
		    disconnectService();
		}
	    } else {
		// There are more pending requests in queue.
		// Just post MCS_BOUND message to trigger processing
		// of next pending install.
		mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
	    }
	    break;
	}
	case OBB_FLUSH_MOUNT_STATE: {
	    final String path = (String) msg.obj;
	    synchronized (mObbMounts) {
		final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
		final Iterator<Entry<String, ObbState>> i =mObbPathToStateMap.entrySet().iterator();
		while (i.hasNext()) {
		    final Entry<String, ObbState> obbEntry = i.next();
		    if (obbEntry.getKey().startsWith(path)) {
			obbStatesToRemove.add(obbEntry.getValue());
		    }
		}

		for (final ObbState obbState : obbStatesToRemove) {
		    removeObbStateLocked(obbState);
		    try {
			obbState.token.onObbResult(obbState.filename, obbState.nonce,
				OnObbStateChangeListener.UNMOUNTED);
		    } catch (RemoteException e) {
			Slog.i(TAG, "Couldn't send unmount notification for  OBB: "+ obbState.filename);
		    }
		}
	    }
	    break;
	}
    }
}



MountService命令下发流程

Vold作为存储设备的管控中心,需要接收来自上层MountService的操作命令,MountService驻留在SystemServer进程中,和Vold作为两个不同的进程,它们之间的通信方式采用的是socket通信,在 android之VOLD进程启动源码分析一文中介绍了 CommandListener模块启动了一个socket监听线程,用于专门接收来之上层MountService的连接请求。而在MountService这端,同样启动了VoldConnector socket连接线程,用于循环连接服务端,保证连接不被中断,当成功连接Vold时,循环从服务端读取数据。MountService按照指定格式向Vold发送命令,由于发送的命令比较多,这里不做一一接收,只对其中的mount命令的发送流程进行介绍:

从以上的时序图可以看出,MountService对命令的发送首先是调用makeCommand来组合成指定格式的命令,然后直接写入到Vold socket即可,整个命令发送流程比较简单。
  1. public int mountVolume(String path) {  
  2.         //权限检验   
  3.     validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);  
  4.     waitForReady();  
  5.   
  6.     return doMountVolume(path);  
  7. }  
public int mountVolume(String path) {
        //权限检验
	validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
	waitForReady();

	return doMountVolume(path);
}
调用doMountVolume函数来挂载存储设备:
  1. private int doMountVolume(String path) {  
  2.     int rc = StorageResultCode.OperationSucceeded;  
  3.     try {  
  4.         //命令交给NativeDaemonConnector去发送   
  5.         mConnector.execute("volume""mount", path);  
  6.     } catch (NativeDaemonConnectorException e) {  
  7.         //捕获命令发送的异常,根据异常码来决定发送失败的原因   
  8.         String action = null;  
  9.         int code = e.getCode();  
  10.         if (code == VoldResponseCode.OpFailedNoMedia) {  
  11.         /* 
  12.          * Attempt to mount but no media inserted 
  13.          */  
  14.         rc = StorageResultCode.OperationFailedNoMedia;  
  15.         } else if (code == VoldResponseCode.OpFailedMediaBlank) {  
  16.         if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");  
  17.         /* 
  18.          * Media is blank or does not contain a supported filesystem 
  19.          */  
  20.         updatePublicVolumeState(path, Environment.MEDIA_NOFS);  
  21.         action = Intent.ACTION_MEDIA_NOFS;  
  22.         rc = StorageResultCode.OperationFailedMediaBlank;  
  23.         } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {  
  24.         if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");  
  25.         /* 
  26.          * Volume consistency check failed 
  27.          */  
  28.         updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);  
  29.         action = Intent.ACTION_MEDIA_UNMOUNTABLE;  
  30.         rc = StorageResultCode.OperationFailedMediaCorrupt;  
  31.         } else {  
  32.         rc = StorageResultCode.OperationFailedInternalError;  
  33.         }  
  34.         /* 
  35.          * Send broadcast intent (if required for the failure) 
  36.          */  
  37.         if (action != null) {  
  38.         sendStorageIntent(action, path);  
  39.         }  
  40.     }  
  41.     return rc;  
  42. }  
private int doMountVolume(String path) {
	int rc = StorageResultCode.OperationSucceeded;
	try {
	    //命令交给NativeDaemonConnector去发送
	    mConnector.execute("volume", "mount", path);
	} catch (NativeDaemonConnectorException e) {
	    //捕获命令发送的异常,根据异常码来决定发送失败的原因
	    String action = null;
	    int code = e.getCode();
	    if (code == VoldResponseCode.OpFailedNoMedia) {
		/*
		 * Attempt to mount but no media inserted
		 */
		rc = StorageResultCode.OperationFailedNoMedia;
	    } else if (code == VoldResponseCode.OpFailedMediaBlank) {
		if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
		/*
		 * Media is blank or does not contain a supported filesystem
		 */
		updatePublicVolumeState(path, Environment.MEDIA_NOFS);
		action = Intent.ACTION_MEDIA_NOFS;
		rc = StorageResultCode.OperationFailedMediaBlank;
	    } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
		if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
		/*
		 * Volume consistency check failed
		 */
		updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
		action = Intent.ACTION_MEDIA_UNMOUNTABLE;
		rc = StorageResultCode.OperationFailedMediaCorrupt;
	    } else {
		rc = StorageResultCode.OperationFailedInternalError;
	    }
	    /*
	     * Send broadcast intent (if required for the failure)
	     */
	    if (action != null) {
		sendStorageIntent(action, path);
	    }
	}
	return rc;
}
NativeDaemonConnector命令发送:
  1. public NativeDaemonEvent execute(String cmd, Object... args)  
  2.     throws NativeDaemonConnectorException {  
  3.         //使用executeForList函数来发送命令和命令参数,并返回一组NativeDaemonEvent事件   
  4.     final NativeDaemonEvent[] events = executeForList(cmd, args);  
  5.     if (events.length != 1) {  
  6.         throw new NativeDaemonConnectorException("Expected exactly one response, but received " + events.length);  
  7.     }  
  8.     return events[0];  
  9. }  
public NativeDaemonEvent execute(String cmd, Object... args)
    throws NativeDaemonConnectorException {
        //使用executeForList函数来发送命令和命令参数,并返回一组NativeDaemonEvent事件
	final NativeDaemonEvent[] events = executeForList(cmd, args);
	if (events.length != 1) {
	    throw new NativeDaemonConnectorException("Expected exactly one response, but received " + events.length);
	}
	return events[0];
}
调用executeForList来发送命令和命令参数,并在这里设置超时时间:
  1. public NativeDaemonEvent[] executeForList(String cmd, Object... args)  
  2.     throws NativeDaemonConnectorException {  
  3.     //设置超时时间:DEFAULT_TIMEOUT = 1 * 60 * 1000   
  4.     return execute(DEFAULT_TIMEOUT, cmd, args);  
  5. }  
public NativeDaemonEvent[] executeForList(String cmd, Object... args)
    throws NativeDaemonConnectorException {
    //设置超时时间:DEFAULT_TIMEOUT = 1 * 60 * 1000
    return execute(DEFAULT_TIMEOUT, cmd, args);
}
真正命令发送:
  1. public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)  
  2.     throws NativeDaemonConnectorException {  
  3.     final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();  
  4.     final int sequenceNumber = mSequenceNumber.incrementAndGet();  
  5.     final StringBuilder cmdBuilder = new StringBuilder(Integer.toString(sequenceNumber)).append(' ');  
  6.     //发送起始时间   
  7.     final long startTime = SystemClock.elapsedRealtime();  
  8.     //命令组合   
  9.     makeCommand(cmdBuilder, cmd, args);  
  10.     final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */  
  11.     log("SND -> {" + logCmd + "}"); //SND -> {8 volume mount /storage/sdcard1}   
  12.     cmdBuilder.append('\0');  
  13.     final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */  
  14.     synchronized (mDaemonLock) {  
  15.         if (mOutputStream == null) {  
  16.         throw new NativeDaemonConnectorException("missing output stream");  
  17.         } else {  
  18.         try {  
  19.             //向socket中写入命令   
  20.             mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8));  
  21.         } catch (IOException e) {  
  22.             throw new NativeDaemonConnectorException("problem sending command", e);  
  23.         }  
  24.         }  
  25.     }  
  26.     NativeDaemonEvent event = null;  
  27.     do {  
  28.         event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd);  
  29.         if (event == null) {  
  30.         loge("timed-out waiting for response to " + logCmd);  
  31.         throw new NativeDaemonFailureException(logCmd, event);  
  32.         }  
  33.         log("RMV <- {" + event + "}");  
  34.         events.add(event);  
  35.     } while (event.isClassContinue());  
  36.         //发送结束时间   
  37.     final long endTime = SystemClock.elapsedRealtime();  
  38.     if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {  
  39.         loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");  
  40.     }  
  41.     if (event.isClassClientError()) {  
  42.         throw new NativeDaemonArgumentException(logCmd, event);  
  43.     }  
  44.     if (event.isClassServerError()) {  
  45.         throw new NativeDaemonFailureException(logCmd, event);  
  46.     }  
  47.     return events.toArray(new NativeDaemonEvent[events.size()]);  
  48. }  
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
    throws NativeDaemonConnectorException {
	final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
	final int sequenceNumber = mSequenceNumber.incrementAndGet();
	final StringBuilder cmdBuilder = new StringBuilder(Integer.toString(sequenceNumber)).append(' ');
	//发送起始时间
	final long startTime = SystemClock.elapsedRealtime();
	//命令组合
	makeCommand(cmdBuilder, cmd, args);
	final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */
	log("SND -> {" + logCmd + "}"); //SND -> {8 volume mount /storage/sdcard1}
	cmdBuilder.append('\0');
	final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */
	synchronized (mDaemonLock) {
	    if (mOutputStream == null) {
		throw new NativeDaemonConnectorException("missing output stream");
	    } else {
		try {
		    //向socket中写入命令
		    mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8));
		} catch (IOException e) {
		    throw new NativeDaemonConnectorException("problem sending command", e);
		}
	    }
	}
	NativeDaemonEvent event = null;
	do {
	    event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd);
	    if (event == null) {
		loge("timed-out waiting for response to " + logCmd);
		throw new NativeDaemonFailureException(logCmd, event);
	    }
	    log("RMV <- {" + event + "}");
	    events.add(event);
	} while (event.isClassContinue());
        //发送结束时间
	final long endTime = SystemClock.elapsedRealtime();
	if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
	    loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
	}
	if (event.isClassClientError()) {
	    throw new NativeDaemonArgumentException(logCmd, event);
	}
	if (event.isClassServerError()) {
	    throw new NativeDaemonFailureException(logCmd, event);
	}
	return events.toArray(new NativeDaemonEvent[events.size()]);
}


MountService消息接收流程

MountService需要接收两种类型的消息:
1)当外部存储设备发生热插拔时,kernel将通过netlink方式通知Vold,Vold进程经过一系列处理后最终还是要叫uevent事件消息发送给MountService,Vold发送uevent的过程已经在 android之VOLD进程启动源码分析一文中详细介绍了;
2)当MountService向Vold发送命令后,将接收到Vold的响应消息;
无论是何种类型的消息,MountService都是通过VoldConnector线程来循环接收Vold的请求,整个消息接收流程如下:

1)socket连接
  1. public void run() {  
  2.     //创建并启动VoldConnector.CallbackHandler线程,用于处理native层的Vold进程发送过来的uevent事件消息   
  3.     HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");  
  4.     thread.start();  
  5.     //为VoldConnector.CallbackHandler线程创建一个Handler,用于向该线程分发消息   
  6.     mCallbackHandler = new Handler(thread.getLooper(), this);  
  7.         //进入闭环socket连接模式   
  8.     while (true) {  
  9.         try {  
  10.             listenToSocket();  
  11.         } catch (Exception e) {  
  12.             loge("Error in NativeDaemonConnector: " + e);  
  13.             SystemClock.sleep(5000);  
  14.         }  
  15.     }  
  16. }  
public void run() {
	//创建并启动VoldConnector.CallbackHandler线程,用于处理native层的Vold进程发送过来的uevent事件消息
	HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
	thread.start();
	//为VoldConnector.CallbackHandler线程创建一个Handler,用于向该线程分发消息
	mCallbackHandler = new Handler(thread.getLooper(), this);
        //进入闭环socket连接模式
	while (true) {
		try {
			listenToSocket();
		} catch (Exception e) {
			loge("Error in NativeDaemonConnector: " + e);
			SystemClock.sleep(5000);
		}
	}
}
连接服务端Socket,并读取数据:
  1. private void listenToSocket() throws IOException {  
  2.     LocalSocket socket = null;  
  3.     try {  
  4.         //创建Vold socket   
  5.         socket = new LocalSocket();  
  6.         LocalSocketAddress address = new LocalSocketAddress(mSocket,LocalSocketAddress.Namespace.RESERVED);  
  7.                 //向服务端发起连接请求   
  8.         socket.connect(address);  
  9.                 //从连接的socket中得到输入输出流   
  10.         InputStream inputStream = socket.getInputStream();  
  11.         synchronized (mDaemonLock) {  
  12.             mOutputStream = socket.getOutputStream();  
  13.         }  
  14.                 //对本次连接请求做一些回调处理   
  15.         mCallbacks.onDaemonConnected();  
  16.                 //定义buffer   
  17.         byte[] buffer = new byte[BUFFER_SIZE];  
  18.         int start = 0;  
  19.                 //进入闭环数据读取模式   
  20.         while (true) {  
  21.             int count = inputStream.read(buffer, start, BUFFER_SIZE - start);  
  22.             //当读取的数据长度小于0时,表示连接已断开,跳出循环,重新向服务端发起新的连接请求   
  23.             if (count < 0) {  
  24.                 loge("got " + count + " reading with start = " + start);  
  25.                 break;  
  26.             }  
  27.             // Add our starting point to the count and reset the start.   
  28.             count += start;  
  29.             start = 0;  
  30.                         //解析读取到的数据,得到NativeDaemonEvent   
  31.             for (int i = 0; i < count; i++) {  
  32.                 if (buffer[i] == 0) {  
  33.                     final String rawEvent = new String(buffer, start, i - start, Charsets.UTF_8);  
  34.                     //RCV <- {632 Volume sdcard /storage/sdcard1 bad removal (179:1)}   
  35.                     log("RCV <- {" + rawEvent + "}");  
  36.   
  37.                     try {  
  38.                         final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);  
  39.                         //如果命令码code >= 600 && code < 700   
  40.                         if (event.isClassUnsolicited()) {  
  41.                             //将读取到的事件发送到VoldConnector.CallbackHandler线程中处理   
  42.                             mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(  
  43.                                     event.getCode(), event.getRawEvent()));  
  44.                         //否则将改事件添加到响应队列中   
  45.                         } else {  
  46.                             mResponseQueue.add(event.getCmdNumber(), event);  
  47.                         }  
  48.                     } catch (IllegalArgumentException e) {  
  49.                         log("Problem parsing message: " + rawEvent + " - " + e);  
  50.                     }  
  51.                     start = i + 1;  
  52.                 }  
  53.             }  
  54.             if (start == 0) {  
  55.                 final String rawEvent = new String(buffer, start, count, Charsets.UTF_8);  
  56.                 log("RCV incomplete <- {" + rawEvent + "}");  
  57.             }  
  58.             // We should end at the amount we read. If not, compact then   
  59.             // buffer and read again.   
  60.             if (start != count) {  
  61.                 final int remaining = BUFFER_SIZE - start;  
  62.                 System.arraycopy(buffer, start, buffer, 0, remaining);  
  63.                 start = remaining;  
  64.             } else {  
  65.                 start = 0;  
  66.             }  
  67.         }  
  68.     } catch (IOException ex) {  
  69.         loge("Communications error: " + ex);  
  70.         throw ex;  
  71.     } finally {  
  72.         synchronized (mDaemonLock) {  
  73.             if (mOutputStream != null) {  
  74.                 try {  
  75.                     loge("closing stream for " + mSocket);  
  76.                     mOutputStream.close();  
  77.                 } catch (IOException e) {  
  78.                     loge("Failed closing output stream: " + e);  
  79.                 }  
  80.                 mOutputStream = null;  
  81.             }  
  82.         }  
  83.         try {  
  84.             if (socket != null) {  
  85.                 socket.close();  
  86.             }  
  87.         } catch (IOException ex) {  
  88.             loge("Failed closing socket: " + ex);  
  89.         }  
  90.     }  
  91. }  
private void listenToSocket() throws IOException {
	LocalSocket socket = null;
	try {
		//创建Vold socket
		socket = new LocalSocket();
		LocalSocketAddress address = new LocalSocketAddress(mSocket,LocalSocketAddress.Namespace.RESERVED);
                //向服务端发起连接请求
		socket.connect(address);
                //从连接的socket中得到输入输出流
		InputStream inputStream = socket.getInputStream();
		synchronized (mDaemonLock) {
			mOutputStream = socket.getOutputStream();
		}
                //对本次连接请求做一些回调处理
		mCallbacks.onDaemonConnected();
                //定义buffer
		byte[] buffer = new byte[BUFFER_SIZE];
		int start = 0;
                //进入闭环数据读取模式
		while (true) {
			int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
			//当读取的数据长度小于0时,表示连接已断开,跳出循环,重新向服务端发起新的连接请求
			if (count < 0) {
				loge("got " + count + " reading with start = " + start);
				break;
			}
			// Add our starting point to the count and reset the start.
			count += start;
			start = 0;
                        //解析读取到的数据,得到NativeDaemonEvent
			for (int i = 0; i < count; i++) {
				if (buffer[i] == 0) {
					final String rawEvent = new String(buffer, start, i - start, Charsets.UTF_8);
					//RCV <- {632 Volume sdcard /storage/sdcard1 bad removal (179:1)}
					log("RCV <- {" + rawEvent + "}");

					try {
						final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);
						//如果命令码code >= 600 && code < 700
						if (event.isClassUnsolicited()) {
							//将读取到的事件发送到VoldConnector.CallbackHandler线程中处理
							mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
									event.getCode(), event.getRawEvent()));
						//否则将改事件添加到响应队列中
						} else {
							mResponseQueue.add(event.getCmdNumber(), event);
						}
					} catch (IllegalArgumentException e) {
						log("Problem parsing message: " + rawEvent + " - " + e);
					}
					start = i + 1;
				}
			}
			if (start == 0) {
				final String rawEvent = new String(buffer, start, count, Charsets.UTF_8);
				log("RCV incomplete <- {" + rawEvent + "}");
			}
			// We should end at the amount we read. If not, compact then
			// buffer and read again.
			if (start != count) {
				final int remaining = BUFFER_SIZE - start;
				System.arraycopy(buffer, start, buffer, 0, remaining);
				start = remaining;
			} else {
				start = 0;
			}
		}
	} catch (IOException ex) {
		loge("Communications error: " + ex);
		throw ex;
	} finally {
		synchronized (mDaemonLock) {
			if (mOutputStream != null) {
				try {
					loge("closing stream for " + mSocket);
					mOutputStream.close();
				} catch (IOException e) {
					loge("Failed closing output stream: " + e);
				}
				mOutputStream = null;
			}
		}
		try {
			if (socket != null) {
				socket.close();
			}
		} catch (IOException ex) {
			loge("Failed closing socket: " + ex);
		}
	}
}
2)连接成功回调处理
  1. public void onDaemonConnected() {  
  2.     //创建一个工作线程   
  3.     new Thread("MountService#onDaemonConnected") {  
  4.         @Override  
  5.         public void run() {  
  6.             /** 
  7.              * Determine media state and UMS detection status 
  8.              */  
  9.             try {  
  10.                 //向vold查询所有的存储设备   
  11.                 final String[] vols = NativeDaemonEvent.filterMessageList(  
  12.                         mConnector.executeForList("volume""list"),  
  13.                         VoldResponseCode.VolumeListResult);  
  14.                     //判断存储设备状态   
  15.                 for (String volstr : vols) {  
  16.                     String[] tok = volstr.split(" ");  
  17.                     // FMT: <label> <mountpoint> <state>   
  18.                     String path = tok[1];  
  19.                     String state = Environment.MEDIA_REMOVED;  
  20.   
  21.                     int st = Integer.parseInt(tok[2]);  
  22.                     if (st == VolumeState.NoMedia) {  
  23.                         state = Environment.MEDIA_REMOVED;  
  24.                     } else if (st == VolumeState.Idle) {  
  25.                         state = Environment.MEDIA_UNMOUNTED;  
  26.                     } else if (st == VolumeState.Mounted) {  
  27.                         state = Environment.MEDIA_MOUNTED;  
  28.                         Slog.i(TAG, "Media already mounted on daemon connection");  
  29.                     } else if (st == VolumeState.Shared) {  
  30.                         state = Environment.MEDIA_SHARED;  
  31.                         Slog.i(TAG, "Media shared on daemon connection");  
  32.                     } else {  
  33.                         throw new Exception(String.format("Unexpected state %d", st));  
  34.                     }  
  35.   
  36.                     if (state != null) {  
  37.                         if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);  
  38.                         //更新Volume状态   
  39.                         updatePublicVolumeState(path, state);  
  40.                     }  
  41.                 }  
  42.             } catch (Exception e) {  
  43.                 Slog.e(TAG, "Error processing initial volume state", e);  
  44.                 updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);  
  45.             }  
  46.   
  47.             /* 
  48.              * Now that we've done our initialization, release 
  49.              * the hounds! 
  50.              */  
  51.             mConnectedSignal.countDown();  
  52.             mConnectedSignal = null;  
  53.   
  54.             // 使用PackageManagerService扫描外边存储设备上的APK信息   
  55.             mPms.scanAvailableAsecs();  
  56.   
  57.             // Notify people waiting for ASECs to be scanned that it's done.   
  58.             mAsecsScanned.countDown();  
  59.             mAsecsScanned = null;  
  60.         }  
  61.     }.start();  
  62. }  
public void onDaemonConnected() {
    //创建一个工作线程
	new Thread("MountService#onDaemonConnected") {
		@Override
		public void run() {
			/**
			 * Determine media state and UMS detection status
			 */
			try {
				//向vold查询所有的存储设备
				final String[] vols = NativeDaemonEvent.filterMessageList(
						mConnector.executeForList("volume", "list"),
						VoldResponseCode.VolumeListResult);
			        //判断存储设备状态
				for (String volstr : vols) {
					String[] tok = volstr.split(" ");
					// FMT: <label> <mountpoint> <state>
					String path = tok[1];
					String state = Environment.MEDIA_REMOVED;

					int st = Integer.parseInt(tok[2]);
					if (st == VolumeState.NoMedia) {
						state = Environment.MEDIA_REMOVED;
					} else if (st == VolumeState.Idle) {
						state = Environment.MEDIA_UNMOUNTED;
					} else if (st == VolumeState.Mounted) {
						state = Environment.MEDIA_MOUNTED;
						Slog.i(TAG, "Media already mounted on daemon connection");
					} else if (st == VolumeState.Shared) {
						state = Environment.MEDIA_SHARED;
						Slog.i(TAG, "Media shared on daemon connection");
					} else {
						throw new Exception(String.format("Unexpected state %d", st));
					}

					if (state != null) {
						if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
						//更新Volume状态
						updatePublicVolumeState(path, state);
					}
				}
			} catch (Exception e) {
				Slog.e(TAG, "Error processing initial volume state", e);
				updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
			}

			/*
			 * Now that we've done our initialization, release
			 * the hounds!
			 */
			mConnectedSignal.countDown();
			mConnectedSignal = null;

			// 使用PackageManagerService扫描外边存储设备上的APK信息
			mPms.scanAvailableAsecs();

			// Notify people waiting for ASECs to be scanned that it's done.
			mAsecsScanned.countDown();
			mAsecsScanned = null;
		}
	}.start();
}
存储设备状态更新:
  1. private boolean updatePublicVolumeState(String path, String state) {  
  2.     String oldState;  
  3.     synchronized(mVolumeStates) {  
  4.         oldState = mVolumeStates.put(path, state);  
  5.     }  
  6.     if (state.equals(oldState)) {  
  7.         Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",state, state, path));  
  8.         return false;  
  9.     }  
  10.     Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");  
  11.     if (path.equals(mExternalStoragePath)) {  
  12.         // Update state on PackageManager, but only of real events   
  13.         if (!mEmulateExternalStorage) {  
  14.             if (Environment.MEDIA_UNMOUNTED.equals(state)) {  
  15.                 mPms.updateExternalMediaStatus(falsefalse);  
  16.   
  17.                 /* 
  18.                  * Some OBBs might have been unmounted when this volume was 
  19.                  * unmounted, so send a message to the handler to let it know to 
  20.                  * remove those from the list of mounted OBBS. 
  21.                  */  
  22.                 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE, path));  
  23.             } else if (Environment.MEDIA_MOUNTED.equals(state)) {  
  24.                 mPms.updateExternalMediaStatus(truefalse);  
  25.             }  
  26.         }  
  27.     }  
  28.     synchronized (mListeners) {  
  29.         for (int i = mListeners.size() -1; i >= 0; i--) {  
  30.             MountServiceBinderListener bl = mListeners.get(i);  
  31.             try {  
  32.                 //调用已注册的MountServiceBinderListener来通知存储设备状态改变   
  33.                 bl.mListener.onStorageStateChanged(path, oldState, state);  
  34.             } catch (RemoteException rex) {  
  35.                 Slog.e(TAG, "Listener dead");  
  36.                 mListeners.remove(i);  
  37.             } catch (Exception ex) {  
  38.                 Slog.e(TAG, "Listener failed", ex);  
  39.             }  
  40.         }  
  41.     }  
  42.     return true;  
  43. }  
private boolean updatePublicVolumeState(String path, String state) {
	String oldState;
	synchronized(mVolumeStates) {
		oldState = mVolumeStates.put(path, state);
	}
	if (state.equals(oldState)) {
		Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",state, state, path));
		return false;
	}
	Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
	if (path.equals(mExternalStoragePath)) {
		// Update state on PackageManager, but only of real events
		if (!mEmulateExternalStorage) {
			if (Environment.MEDIA_UNMOUNTED.equals(state)) {
				mPms.updateExternalMediaStatus(false, false);

				/*
				 * Some OBBs might have been unmounted when this volume was
				 * unmounted, so send a message to the handler to let it know to
				 * remove those from the list of mounted OBBS.
				 */
				mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE, path));
			} else if (Environment.MEDIA_MOUNTED.equals(state)) {
				mPms.updateExternalMediaStatus(true, false);
			}
		}
	}
	synchronized (mListeners) {
		for (int i = mListeners.size() -1; i >= 0; i--) {
			MountServiceBinderListener bl = mListeners.get(i);
			try {
				//调用已注册的MountServiceBinderListener来通知存储设备状态改变
				bl.mListener.onStorageStateChanged(path, oldState, state);
			} catch (RemoteException rex) {
				Slog.e(TAG, "Listener dead");
				mListeners.remove(i);
			} catch (Exception ex) {
				Slog.e(TAG, "Listener failed", ex);
			}
		}
	}
	return true;
}


MountServiceBinderListener的注册过程:
  1. public void registerListener(IMountServiceListener listener) {  
  2.     synchronized (mListeners) {  
  3.         MountServiceBinderListener bl = new MountServiceBinderListener(listener);  
  4.         try {  
  5.             listener.asBinder().linkToDeath(bl, 0);  
  6.             mListeners.add(bl);  
  7.         } catch (RemoteException rex) {  
  8.             Slog.e(TAG, "Failed to link to listener death");  
  9.         }  
  10.     }  
  11. }  
public void registerListener(IMountServiceListener listener) {
	synchronized (mListeners) {
		MountServiceBinderListener bl = new MountServiceBinderListener(listener);
		try {
			listener.asBinder().linkToDeath(bl, 0);
			mListeners.add(bl);
		} catch (RemoteException rex) {
			Slog.e(TAG, "Failed to link to listener death");
		}
	}
}
使用StorageManager的内部类MountServiceBinderListener对象来构造MountService的内部类MountServiceBinderListener对象,并添加到MountService的成员变量mListeners列表中。StorageManager的内部类MountServiceBinderListener定义如下:
  1. private class MountServiceBinderListener extends IMountServiceListener.Stub {  
  2.     public void onUsbMassStorageConnectionChanged(boolean available) {  
  3.         final int size = mListeners.size();  
  4.         for (int i = 0; i < size; i++) {  
  5.             mListeners.get(i).sendShareAvailabilityChanged(available);  
  6.         }  
  7.     }  
  8.   
  9.     public void onStorageStateChanged(String path, String oldState, String newState) {  
  10.         final int size = mListeners.size();  
  11.         for (int i = 0; i < size; i++) {  
  12.             mListeners.get(i).sendStorageStateChanged(path, oldState, newState);  
  13.         }  
  14.     }  
  15. }  
private class MountServiceBinderListener extends IMountServiceListener.Stub {
	public void onUsbMassStorageConnectionChanged(boolean available) {
		final int size = mListeners.size();
		for (int i = 0; i < size; i++) {
			mListeners.get(i).sendShareAvailabilityChanged(available);
		}
	}

	public void onStorageStateChanged(String path, String oldState, String newState) {
		final int size = mListeners.size();
		for (int i = 0; i < size; i++) {
			mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
		}
	}
}
最后调用ListenerDelegate的sendStorageStateChanged来实现
3)事件处理
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(event.getCode(), event.getRawEvent())); 将事件已消息的方式发送到VoldConnector.CallbackHandler线程中处理:
  1. public boolean handleMessage(Message msg) {  
  2.     String event = (String) msg.obj;  
  3.     try {  
  4.         //回调MountService的onEvent函数进行处理   
  5.         if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {  
  6.             log(String.format("Unhandled event '%s'", event));  
  7.         }  
  8.     } catch (Exception e) {  
  9.         loge("Error handling '" + event + "': " + e);  
  10.     }  
  11.     return true;  
  12. }  
public boolean handleMessage(Message msg) {
	String event = (String) msg.obj;
	try {
		//回调MountService的onEvent函数进行处理
		if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {
			log(String.format("Unhandled event '%s'", event));
		}
	} catch (Exception e) {
		loge("Error handling '" + event + "': " + e);
	}
	return true;
}

  1. public boolean onEvent(int code, String raw, String[] cooked) {  
  2.     if (DEBUG_EVENTS) {  
  3.         StringBuilder builder = new StringBuilder();  
  4.         builder.append("onEvent::");  
  5.         builder.append(" raw= " + raw);  
  6.         if (cooked != null) {  
  7.             builder.append(" cooked = " );  
  8.             for (String str : cooked) {  
  9.                 builder.append(" " + str);  
  10.             }  
  11.         }  
  12.         Slog.i(TAG, builder.toString());  
  13.     }  
  14.     if (code == VoldResponseCode.VolumeStateChange) {  
  15.         /* 
  16.          * One of the volumes we're managing has changed state. 
  17.          * Format: "NNN Volume <label> <path> state changed 
  18.          * from <old_#> (<old_str>) to <new_#> (<new_str>)" 
  19.          */  
  20.         notifyVolumeStateChange(cooked[2], cooked[3], Integer.parseInt(cooked[7]),Integer.parseInt(cooked[10]));  
  21.     } else if ((code == VoldResponseCode.VolumeDiskInserted) ||  
  22.                (code == VoldResponseCode.VolumeDiskRemoved) ||  
  23.                (code == VoldResponseCode.VolumeBadRemoval)) {  
  24.         // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)   
  25.         // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)   
  26.         // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)   
  27.         String action = null;  
  28.         final String label = cooked[2];  
  29.         final String path = cooked[3];  
  30.         int major = -1;  
  31.         int minor = -1;  
  32.   
  33.         try {  
  34.             String devComp = cooked[6].substring(1, cooked[6].length() -1);  
  35.             String[] devTok = devComp.split(":");  
  36.             major = Integer.parseInt(devTok[0]);  
  37.             minor = Integer.parseInt(devTok[1]);  
  38.         } catch (Exception ex) {  
  39.             Slog.e(TAG, "Failed to parse major/minor", ex);  
  40.         }  
  41.   
  42.         if (code == VoldResponseCode.VolumeDiskInserted) {  
  43.             new Thread() {  
  44.                 @Override  
  45.                 public void run() {  
  46.                     try {  
  47.                         int rc;  
  48.                         if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {  
  49.                             Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));  
  50.                         }  
  51.                     } catch (Exception ex) {  
  52.                         Slog.w(TAG, "Failed to mount media on insertion", ex);  
  53.                     }  
  54.                 }  
  55.             }.start();  
  56.         } else if (code == VoldResponseCode.VolumeDiskRemoved) {  
  57.             /* 
  58.              * This event gets trumped if we're already in BAD_REMOVAL state 
  59.              */  
  60.             if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {  
  61.                 return true;  
  62.             }  
  63.             /* Send the media unmounted event first */  
  64.             if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");  
  65.             updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);  
  66.             sendStorageIntent(Environment.MEDIA_UNMOUNTED, path);  
  67.   
  68.             if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");  
  69.             updatePublicVolumeState(path, Environment.MEDIA_REMOVED);  
  70.             action = Intent.ACTION_MEDIA_REMOVED;  
  71.         } else if (code == VoldResponseCode.VolumeBadRemoval) {  
  72.             if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");  
  73.             /* Send the media unmounted event first */  
  74.             updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);  
  75.             action = Intent.ACTION_MEDIA_UNMOUNTED;  
  76.   
  77.             if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");  
  78.             updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);  
  79.             action = Intent.ACTION_MEDIA_BAD_REMOVAL;  
  80.         } else {  
  81.             Slog.e(TAG, String.format("Unknown code {%d}", code));  
  82.         }  
  83.   
  84.         if (action != null) {  
  85.             sendStorageIntent(action, path);  
  86.         }  
  87.     } else {  
  88.         return false;  
  89.     }  
  90.     return true;  
  91. }  
public boolean onEvent(int code, String raw, String[] cooked) {
	if (DEBUG_EVENTS) {
		StringBuilder builder = new StringBuilder();
		builder.append("onEvent::");
		builder.append(" raw= " + raw);
		if (cooked != null) {
			builder.append(" cooked = " );
			for (String str : cooked) {
				builder.append(" " + str);
			}
		}
		Slog.i(TAG, builder.toString());
	}
	if (code == VoldResponseCode.VolumeStateChange) {
		/*
		 * One of the volumes we're managing has changed state.
		 * Format: "NNN Volume <label> <path> state changed
		 * from <old_#> (<old_str>) to <new_#> (<new_str>)"
		 */
		notifyVolumeStateChange(cooked[2], cooked[3], Integer.parseInt(cooked[7]),Integer.parseInt(cooked[10]));
	} else if ((code == VoldResponseCode.VolumeDiskInserted) ||
			   (code == VoldResponseCode.VolumeDiskRemoved) ||
			   (code == VoldResponseCode.VolumeBadRemoval)) {
		// FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
		// FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
		// FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
		String action = null;
		final String label = cooked[2];
		final String path = cooked[3];
		int major = -1;
		int minor = -1;

		try {
			String devComp = cooked[6].substring(1, cooked[6].length() -1);
			String[] devTok = devComp.split(":");
			major = Integer.parseInt(devTok[0]);
			minor = Integer.parseInt(devTok[1]);
		} catch (Exception ex) {
			Slog.e(TAG, "Failed to parse major/minor", ex);
		}

		if (code == VoldResponseCode.VolumeDiskInserted) {
			new Thread() {
				@Override
				public void run() {
					try {
						int rc;
						if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
							Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
						}
					} catch (Exception ex) {
						Slog.w(TAG, "Failed to mount media on insertion", ex);
					}
				}
			}.start();
		} else if (code == VoldResponseCode.VolumeDiskRemoved) {
			/*
			 * This event gets trumped if we're already in BAD_REMOVAL state
			 */
			if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
				return true;
			}
			/* Send the media unmounted event first */
			if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
			updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
			sendStorageIntent(Environment.MEDIA_UNMOUNTED, path);

			if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
			updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
			action = Intent.ACTION_MEDIA_REMOVED;
		} else if (code == VoldResponseCode.VolumeBadRemoval) {
			if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
			/* Send the media unmounted event first */
			updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
			action = Intent.ACTION_MEDIA_UNMOUNTED;

			if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
			updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
			action = Intent.ACTION_MEDIA_BAD_REMOVAL;
		} else {
			Slog.e(TAG, String.format("Unknown code {%d}", code));
		}

		if (action != null) {
			sendStorageIntent(action, path);
		}
	} else {
		return false;
	}
	return true;
}
整个MountService与Vold的通信到此就介绍完了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值