本文基于android 早期版本 可能是4.4

1. 相关代码目录:

android \system\core\init

android\system\core\libsysutils\src\FrameworkListener.cpp

android \system\vold

android \frameworks\base\services\java\com\android\server

 

2. SD卡开机加载方法和简易流程图

总结起来SD卡加载大概有3种方式:

1.      开机自动加载;

2.      热插拔;

如果手机支持热插拔,底层驱动会将SD卡驱动信息发送给VOLD,VolumeManager 或者Volume类会将处理状态发送给MountService,MountService最后发送状态给APP;

 

3.      通过setting菜单安装

  /*卸载该分区挂载的所有挂载点,这里为什么用所有来形容了,因为Android 系统挂载一个分区的期间,重复挂载在好几个目录,将分区挂载在/mnt/asec目录,也挂载 

   在/mnt/secure/asec目录,也挂载在/mnt/sdcard目录下,总共三次挂载,谷歌不知为什么搞这么复杂? 

   待深究。。*/  

 

这里介绍下开机自动加载的过程,以下是一个简单流程图:



源代码分析:

1.      开机

 

Vold为一守护进程,初始化时,会创建classNetlinkManager和VolumeManager,

Class  NetlinkManager接收来自底层的信息,然后转交给VolumeManager处理;

class VolumeManager 单例模式,它主要负责vold的管理操作

class DirectVolume封装了很多的方法和属性;

class  CommandListener内部封装了一个socket 用来跨进程通信,它在vold 进程中属于监听类,即服务器端,主要收到上层 MountService发来的命令,分析后,转交给VolumeManager处理;VolumeManager处理信息后,或报告给上层MountService

 

关于vold 的其他介绍请参考之前的《SD卡基本功能的原理实现和流程分析》。

 

system\core\init\init.c

Init .c通过加载Init.rc文件初始化Vold 模块和app_process模块,找到主函数main开始执行

 

service vold /system/bin/vold

   class core

   socket vold stream 0660 root mount

ioprio be 2

 

service zygote /system/bin/app_process-Xzygote /system/bin --zygote --start-system-server

   class main

   socket zygote stream 660 root system

   onrestart write /sys/android_power/request_state wake

   onrestart write /sys/power/state on

   onrestart restart media

   onrestart restart netd

 

找到主函数main开始执行,vold模块main 函数:

int main() {

 

   VolumeManager *vm;

   CommandListener *cl;

   NetlinkManager *nm;

 

   SLOGI("Vold 2.1 (the revenge) firing up");

 

   mkdir("/dev/block/vold", 0755);

 

   /* For when cryptfs checks and mounts an encrypted filesystem */

   klog_set_level(6);

 

   /* Create our singleton managers */

   if (!(vm = VolumeManager::Instance())) {

       SLOGE("Unable to create VolumeManager");

       exit(1);

   };

 

   if (!(nm = NetlinkManager::Instance())) {

       SLOGE("Unable to create NetlinkManager");

       exit(1);

   };

 

   cl = new CommandListener();

   vm->setBroadcaster((SocketListener *) cl);

   nm->setBroadcaster((SocketListener *) cl);

 

   if (vm->start()) {

       SLOGE("Unable to start VolumeManager (%s)", strerror(errno));

       exit(1);

    }

 

   if (process_config(vm)) {

       SLOGE("Error reading configuration (%s)... continuing anyways",strerror(errno));

    }

 

   if (nm->start()) {

       SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));

       exit(1);

    }

 

   coldboot("/sys/block");

//   coldboot("/sys/class/switch");

 

   /*

    * Now that we're up, we can respond to commands

    */

   if (cl->startListener()) {

       SLOGE("Unable to start CommandListener (%s)",strerror(errno));

       exit(1);

    }

 

   // Eventually we'll become the monitoring thread

   while(1) {

       sleep(1000);

    }

 

   SLOGI("Vold exiting");

   exit(0);

}

app_main.cpp 主函数:

int main(int argc, char* const argv[])

{

#ifdef __arm__

   /*

    * b/7188322 - Temporarily revert to the compat memory layout

    * to avoid breaking third party apps.

    *

    * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.

    *

    *http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466

    * changes the kernel mapping from bottom up to top-down.

    * This breaks some programs which improperly embed

    * an out of date copy of Android's linker.

    */

   char value[PROPERTY_VALUE_MAX];

   property_get("ro.kernel.qemu", value, "");

   bool is_qemu = (strcmp(value, "1") == 0);

   if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) &&!is_qemu) {

       int current = personality(0xFFFFFFFF);

       if ((current & ADDR_COMPAT_LAYOUT) == 0) {

           personality(current | ADDR_COMPAT_LAYOUT);

           setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);

           execv("/system/bin/app_process", argv);

           return -1;

       }

    }

   unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");

#endif

 

   // ADDED BY MARS BEGIN

   setconnecthook(android::hook_connect);

   // ADDED BY MARS END

 

    //These are global variables in ProcessState.cpp

   mArgC = argc;

   mArgV = argv;

 

   mArgLen = 0;

   for (int i=0; i

       mArgLen += strlen(argv[i]) + 1;

    }

   mArgLen--;

 

   AppRuntime runtime;

   const char* argv0 = argv[0];

 

   // Process command line arguments

   // ignore argv[0]

   argc--;

   argv++;

 

   // Everything up to '--' or first non '-' arg goes to the vm

 

   int i = runtime.addVmArguments(argc, argv);

 

   // Parse runtime arguments.  Stopat first unrecognized option.

   bool zygote = false;

   bool startSystemServer = false;

   bool application = false;

   const char* parentDir = NULL;

   const char* niceName = NULL;

   const char* className = NULL;

   while (i < argc) {

       const char* arg = argv[i++];

       if (!parentDir) {

           parentDir = arg;

       } else if (strcmp(arg, "--zygote") == 0) {

           zygote = true;

           niceName = "zygote";

       } else if (strcmp(arg, "--start-system-server") == 0) {

           startSystemServer = true;

       } else if (strcmp(arg, "--application") == 0) {

           application = true;

       } else if (strncmp(arg, "--nice-name=", 12) == 0) {

           niceName = arg + 12;

       } else {

           className = arg;

           break;

       }

    }

 

   if (niceName && *niceName) {

       setArgv0(argv0, niceName);

       set_process_name(niceName);

    }

 

   runtime.mParentDir = parentDir;

 

    if (zygote) {

       runtime.start("com.android.internal.os.ZygoteInit",

                startSystemServer ?"start-system-server" : "");

    } else if(className) {

       // Remainder of args get passed to startup class main()

       runtime.mClassName = className;

       runtime.mArgC = argc - i;

       runtime.mArgV = argv + i;

       runtime.start("com.android.internal.os.RuntimeInit",

                application ?"application" : "tool");

    }else {

       fprintf(stderr, "Error: no class name or --zygotesupplied.\n");

       app_usage();

       LOG_ALWAYS_FATAL("app_process: no class name or --zygotesupplied.");

       return 10;

    }

}

 

 

ZygoteInit.java 找到主函数:

    public static void main(String argv[]) {

        try {

            // Start profiling the zygoteinitialization.

            SamplingProfilerIntegration.start();

 

            registerZygoteSocket();

           EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,

                SystemClock.uptimeMillis());

            preload();

            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,

                SystemClock.uptimeMillis());

 

            // Finish profiling the zygoteinitialization.

           SamplingProfilerIntegration.writeZygoteSnapshot();

 

            // Do an initial gc to clean upafter startup

            gc();

 

            // Disable tracing so that forkedprocesses do not inherit stale tracing tags from

            // Zygote.

            Trace.setTracingEnabled(false);

 

            // If requested, start systemserver directly from Zygote

            if (argv.length != 2) {

                throw newRuntimeException(argv[0] + USAGE_STRING);

            }

 

            if(argv[1].equals("start-system-server")) {

               startSystemServer();

                //ADDED BY MARS BEGIN

                // startMrvlRootServer();

                //ADDED BY MARS END

            } else if (!argv[1].equals("")) {

                throw newRuntimeException(argv[0] + USAGE_STRING);

            }

 

            Log.i(TAG, "Accepting commandsocket connections");

 

            runSelectLoop();

 

            closeServerSocket();

        } catch (MethodAndArgsCaller caller) {

            caller.run();

        } catch (RuntimeException ex) {

            Log.e(TAG, "Zygote died withexception", ex);

            closeServerSocket();

            throw ex;

        }

    }

 

 

    private static boolean startSystemServer()

            throws MethodAndArgsCaller,RuntimeException {

        long capabilities =posixCapabilitiesAsBits(

            OsConstants.CAP_KILL,

            OsConstants.CAP_NET_ADMIN,

            OsConstants.CAP_NET_BIND_SERVICE,

            OsConstants.CAP_NET_BROADCAST,

            OsConstants.CAP_NET_RAW,

            OsConstants.CAP_SYS_MODULE,

            OsConstants.CAP_SYS_NICE,

            OsConstants.CAP_SYS_RESOURCE,

            OsConstants.CAP_SYS_TIME,

            OsConstants.CAP_SYS_TTY_CONFIG

        );

        /* Hardcoded command line to start thesystem server */

        String args[] = {

            "--setuid=1000",

            "--setgid=1000",

           "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",

            "--capabilities=" +capabilities + "," + capabilities,

            "--runtime-init",

            "--nice-name=system_server",

           "com.android.server.SystemServer",

        };

        ZygoteConnection.Arguments parsedArgs =null;

 

        int pid;

 

        try {

            parsedArgs = newZygoteConnection.Arguments(args);

           ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);

           ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

 

            /* Requestto fork the system server process */

            pid =Zygote.forkSystemServer(

                    parsedArgs.uid, parsedArgs.gid,

                   parsedArgs.gids,

                   parsedArgs.debugFlags,

                   null,

                   parsedArgs.permittedCapabilities,

                   parsedArgs.effectiveCapabilities);

        } catch (IllegalArgumentException ex) {

            throw new RuntimeException(ex);

        }

 

        /* For child process */

        if (pid == 0) {

           handleSystemServerProcess(parsedArgs);

        }

 

        return true;

    }

 

SystemServer.java

   public static void main(String[] args) {

       SystemProperties.set("persist.sys.dalvik.vm.lib",

                            VMRuntime.getRuntime().vmLibrary());

 

       if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {

           // If a device's clock is before 1970 (before 0), a lot of

           // APIs crash dealing with negative numbers, notably

           // java.io.File#setLastModified, so instead we fake it and

           // hope that time from cell towers or NTP fixes it

           // shortly.

           Slog.w(TAG, "System clock is before 1970; setting to 1970.");

           SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);

       }

 

       if (SamplingProfilerIntegration.isEnabled()) {

           SamplingProfilerIntegration.start();

           timer = new Timer();

           timer.schedule(new TimerTask() {

                @Override

                public void run() {

                   SamplingProfilerIntegration.writeSnapshot("system_server",null);

                }

           }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);

       }

 

       // Mmmmmm... more memory!

       dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();

 

       // The system server has to run all of the time, so it needs to be

       // as efficient as possible with its memory usage.

       VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

 

       Environment.setUserRequired(true);

 

       System.loadLibrary("android_servers");

 

      

 Slog.i(TAG, "Entered the Android systemserver!");

 

       // Initialize native services.

       nativeInit();

 

       // This used to be its own separate thread, but now it is

       // just the loop we run on the main thread.

       ServerThread thr = new ServerThread();

        thr.initAndLoop();

}

 

initAndLoop函数代码比较长,它会初始化系统的service, 当然也包括我们关心的MountService:

先构造函数:

mountService = new MountService(context);

然后调用ActivityManagerService.self().systemReady

 

        // We now tell the activity manager itis okay to run third party

        // code.  It will call back into us once it has gottento the state

        // where third party code can reallyrun (but before it has actually

        // started launching the initialapplications), for us to complete our

        // initialization.

ActivityManagerService.self().systemReady(newRunnable() {

            public void run() {

                Slog.i(TAG, "Makingservices ready");

 

                try {

                    ActivityManagerService.self().startObservingNativeCrashes();

                } catch (Throwable e) {

                    reportWtf("observingnative crashes", e);

                }

                if (!headless) {

                    startSystemUi(contextF);

                }

                try {

                    if(mountServiceF != null) mountServiceF.systemReady();

                } catch(Throwable e) {

                   reportWtf("making Mount Service ready", e);

                }

 

 

MountService 构造函数:

    public MountService(Context context) {

        mContext = context;

 

        synchronized (mVolumesLock) {

            readStorageListLocked();

        }

 

        // XXX: This will go away soon in favorof IMountServiceObserver

        mPms = (PackageManagerService)ServiceManager.getService("package");

新建一个重要的HandlerThread,用来处理一些重要的消息,主要处理开机和卸载的时候的一些消息

 

        HandlerThreadhthread = new HandlerThread(TAG);

       hthread.start();

        mHandler = newMountServiceHandler(hthread.getLooper());

 

        // Watch for user changes

        final IntentFilter userFilter = newIntentFilter();

       userFilter.addAction(Intent.ACTION_USER_ADDED);

       userFilter.addAction(Intent.ACTION_USER_REMOVED);

        mContext.registerReceiver(mUserReceiver,userFilter, null, mHandler);

 

        // Watch for USB changes on availablevolumes

        StorageVolume[] volumes =getVolumeList();

        boolean allowUMS = false;

        for (StorageVolume volume : volumes) {

            if (volume != null &&volume.allowMassStorage()) {

                allowUMS = true;

                break;

            }

        }

        if (allowUMS) {

           mContext.registerReceiver(mUsbReceiver, newIntentFilter(UsbManager.ACTION_USB_STATE),

                    null, mHandler);

        }

 

        // Watch for idle maintenance changes

        IntentFilter idleMaintenanceFilter =new IntentFilter();

       idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);

        mContext.registerReceiverAsUser(mIdleMaintenanceReceiver,UserHandle.ALL,

                idleMaintenanceFilter, null,mHandler);

 

        // Add OBB Action Handler toMountService thread.

        mObbActionHandler = newObbActionHandler(IoThread.get().getLooper());

 

        /*

         * Create the connection to vold with amaximum queue of twice the

         * amount of containers we'd everexpect to have. This keeps an

         * "asec list" from blockinga thread repeatedly.

         */

        mConnector =new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG,25);

 

        Thread thread = new Thread(mConnector,VOLD_TAG);

        thread.start();

这里启用了一个新线程,最终会在listenToSocke()函数中回调到onDaemonConnected(),

        // Add ourself to the Watchdog monitorsif enabled.

        if (WATCHDOG_ENABLE) {

           Watchdog.getInstance().addMonitor(this);

        }

    }

 

//构造函数

   NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, Stringsocket,

            int responseQueueSize, StringlogTag, int maxLogSize) {

        mCallbacks = callbacks;

        mSocket = socket;

        mResponseQueue = newResponseQueue(responseQueueSize);

        mSequenceNumber = new AtomicInteger(0);

        TAG = logTag != null ? logTag :"NativeDaemonConnector";

        mLocalLog = new LocalLog(maxLogSize);

    }

 

    @Override

    public void run() {

        mCallbackHandler = newHandler(FgThread.get().getLooper(), this);

 

        while (true) {

            try {

//开始监听来自于底层vold部分的消息

                listenToSocket();

            } catch (Exception e) {

                loge("Error inNativeDaemonConnector: " + e);

                SystemClock.sleep(5000);

            }

        }

    }

 

 

    public void onDaemonConnected() {

        /*

         * Since we'll be calling back into theNativeDaemonConnector,

         * we need to do our work in a newthread.

         */

        newThread("MountService#onDaemonConnected") {

            @Override

            public void run() {

                /**

                 * Determine media state andUMS detection status

                 */

                try {

//给vold下发volume list命令,先列出系统目前有几个volume对象,获取到这些对象的标签

                    final String[] vols =NativeDaemonEvent.filterMessageList(

                           mConnector.executeForList("volume", "list"),

                           VoldResponseCode.VolumeListResult);

                    for (String volstr : vols){

                        String[] tok =volstr.split(" ");

                        // FMT:

                        String path = tok[1];

                        String state =Environment.MEDIA_REMOVED;

 

                        final StorageVolumevolume;

                        synchronized(mVolumesLock) {

                            volume =mVolumesByPath.get(path);

                        }

……

}

MountService.java

    public void systemReady() {

        mSystemReady = true;

       mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();

    }

此处通过向MountServiceHandler发送H_SYSTEM_READY 消息来调用handleSystemReady()函数:

 

   private void handleSystemReady() {

        // Snapshot current volume states sinceit's not safe to call into vold

        // while holding locks.

        final HashMapsnapshot;

        synchronized (mVolumesLock) {

            snapshot = new HashMap(mVolumeStates);

        }

 

        for (Map.Entryentry : snapshot.entrySet()) {

            final String path = entry.getKey();

            final String state =entry.getValue();

 

            if(state.equals(Environment.MEDIA_UNMOUNTED)) {

                int rc = doMountVolume(path);

                if (rc !=StorageResultCode.OperationSucceeded) {

                    Slog.e(TAG,String.format("Boot-time mount failed (%d)",

                            rc));

                }

            } else if(state.equals(Environment.MEDIA_SHARED)) {

                /*

                 * Bootstrap UMS enabled statesince vold indicates

                 * the volume is shared(runtime restart while ums enabled)

                 */

                notifyVolumeStateChange(null,path, VolumeState.NoMedia,

                        VolumeState.Shared);

            }

        }

 

        // Push mounted state for all emulatedstorage

        synchronized (mVolumesLock) {

            for (StorageVolume volume :mVolumes) {

                if (volume.isEmulated()) {

                   updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);

                }

            }

        }

 

        /*

         * If UMS was connected on boot, sendthe connected event

         * now that we're up.

         */

        if (mSendUmsConnectedOnBoot) {

            sendUmsIntent(true);

            mSendUmsConnectedOnBoot = false;

        }

    }

 

doMountVolume就是之前讲过的挂载函数,NativeDaemonConnector 和CommandListener 作为桥梁将volume mount 命令发送给vold 模块的另一大类VolumeManager来执行相应的挂载操作,挂载完成后会将相应的状态信息再通过这个桥梁发送给Mountservice中的onEvent,于是执行以下函数:

    private void notifyVolumeStateChange(Stringlabel, String path, int oldState, int newState) {

        final StorageVolume volume;

        final String state;

        synchronized (mVolumesLock) {

            volume = mVolumesByPath.get(path);

            state = getVolumeState(path);

        }

 

        if (DEBUG_EVENTS) Slog.i(TAG,"notifyVolumeStateChange::" + state);

 

        String action = null;

 

        if (oldState == VolumeState.Shared&& newState != oldState) {

            if (LOCAL_LOGD) Slog.d(TAG,"Sending ACTION_MEDIA_UNSHARED intent");

           sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);

        }

 

        if (newState == VolumeState.Init) {

        } else if (newState ==VolumeState.NoMedia) {

            // NoMedia is handled via DiskRemove events

        } else if (newState ==VolumeState.Idle) {

            /*

             * Don't notify if we're inBAD_REMOVAL, NOFS, UNMOUNTABLE, or

             * if we're in the process of enablingUMS

             */

            if (!state.equals(

                   Environment.MEDIA_BAD_REMOVAL) && !state.equals(

                           Environment.MEDIA_NOFS) && !state.equals(

                                    Environment.MEDIA_UNMOUNTABLE)&& !getUmsEnabling()) {

                if (DEBUG_EVENTS) Slog.i(TAG,"updating volume state for media bad removal nofs and unmountable");

                updatePublicVolumeState(volume,Environment.MEDIA_UNMOUNTED);

                action =Intent.ACTION_MEDIA_UNMOUNTED;

            }

        } else if (newState ==VolumeState.Pending) {

        } else if (newState ==VolumeState.Checking) {

            if (DEBUG_EVENTS) Slog.i(TAG,"updating volume state checking");

            updatePublicVolumeState(volume,Environment.MEDIA_CHECKING);

            action =Intent.ACTION_MEDIA_CHECKING;

        } else if(newState == VolumeState.Mounted) {

            if(DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");

           updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);

            action =Intent.ACTION_MEDIA_MOUNTED;

        } else if (newState == VolumeState.Unmounting) {

            action = Intent.ACTION_MEDIA_EJECT;

        } else if (newState ==VolumeState.Formatting) {

        } else if (newState ==VolumeState.Shared) {

            if (DEBUG_EVENTS) Slog.i(TAG,"Updating volume state media mounted");

            /* Send the media unmounted eventfirst */

            updatePublicVolumeState(volume,Environment.MEDIA_UNMOUNTED);

           sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume,UserHandle.ALL);

 

            if (DEBUG_EVENTS) Slog.i(TAG,"Updating media shared");

            updatePublicVolumeState(volume,Environment.MEDIA_SHARED);

            action =Intent.ACTION_MEDIA_SHARED;

            if (LOCAL_LOGD) Slog.d(TAG,"Sending ACTION_MEDIA_SHARED intent");

        } else if (newState ==VolumeState.SharedMnt) {

            Slog.e(TAG, "Live shared mountsnot supported yet!");

            return;

        } else {

            Slog.e(TAG, "UnhandledVolumeState {" + newState + "}");

        }

 

        if (action != null) {

            sendStorageIntent(action,volume, UserHandle.ALL);

        }

    }

 

 

    private void sendStorageIntent(Stringaction, StorageVolume volume, UserHandle user) {

        final Intent intent = newIntent(action, Uri.parse("file://" + volume.getPath()));

       intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);

        Slog.d(TAG, "sendStorageIntent "+ intent + " to " + user);

        mContext.sendBroadcastAsUser(intent,user);

    }

3. 关机卸载SD卡部分




 

MountServiceHandler 接收消息顺序:

1  H_UNMOUNT_PM_UPDATE

2  H_UNMOUNT_PM_DONE

3  H_UNMOUNT_MS

 

 

 

关机确认后,启动关机线程ShutdownThread的run 函数,

public void run() {

……

        synchronized (mActionDoneSync) {

            try {

                final IMountService mount =IMountService.Stub.asInterface(

                       ServiceManager.checkService("mount"));

                if(mount != null) {

                   mount.shutdown(observer);

                } else{

                   Log.w(TAG, "MountService unavailable for shutdown");

                }

            } catch (Exception e) {

                Log.e(TAG, "Exceptionduring MountService shutdown", e);

            }

            while (!mActionDone) {

                long delay = endShutTime -SystemClock.elapsedRealtime();

                if (delay <= 0) {

                    Log.w(TAG, "Shutdownwait timed out");

                    break;

                }

                try {

                   mActionDoneSync.wait(delay);

                } catch (InterruptedExceptione) {

                }

            }

        }

……

}

这里调用到MountService 中的shutdown 函数:

   public void shutdown(final IMountShutdownObserver observer) {

       validatePermission(android.Manifest.permission.SHUTDOWN);

 

       Slog.i(TAG, "Shutting down");

       synchronized (mVolumesLock) {

           for (String path : mVolumeStates.keySet()) {

                String state = mVolumeStates.get(path);

 

                if(state.equals(Environment.MEDIA_SHARED)) {

                    /*

                     * If the media is currently shared, unshareit.

                     * XXX: This is stilldangerous!. We should not

                     * be rebooting at *all* ifUMS is enabled, since

                     * the UMS host could havedirty FAT cache entries

                     * yet to flush.

                     */

                   setUsbMassStorageEnabled(false);

                } else if(state.equals(Environment.MEDIA_CHECKING)) {

                    /*

                     * If the media is being checked,then we need to wait for

                     * it to complete beforebeing able to proceed.

                     */

                    // XXX: @hackbod - Shouldwe disable the ANR timer here?

                    int retries = 30;

                    while(state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {

                        try {

                            Thread.sleep(1000);

                        } catch(InterruptedException iex) {

                            Slog.e(TAG, "Interruptedwhile waiting for media", iex);

                            break;

                        }

                        state =Environment.getExternalStorageState();

                    }

                    if (retries == 0) {

                        Slog.e(TAG, "Timedout waiting for media to check");

                    }

                }

 

                if (state.equals(Environment.MEDIA_MOUNTED)){

                    // Post a unmount message.

                    ShutdownCallBack ucb = newShutdownCallBack(path, observer);

                   mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));

                } elseif (observer != null) {

                    /*

                     * Observer is waiting foronShutDownComplete when we are done.

                     * Since nothing will bedone send notification directly so shutdown

                     * sequence can continue.

                     */

                    try {

                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);

                    } catch (RemoteException e){

                        Slog.w(TAG,"RemoteException when shutting down");

                    }

                }

           }

       }

}

通过给MountServiceHandler发送H_UNMOUNT_PM_UPDATE消息调用PM中的updateExternalMediaStatus函数来更新外部媒体状态,PM中unloadAllContainers();会先调用SecureContainer   卸载安全目录(如果有挂载该安全目录), 处理完成后调用MountService中的finishMediaUpdate()来给MountServiceHandler再发送  H_UNMOUNT_PM_DONE,H_UNMOUNT_MS消息来杀死运行中的进程,

最后调用到doUnmountVolume 函数,和挂载时一样通过给vold 发送卸载命令来卸载SD卡。

可以看到安卓为了模块间的独立大量使用了轻量级的IPC binder 和一些线程间消息的传递。



4. 热插拔SD卡简介

NetlinkManager  中监听Linux内核的热插拔事件,uevent事件

 

void NetlinkHandler::onEvent(NetlinkEvent*evt) {

   VolumeManager *vm = VolumeManager::Instance();

   const char *subsys = evt->getSubsystem();

 

   if (!subsys) {

       SLOGW("No subsystem found in netlink event");

       return;

    }

 

   if (!strcmp(subsys, "block")) {

       vm->handleBlockEvent(evt);

}

 

int DirectVolume::handleBlockEvent(NetlinkEvent*evt) 对以下六种磁盘的操作动作做出判断

 

void handleDiskAdded(const char *devpath,NetlinkEvent *evt); 

void handleDiskRemoved(const char *devpath,NetlinkEvent *evt); 

void handleDiskChanged(const char *devpath,NetlinkEvent *evt); 

void handlePartitionAdded(const char*devpath, NetlinkEvent *evt); 

void handlePartitionRemoved(const char*devpath, NetlinkEvent *evt); 

void handlePartitionChanged(const char*devpath, NetlinkEvent *evt); 

 

主要用来处理存储卡插入移除和SD卡改变,以及一些分区的处理,同时发送状态的改变信息给MountService. 再由MountService 来下发相应的命令给vold中的VolumeManager来做相应的处理。

 

1.      Socket 通信

未完。。。

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. Linux Kernel and Android(安卓)休眠与唤醒
  4. Android(安卓)NDK中使用LOG调试C++程序
  5. Android4.4 GPS框架分析
  6. Android(安卓)锁屏或者home键 tcp 断开
  7. Android(安卓)Studio 开发–微信APP门户界面设计
  8. 史无前例!全网最全的Android面试题集锦(贼干货!)
  9. Android事件分发机制完全解析(终极版)

随机推荐

  1. Andriod 环境配置以及第一个Android Appl
  2. android 调用系统相机拍照并保存照片原图
  3. Android系统的开机画面显示过程分析(11)
  4. Android(安卓)Textview实现文字颜色渐变
  5. Android(安卓)javah -jni 找不到类的解决
  6. android studio中光线传感器解析
  7. Android(安卓)ViewPager的初始化及遇到的
  8. [Android] 输入法的开发
  9. 安卓APP:利用AndroidStudio开发usb串口通
  10. android p状态栏,插入sim卡,关闭数据流量,状