Android 4.4关机流程

基于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卡得状态有异常。
 

你可能感兴趣的:(Android)