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创建及注册过程如下:
-
MountService mountService = null;
-
if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
-
try {
-
-
-
-
-
Slog.i(TAG, "Mount Service");
-
mountService = new MountService(context);
-
-
ServiceManager.addService("mount", mountService);
-
} catch (Throwable e) {
-
reportWtf("starting Mount Service", e);
-
}
-
}
MountService各个类关系图:

构造MountService对象实例:
-
public MountService(Context context) {
-
mContext = context;
-
-
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);
-
}
-
}
-
-
-
if (Environment.getSecondStorageType() == Environment.SECOND_STORAGE_TYPE_NAND) {
-
mVolumeStates.put(Environment.getSecondStorageDirectory().getPath(), Environment.MEDIA_MOUNTED);
-
}
-
-
mPms = (PackageManagerService) ServiceManager.getService("package");
-
IntentFilter filter = new IntentFilter();
-
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-
-
if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {
-
filter.addAction(UsbManager.ACTION_USB_STATE);
-
}
-
-
mContext.registerReceiver(mBroadcastReceiver, filter, null, null);
-
-
mHandlerThread = new HandlerThread("MountService");
-
mHandlerThread.start();
-
-
mHandler = new MountServiceHandler(mHandlerThread.getLooper());
-
-
-
mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
-
-
-
-
-
-
-
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
-
-
Thread thread = new Thread(mConnector, VOLD_TAG);
-
thread.start();
-
-
-
if (WATCHDOG_ENABLE) {
-
Watchdog.getInstance().addMonitor(this);
-
}
-
}
在开始构造MountService前,首先读取frameworks/base/core/res/res/xml/storage_list.xml文件,该文件以XML方式保存了所有存储设备的参数,文件内容如下所示:
-
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
-
-
<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线程创建
-
mHandlerThread = new HandlerThread("MountService");
-
mHandlerThread.start();
-
mHandler = new MountServiceHandler(mHandlerThread.getLooper());
-
-
-
mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
MountServiceHandler消息处理:
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case H_UNMOUNT_PM_UPDATE: {
-
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
-
mForceUnmounts.add(ucb);
-
-
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;
-
-
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 {
-
-
ams.killPids(pids, "unmount media", true);
-
-
pids = getStorageUsers(path);
-
if (pids == null || pids.length == 0) {
-
done = true;
-
}
-
}
-
}
-
if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
-
-
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));
-
}
-
}
-
-
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
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case OBB_RUN_ACTION: {
-
final ObbAction action = (ObbAction) msg.obj;
-
-
-
-
if (!mBound) {
-
-
-
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) {
-
-
action.handleError();
-
}
-
mActions.clear();
-
} else if (mActions.size() > 0) {
-
final ObbAction action = mActions.get(0);
-
if (action != null) {
-
action.execute(this);
-
}
-
} else {
-
-
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) {
-
-
action.handleError();
-
}
-
mActions.clear();
-
}
-
}
-
break;
-
}
-
case OBB_MCS_UNBIND: {
-
-
if (mActions.size() > 0) {
-
mActions.remove(0);
-
}
-
if (mActions.size() == 0) {
-
if (mBound) {
-
disconnectService();
-
}
-
} else {
-
-
-
-
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即可,整个命令发送流程比较简单。
-
public int mountVolume(String path) {
-
-
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-
waitForReady();
-
-
return doMountVolume(path);
-
}
调用doMountVolume函数来挂载存储设备:
-
private int doMountVolume(String path) {
-
int rc = StorageResultCode.OperationSucceeded;
-
try {
-
-
mConnector.execute("volume", "mount", path);
-
} catch (NativeDaemonConnectorException e) {
-
-
String action = null;
-
int code = e.getCode();
-
if (code == VoldResponseCode.OpFailedNoMedia) {
-
-
-
-
rc = StorageResultCode.OperationFailedNoMedia;
-
} else if (code == VoldResponseCode.OpFailedMediaBlank) {
-
if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
-
-
-
-
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");
-
-
-
-
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
-
action = Intent.ACTION_MEDIA_UNMOUNTABLE;
-
rc = StorageResultCode.OperationFailedMediaCorrupt;
-
} else {
-
rc = StorageResultCode.OperationFailedInternalError;
-
}
-
-
-
-
if (action != null) {
-
sendStorageIntent(action, path);
-
}
-
}
-
return rc;
-
}
NativeDaemonConnector命令发送:
-
public NativeDaemonEvent execute(String cmd, Object... args)
-
throws NativeDaemonConnectorException {
-
-
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来发送命令和命令参数,并在这里设置超时时间:
-
public NativeDaemonEvent[] executeForList(String cmd, Object... args)
-
throws NativeDaemonConnectorException {
-
-
return execute(DEFAULT_TIMEOUT, cmd, args);
-
}
真正命令发送:
-
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();
-
log("SND -> {" + logCmd + "}");
-
cmdBuilder.append('\0');
-
final String sentCmd = cmdBuilder.toString();
-
synchronized (mDaemonLock) {
-
if (mOutputStream == null) {
-
throw new NativeDaemonConnectorException("missing output stream");
-
} else {
-
try {
-
-
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连接
-
public void run() {
-
-
HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
-
thread.start();
-
-
mCallbackHandler = new Handler(thread.getLooper(), this);
-
-
while (true) {
-
try {
-
listenToSocket();
-
} catch (Exception e) {
-
loge("Error in NativeDaemonConnector: " + e);
-
SystemClock.sleep(5000);
-
}
-
}
-
}
连接服务端Socket,并读取数据:
-
private void listenToSocket() throws IOException {
-
LocalSocket socket = null;
-
try {
-
-
socket = new LocalSocket();
-
LocalSocketAddress address = new LocalSocketAddress(mSocket,LocalSocketAddress.Namespace.RESERVED);
-
-
socket.connect(address);
-
-
InputStream inputStream = socket.getInputStream();
-
synchronized (mDaemonLock) {
-
mOutputStream = socket.getOutputStream();
-
}
-
-
mCallbacks.onDaemonConnected();
-
-
byte[] buffer = new byte[BUFFER_SIZE];
-
int start = 0;
-
-
while (true) {
-
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
-
-
if (count < 0) {
-
loge("got " + count + " reading with start = " + start);
-
break;
-
}
-
-
count += start;
-
start = 0;
-
-
for (int i = 0; i < count; i++) {
-
if (buffer[i] == 0) {
-
final String rawEvent = new String(buffer, start, i - start, Charsets.UTF_8);
-
-
log("RCV <- {" + rawEvent + "}");
-
-
try {
-
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);
-
-
if (event.isClassUnsolicited()) {
-
-
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 + "}");
-
}
-
-
-
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)连接成功回调处理
-
public void onDaemonConnected() {
-
-
new Thread("MountService#onDaemonConnected") {
-
@Override
-
public void run() {
-
-
-
-
try {
-
-
final String[] vols = NativeDaemonEvent.filterMessageList(
-
mConnector.executeForList("volume", "list"),
-
VoldResponseCode.VolumeListResult);
-
-
for (String volstr : vols) {
-
String[] tok = volstr.split(" ");
-
-
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);
-
-
updatePublicVolumeState(path, state);
-
}
-
}
-
} catch (Exception e) {
-
Slog.e(TAG, "Error processing initial volume state", e);
-
updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
-
}
-
-
-
-
-
-
mConnectedSignal.countDown();
-
mConnectedSignal = null;
-
-
-
mPms.scanAvailableAsecs();
-
-
-
mAsecsScanned.countDown();
-
mAsecsScanned = null;
-
}
-
}.start();
-
}
存储设备状态更新:
-
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)) {
-
-
if (!mEmulateExternalStorage) {
-
if (Environment.MEDIA_UNMOUNTED.equals(state)) {
-
mPms.updateExternalMediaStatus(false, false);
-
-
-
-
-
-
-
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 {
-
-
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的注册过程:
-
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定义如下:
-
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线程中处理:
-
public boolean handleMessage(Message msg) {
-
String event = (String) msg.obj;
-
try {
-
-
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;
-
}
-
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) {
-
-
-
-
-
-
notifyVolumeStateChange(cooked[2], cooked[3], Integer.parseInt(cooked[7]),Integer.parseInt(cooked[10]));
-
} else if ((code == VoldResponseCode.VolumeDiskInserted) ||
-
(code == VoldResponseCode.VolumeDiskRemoved) ||
-
(code == VoldResponseCode.VolumeBadRemoval)) {
-
-
-
-
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) {
-
-
-
-
if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
-
return true;
-
}
-
-
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");
-
-
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的通信到此就介绍完了。