【输出文档】 Android MountService 源码分析

Android 存储设备管理框架

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

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

Android MountService框架设计

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

[java] view plaincopy

 

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 plaincopy

 

  1. 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 plaincopy

 

<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带有消息循环的工作线程,用于处理MountServiceHandleObbActionHandler分发过来的消息;同时创建一个用于连接Vold服务端socketVoldConnector线程,该线程在进入闭环运行前会创建一个带有消息循环的VoldConnector.CallbackHandler线程,用于处理native层的Vold进程发送过来的uevent事件消息;然后向服务端Vold发送连接请求,得到socket连接后,从该socket中循环读取数据以接收来之服务端Volduevent消息,当读取的数据长度为0时,向服务端重新发起连接,如此循环,保证客户端MountService与服务端Vold一直保持正常连接。当成功连接到服务端Vold时,VoldConnector线程会创建一个MountService#onDaemonConnected线程,用于处理本次连接请求响应。

1.MountService线程创建

[java] view plaincopy

 

  1. 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 plaincopy



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 plaincopy

 


  1.  

MountService命令下发流程

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

从以上的时序图可以看出,MountService对命令的发送首先是调用makeCommand来组合成指定格式的命令[p2] ,然后直接写入到Vold socket即可,整个命令发送流程比较简单。

 

[java] view plaincopy

 

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

调用doMountVolume函数来挂载存储设备:

 

[java] view plaincopy

 

  1. 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 plaincopy

 

  1. 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 plaincopy

 

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

真正命令发送:

[java] view plaincopy

 

  1. 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消息接收流程[p3] 

MountService需要接收两种类型的消息:

1当外部存储设备发生热插拔时,kernel将通过netlink方式通知VoldVold进程经过一系列处理后最终还是要叫uevent事件消息发送给MountService,Vold发送uevent的过程已经在androidVOLD进程启动源码分析一文中详细介绍了;

2)当MountServiceVold发送命令后,将接收到Vold的响应消息;

无论是何种类型的消息,MountService都是通过VoldConnector线程来循环接收Vold的请求,整个消息接收流程如下:

1socket连接

[java] view plaincopy

 

  1. 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 plaincopy

 

  1. 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 plaincopy

 

  1. 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 plaincopy

 

  1. 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 plaincopy

 

  1. 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 plaincopy

 

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

最后调用ListenerDelegatesendStorageStateChanged来实现

3)事件处理

mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(event.getCode(), event.getRawEvent())); 将事件已消息的方式发送到VoldConnector.CallbackHandler线程中处理:

[java] view plaincopy

 

  1. 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 plaincopy
    
    
    
    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; 
    } 

整个MountServiceVold的通信到此就介绍完了。

 


VOLD 中通过CommandListener监听MountService 的消息;

MountService 发送命令 的生成

MountService 消息接收

猜你喜欢

转载自blog.csdn.net/pirionFordring/article/details/83419671
今日推荐