基于Android 4.4得源码分析得。

最近有客户反馈Android得关机流程出现关机logo显示很久得问题,所有今天看下Android得关机流程(项目是基于4.4版本得)

长按power降会出现关机选择框源码在PhoneWindowManager.java中得interceptPowerKeyDown进行处理。

    private void interceptPowerKeyDown(boolean handled) {        mPowerKeyHandled = handled;        if (!handled) {            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());        }    }
 private final Runnable mPowerLongPress = new Runnable() {        @Override        public void run() {        mBootFastRuning = true;            // The context isn't read            if (mLongPressOnPowerBehavior < 0) {                mLongPressOnPowerBehavior = mContext.getResources().getInteger(                        com.android.internal.R.integer.config_longPressOnPowerBehavior);            }            int resolvedBehavior = mLongPressOnPowerBehavior;            if (FactoryTest.isLongPressOnPowerOffEnabled()) {                resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;            }            Slog.e(TAG, "resolvedBehavior: " + resolvedBehavior);            switch (resolvedBehavior) {            case LONG_PRESS_POWER_NOTHING:                break;            //弹框确认是否关机            case LONG_PRESS_POWER_GLOBAL_ACTIONS:                mPowerKeyHandled = true;                if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {                    performAuditoryFeedbackForAccessibilityIfNeed();                }                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);showGlobalActionsDialog();                     break;            //直接关机            case LONG_PRESS_POWER_SHUT_OFF:            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:                mPowerKeyHandled = true;                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);                mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);                break;            }if(DEBUG_BOOTFAST)Slog.d(TAG,"shutdown finish out");mBootFastRuning = false;                    }    };

处理过程是在mPowerLongPress线程了,可以选择立刻关机或者弹框选择。接着看下showGlobalActionsDialog();得流程。

    void showGlobalActionsDialog() {        if (mGlobalActions == null) {            //创建GlobalActions对象            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);        }        final boolean keyguardShowing = keyguardIsShowingTq();        //显示弹框        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());        if (keyguardShowing) {            // since it took two seconds of long press to bring this up,            // poke the wake lock so they have some time to see the dialog.            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);        }    }

调用showDialog来显示。

    /**     * Show the global actions dialog (creating if necessary)     * @param keyguardShowing True if keyguard is showing     */    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {        mKeyguardShowing = keyguardShowing;        mDeviceProvisioned = isDeviceProvisioned;        if (mDialog != null) {            //如果显示了,先关闭            mDialog.dismiss();            mDialog = null;            // Show delayed, so that the dismiss of the previous dialog completes            mHandler.sendEmptyMessage(MESSAGE_SHOW);        } else {            handleShow();        }    }

如何dialog显示,先关闭,然后再显示,否则调用handleShow();

private void handleShow() {         awakenIfNecessary();        mDialog = createDialog();   //创建dialog对象        prepareDialog();            //准备dialog       WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();        attrs.setTitle("GlobalActions");        mDialog.getWindow().setAttributes(attrs);        mDialog.show();        //显示        mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);mWindowManagerFuncs.shutdown(true);    }

主要是创建dialog然后显示,接下里得关机动作在dialog中进行选择,看下createDialog得源码。

 /**     * Create the global actions dialog.     * @return A new dialog.     */    private GlobalActionsDialog createDialog() {        // Simple toggle style if there's no vibrator, otherwise use a tri-state        if (!mHasVibrator) {            mSilentModeAction = new SilentModeToggleAction();        } else {            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);        }        mAirplaneModeOn = new ToggleAction(                R.drawable.ic_lock_airplane_mode,                R.drawable.ic_lock_airplane_mode_off,                R.string.global_actions_toggle_airplane_mode,                R.string.global_actions_airplane_mode_on_status,                R.string.global_actions_airplane_mode_off_status) {            void onToggle(boolean on) {                if (mHasTelephony && Boolean.parseBoolean(                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {                    mIsWaitingForEcmExit = true;                    // Launch ECM exit dialog                    Intent ecmDialogIntent =                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                    mContext.startActivity(ecmDialogIntent);                } else {                    changeAirplaneModeSystemSetting(on);                }            }            @Override            protected void changeStateFromPress(boolean buttonOn) {                if (!mHasTelephony) return;                // In ECM mode airplane state cannot be changed                if (!(Boolean.parseBoolean(                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {                    mState = buttonOn ? State.TurningOn : State.TurningOff;                    mAirplaneState = mState;                }            }            public boolean showDuringKeyguard() {                return true;            }            public boolean showBeforeProvisioning() {                return true;            }        };        onAirplaneModeChanged();        mItems = new ArrayList();        // first: power off        mItems.add(            new SinglePressAction(                    com.android.internal.R.drawable.ic_lock_power_off,                    R.string.global_action_power_off) {                public void onPress() {                    // shutdown by making sure radio and power are handled accordingly.                    mWindowManagerFuncs.shutdown(true);                }                public boolean onLongPress() {                    mWindowManagerFuncs.rebootSafeMode(true);                    return true;                }                public boolean showDuringKeyguard() {                    return true;                }                public boolean showBeforeProvisioning() {                    return true;                }            });        // reboot, added by yemao, 2013-8-22 12:57:21        mItems.add(            new SinglePressAction(                    com.android.internal.R.drawable.ic_lock_reboot,                    R.string.global_action_reboot) {                public void onPress() {                    // reboot                    mWindowManagerFuncs.reboot("Global Action Reboot!!", true);                }                public boolean onLongPress() {                    return true;                }                public boolean showDuringKeyguard() {                    return true;                }                public boolean showBeforeProvisioning() {                    return true;                }            });        // next: airplane mode        // remove Airplane Toggle in non-telephony applications, yemao, 2013-5-27 20:39:12        // use the same property with which of baseband version used in the Settings.apk        if (SystemProperties.getBoolean("ro.sw.embeded.telephony", false)) {            mItems.add(mAirplaneModeOn);        }        // next: bug report, if enabled        if (Settings.Global.getInt(mContext.getContentResolver(),                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {            mItems.add(                new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,                        R.string.global_action_bug_report) {                    public void onPress() {                        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);                        builder.setTitle(com.android.internal.R.string.bugreport_title);                        builder.setMessage(com.android.internal.R.string.bugreport_message);                        builder.setNegativeButton(com.android.internal.R.string.cancel, null);                        builder.setPositiveButton(com.android.internal.R.string.report,                                new DialogInterface.OnClickListener() {                                    @Override                                    public void onClick(DialogInterface dialog, int which) {                                        // Add a little delay before executing, to give the                                        // dialog a chance to go away before it takes a                                        // screenshot.                                        mHandler.postDelayed(new Runnable() {                                            @Override public void run() {                                                try {                                                    ActivityManagerNative.getDefault()                                                            .requestBugReport();                                                } catch (RemoteException e) {                                                }                                            }                                        }, 500);                                    }                                });                        AlertDialog dialog = builder.create();                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);                        dialog.show();                    }                    public boolean onLongPress() {                        return false;                    }                    public boolean showDuringKeyguard() {                        return true;                    }                    public boolean showBeforeProvisioning() {                        return false;                    }                });        }

可以看到关机得函数是在mWindowManagerFuncs.shutdown(true);shutdown函数得实现是在WindowManagerService中得。

    // Called by window manager policy.  Not exposed externally.    @Override    public void shutdown(boolean confirm) {        ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);    }

主要实现得还是子啊ShutdownThread得线程里。

    /**     * Request a clean shutdown, waiting for subsystems to clean up their     * state etc.  Must be called from a Looper thread in which its UI     * is shown.     *     * @param context Context used to display the shutdown progress dialog.     * @param confirm true if user confirmation is needed before shutting down.     */    public static void shutdown(final Context context, boolean confirm) {        mReboot = false;        mRebootSafeMode = false;        shutdownInner(context, confirm);    }

接着看下shutdownInner是如何实现得。

static void shutdownInner(final Context context, boolean confirm) {        // ensure that only one thread is trying to power down.        // any additional calls are just returned        //确保只有一个关机线程        synchronized (sIsStartedGuard) {            if (sIsStarted) {                Log.d(TAG, "Request to shutdown already running, returning.");                return;            }        }         获取长按资源id        final int longPressBehavior = context.getResources().getInteger(                        com.android.internal.R.integer.config_longPressOnPowerBehavior);         final int resourceId = mRebootSafeMode                ? com.android.internal.R.string.reboot_safemode_confirm                : (longPressBehavior == 2                        ? com.android.internal.R.string.shutdown_confirm_question                        : com.android.internal.R.string.shutdown_confirm);        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);        if (confirm) {            final CloseDialogReceiver closer = new CloseDialogReceiver(context);            if (sConfirmDialog != null) {                sConfirmDialog.dismiss();            }            // add for reboot Global Action, yemao, 2013-8-22 22:08:49           (mRebootSafeMode == true){               //再次确认是否关机,所以需要创建弹框                sConfirmDialog = new AlertDialog.Builder(context)                    .setTitle(mRebootSafeMode                            ? com.android.internal.R.string.reboot_safemode_title                            : com.android.internal.R.string.power_off)                    .setMessage(resourceId)                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {                        public void onClick(DialogInterface dialog, int which) {                            beginShutdownSequence(context);                        }                    })                    .setNegativeButton(com.android.internal.R.string.no, null)                    .create();            } else {                if(Settings.Global.getInt(context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1)==1&&SystemProperties.getBoolean("ro.sys.bootfast", false)){                    boolean [] enableBootFast = {false};                    enableBootFast[0] = Settings.System.getIntForUser(context.getContentResolver(), Settings.System.BOOT_FAST_ENABLE, 0,UserHandle.USER_CURRENT)==0?false:true;                    sConfirmDialog = new AlertDialog.Builder(context)                    .setTitle(mRebootSafeMode                            ? com.android.internal.R.string.reboot_safemode_title                            : com.android.internal.R.string.power_off)                    .setMultiChoiceItems(com.android.internal.R.array.quick_boot_mode,enableBootFast,new DialogInterface.OnMultiChoiceClickListener(){                            public void onClick(DialogInterface dialog, int which, boolean isChecked) {                                Log.d(TAG,"which = "+ which + "isChecked = " + isChecked);                                if(which==0){                                    if(isChecked){                                        Settings.System.putIntForUser(context.getContentResolver(), Settings.System.BOOT_FAST_ENABLE, 1,UserHandle.USER_CURRENT);                                    }else{                                        Settings.System.putIntForUser(context.getContentResolver(), Settings.System.BOOT_FAST_ENABLE, 0,UserHandle.USER_CURRENT);                                    }                                }                            }                        })                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {                        public void onClick(DialogInterface dialog, int which) {if(mPolicy!=null){mPolicy.acquireBAView();}                            beginShutdownSequence(context);                        }                    })                    .setNegativeButton(com.android.internal.R.string.no, null)                    .create();                }else{                            beginShutdownSequence(context);                }            }        } else {            //如果不需要确认就直接关机            beginShutdownSequence(context);        }    }

接着看下beginShutdownSequence得流程。

 private static void beginShutdownSequence(Context context) {        synchronized (sIsStartedGuard) {            if (sIsStarted) {                Log.d(TAG, "Shutdown sequence already running, returning.");                return;            }            sIsStarted = true;        }SystemProperties.set("sys.start_shutdown", "1");SystemProperties.set("sys.fasboot_shutdown", "1");if(SystemProperties.getBoolean("ro.sys.bootfast", false)&&(1==Settings.System.getIntForUser(context.getContentResolver(), Settings.System.BOOT_FAST_ENABLE, 0,UserHandle.USER_CURRENT))){            mBootFastEnable = true;        }else{            mBootFastEnable = false;        }if(mReboot){mBootFastEnable = false;Log.d(TAG,"reboot!");}if(mRebootSafeMode){mBootFastEnable = false;Log.d(TAG,"Go Into Safe Mode real reboot");}if(Zygote.systemInSafeMode){mBootFastEnable = false;Log.d(TAG,"In Safe Mode real reboot");}if(mRebootReason!=null){mBootFastEnable = false;Log.d(TAG,"have reason " + mRebootReason + "real reboot");}if(SystemProperties.getInt("sys.battery_zero",0)==1){mBootFastEnable = false;Log.d(TAG,"Battery to low we really shutdown!");}if(SystemProperties.getInt("sys.temperature_high",0)==1){mBootFastEnable = false;Log.d(TAG,"temperature high we relly shutdown!");}        //显示关机进度得画面。        final ProgressDialog pd = new ProgressDialog(context);     if(mReboot){pd.setTitle(context.getText(com.android.internal.R.string.global_action_reboot));pd.setMessage(context.getText(com.android.internal.R.string.reboot_title));}else{pd.setTitle(context.getText(com.android.internal.R.string.power_off));pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));}        pd.setIndeterminate(true);        pd.setCancelable(false);        pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);        //关机得处理核心流程sInstance = new ShutdownThread();        sInstance.mContext = context;        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);        // make sure we never fall asleep again        //解除休眠模式        sInstance.mCpuWakeLock = null;        try {            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(                    PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");            sInstance.mCpuWakeLock.setReferenceCounted(false);            sInstance.mCpuWakeLock.acquire();        } catch (SecurityException e) {            Log.w(TAG, "No permission to acquire wake lock", e);            sInstance.mCpuWakeLock = null;        }        // also make sure the screen stays on for better user experience        sInstance.mScreenWakeLock = null;        if (sInstance.mPowerManager.isScreenOn()) {            try {                sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(                        PowerManager.FULL_WAKE_LOCK, TAG + "-screen");                sInstance.mScreenWakeLock.setReferenceCounted(false);                sInstance.mScreenWakeLock.acquire();            } catch (SecurityException e) {                Log.w(TAG, "No permission to acquire wake lock", e);                sInstance.mScreenWakeLock = null;            }        }        // start the thread that initiates shutdown        sInstance.mHandler = new Handler() {        @Override        public void handleMessage(Message msg){        switch(msg.what) {        case  CLOSE_PROCESS_DIALOG:        Log.v(TAG,"close process dialog now");        pd.dismiss();        break;        }        }        };        sInstance.start();    }

显示关机画面,然后掉ShutDownThread得润函数。

/**     * Makes sure we handle the shutdown gracefully.     * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.     */    public void run() {        BroadcastReceiver br = new BroadcastReceiver() {            @Override public void onReceive(Context context, Intent intent) {                // We don't allow apps to cancel this, so ignore the result.                actionDone();            }        };        if(!mBootFastEnable){            int shutdownanimation = SystemProperties.getInt("persist.sys.shutdownanimation", 0);            int value = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT);            int rotation = Surface.ROTATION_0;            if (shutdownanimation == 1) {                IWindowManager mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));                if (mWindowManager != null) {                    try{                        rotation = mWindowManager.getRotation();                        mWindowManager.freezeRotation(Surface.ROTATION_0);                        mWindowManager.updateRotation(true, true);                    } catch (RemoteException e) {                        e.printStackTrace();                    }                }                if (rotation != Surface.ROTATION_0) {                    SystemClock.sleep(600);                } else {                    SystemClock.sleep(200);                }                SystemProperties.set("sys.shutdown_animation", "shutdown");                SystemProperties.set("service.bootanim.exit", "0");                SystemProperties.set("ctl.start", "bootanim");            }        /*         * Write a system property in case the system_server reboots before we         * get to the actual hardware restart. If that happens, we'll retry at         * the beginning of the SystemServer startup.         */        {            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);        }        /*         * If we are rebooting into safe mode, write a system property         * indicating so.         */        if (mRebootSafeMode) {            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");        }killRemoveActivity(mContext);killRemoveService(mContext);        Log.i(TAG, "Sending shutdown broadcast...");                // First send the high-level shut down broadcast.        mActionDone = false;            //发送关机广播        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);        mContext.sendOrderedBroadcastAsUser(intent,        UserHandle.ALL, null, br, mHandler, 0, null, null);                final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;        synchronized (mActionDoneSync) {            while (!mActionDone) {                long delay = endTime - SystemClock.elapsedRealtime();                if (delay <= 0) {                    Log.w(TAG, "Shutdown broadcast timed out");                    break;                }                try {                    mActionDoneSync.wait(delay);                } catch (InterruptedException e) {                }            }        }                Log.i(TAG, "Shutting down activity manager...");                final IActivityManager am =            ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));        if (am != null) {            try {                am.shutdown(MAX_BROADCAST_TIME);            } catch (RemoteException e) {            }        }        //Allwinner, if no radio,not need shutdown        if(SystemProperties.get(PROPERTY_EMBEDED_TELEPHONY).equals("true")){        shutdownRadios(MAX_RADIO_WAIT_TIME);        }        // Shutdown MountService to ensure media is in a safe state        IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {            public void onShutDownComplete(int statusCode) throws RemoteException {                Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");                actionDone();            }        };        Log.i(TAG, "Shutting down MountService");        // Set initial variables and time out time.        mActionDone = false;        final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;        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, "Exception during MountService shutdown", e);            }            while (!mActionDone) {                long delay = endShutTime - SystemClock.elapsedRealtime();                if (delay <= 0) {                    Log.w(TAG, "Shutdown wait timed out");                    break;                }                try {                    mActionDoneSync.wait(delay);                } catch (InterruptedException e) {                }            }        }            if (shutdownanimation == 1) {                if (value == 0) {                    Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, rotation);                }                Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, value, UserHandle.USER_CURRENT);            }        rebootOrShutdown(mReboot, mRebootReason);        }        else{//Allwiner, fast boot shut begin        if (SHUTDOWN_VIBRATE_MS > 0) {            // vibrate before shutting down            Vibrator vibrator = new SystemVibrator();            if(vibrator.hasVibrator()){                try {                    vibrator.vibrate(SHUTDOWN_VIBRATE_MS);                } catch (Exception e) {                    // Failure to vibrate shouldn't interrupt shutdown.  Just log it.                    Log.w(TAG, "Failed to vibrate during shutdown.", e);               }           }        }if(mPolicy!=null){            //关屏mPolicy.hideScreen(true);mPolicy.enableKeyguard(true);Log.d(TAG,"enable keyguard true");}IWindowManager mWindowManager;mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));if(mWindowManager != null){try{boolean alreadyfreeze  = Settings.System.getIntForUser(mContext.getContentResolver(),                Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;Log.d(TAG,"alreadyfreeze = " + alreadyfreeze);Log.d(TAG,"rotation = " + mWindowManager.getRotation());Settings.System.putInt(mContext.getContentResolver(), Settings.System.ROTATION_MODE_SET,alreadyfreeze?(0 - mWindowManager.getRotation()):1);                mWindowManager.freezeRotation(Surface.ROTATION_0);                mWindowManager.updateRotation(true, true);                mWindowManager.setEventDispatching(false);            }catch (RemoteException e) {            }}//shutdownRadios(MAX_RADIO_WAIT_TIME);       //设置飞行模式setAirplaneModeState(true); //set airplane mode        SystemClock.sleep(BOOTFAST_WAIT_TIME);        //杀掉activity    killRemoveActivity(mContext);        //杀掉service    killRemoveService(mContext);//MobileDirectController.getInstance().setNetworkEnable(false);sIsStarted = false;try{sInstance.mCpuWakeLock.release();sInstance.mScreenWakeLock.release();}catch(SecurityException e){SystemProperties.set("sys.start_shutdown", "0");}        SystemClock.sleep(BOOTFAST_WAIT_TIME);sInstance.mHandler.sendEmptyMessage(CLOSE_PROCESS_DIALOG);Log.v(TAG,"CLOSE_PROCESS_DIALOG");SystemProperties.set("sys.start_shutdown", "0");sInstance.mPowerManager.goToBootFastSleep(SystemClock.uptimeMillis());}    }

主要流程是关闭一下模块:

ActivityManagerService

PackageManagerService

phone

 Bluetooth Radio

MountService

有的模块可能需要监听手机关机事件,所以在关机时发送关机广播,通知相关模块处理。
而在关机过程中为了不损坏手机性能,记录当前一些状态,需要将一些模块服务进程先关闭,然后才进行关机。在本问题将着重讲解该过程。
最后,调用power进行关机,实际就是在SystemProperties中设置相关数据,让底层进行读取,执行Builtins.c的do_powerctl函数,最终通过bionic的reboot.cpp 调用kernel中kernel_power_off进行关机。
 

接着看下关于关机sd卡得处理逻辑。

  (图片链接https://img-blog.csdn.net/20170119201115531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnVfa2V2aW4wNjA2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)

在关机的时候如果sdcard处于MOUNTED状态下,就需要发送消息H_UNMOUNT_PM_UPDATE将sdcard进行unmount操作。
如果sdcard为emulated模拟内卡,就不需要进行unmount操作,所以模拟内卡比物理内卡的手机关机速度要快很多。
在进行unmount操作时,需要先调用PackageManagerService进行更新一下包状态,删除安装在sd卡上的软件。完成之后回调到MountService中。
之后需要向底层发送命令查询占用sd卡的进程(如数据库,slog所在进程),然后调用AMS将占用sd卡的进程杀死。由于占用sd卡的进程比较顽强,可能杀死后还会起来,所以杀完后再进行查询占用sd卡的进程。如果所查进程数仍然不为NULL,就会再次杀,最多尝试杀四次,如果还杀不死就调用底层vold进行强制杀死。故,如果占用sd卡的进程较多,这部分就会较耗时。
上层的准备工作处理完毕后,就需要向底层发送命令来进行卸载sd卡。
底层在卸载sd卡的过程中,要将sd卡的状态改变发广播到上层,通知MountSevice。
sd卡状态由Mounted变为Unmounting时,为了给上层framework一定的反应时间,底层在发送广播后睡了1s。
之后开始umount操作,如果在上层没有将占用sd卡的进程杀死,就会在底层强制杀进程。系统原生给了10次机会,每次umount失败一次系统都会睡1s之后在尝试umount,如果在最后一次仍然没有成功就强制杀进程。所以重新umount的次数越多耗时就会越长。

所以在关机得时间长,很有可能是跟sd卡得卸载异常有关系,可能是当时得sd卡得状态有异常。
 

更多相关文章

  1. Android翻译:应用程序的生命周期 kill进程
  2. 通过网络使用ADB ( Connect to android with ADB over TCP )
  3. Android开发艺术探索读书笔记(第二章)
  4. Android(安卓)横竖屏切换时候重新进行数据请求问题
  5. Android(安卓)进程管理
  6. android SystemClock设置系统时间需要system权限
  7. android文件系统挂载分析(1)---正常开机挂载,分区信息解读
  8. Android(安卓)IPC 机制,进程间通信
  9. Android(安卓)7.1.2(Android(安卓)N) Activity启动流程分析

随机推荐

  1. 2011.09.26(2)——— android sample之Note
  2. android 常用的数据库表以及操作说明
  3. 4.11笔记 android database打开方式,ios反
  4. android用户界面-组件Widget-画廊视图Gal
  5. Android动态显示隐藏密码输入框的内容
  6. Android(安卓)IPC 通讯机制源码分析
  7. 安卓入门.RelativeLayout相对布局1
  8. android实战
  9. android实现页面下方的Tab效果
  10. android xml 解析 修改