您的位置:首页 > 移动开发 > Android开发

Android Service之MountService源码分析

2014-03-04 19:30 363 查看

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创建及注册过程如下:

[java]
view plaincopyprint?

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 = 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对象实例:

[java]
view plaincopyprint?

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, nullnull);  
    //创建并启动一个带消息循环的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);  
    }  
}  

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方式保存了所有存储设备的参数,文件内容如下所示:

[html]
view plaincopyprint?

<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>  

<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线程创建

[java]
view plaincopyprint?

mHandlerThread = new HandlerThread("MountService");  
mHandlerThread.start();  
mHandler = new MountServiceHandler(mHandlerThread.getLooper());  
  
// Add OBB Action Handler to MountService thread.
  
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消息处理:

[java]
view plaincopyprint?

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(falsetrue);  
        }  
        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;  
    }  
    }  
}  

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

[java]
view plaincopyprint?

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;  
    }  
    }  
}  

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即可,整个命令发送流程比较简单。

[java]
view plaincopyprint?

public int mountVolume(String path) {  
        //权限检验
  
    validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);  
    waitForReady();  
  
    return doMountVolume(path);  
}  

public int mountVolume(String path) {
//权限检验
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();

return doMountVolume(path);
}
调用doMountVolume函数来挂载存储设备:

[java]
view plaincopyprint?

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;  
}  

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命令发送:

[java]
view plaincopyprint?

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];  
}  

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来发送命令和命令参数,并在这里设置超时时间:

[java]
view plaincopyprint?

public NativeDaemonEvent[] executeForList(String cmd, Object... args)  
    throws NativeDaemonConnectorException {  
    //设置超时时间:DEFAULT_TIMEOUT = 1 * 60 * 1000
  
    return execute(DEFAULT_TIMEOUT, cmd, args);  
}  

public NativeDaemonEvent[] executeForList(String cmd, Object... args)
throws NativeDaemonConnectorException {
//设置超时时间:DEFAULT_TIMEOUT = 1 * 60 * 1000
return execute(DEFAULT_TIMEOUT, cmd, args);
}
真正命令发送:

[java]
view plaincopyprint?

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()]);  
}  

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连接

[java]
view plaincopyprint?

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);  
        }  
    }  
}  

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,并读取数据:

[java]
view plaincopyprint?

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);  
        }  
    }  
}  

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)连接成功回调处理

[java]
view plaincopyprint?

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();  
}  

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();
}
存储设备状态更新:

[java]
view plaincopyprint?

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(falsefalse);  
  
                /* 
                 * 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(truefalse);  
            }  
        }  
    }  
    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;  
}  

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的注册过程:

[java]
view plaincopyprint?

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");  
        }  
    }  
}  

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定义如下:

[java]
view plaincopyprint?

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);  
        }  
    }  
}  

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线程中处理:

[java]
view plaincopyprint?

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;  
}  

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;
}


[java]
view plaincopyprint?

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;  
}  

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的通信到此就介绍完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: