Android CM12.1(android5.1) 关机流程
之前查资料时从网上找的,觉得很正确。就借用一下别人的劳动成果吧~
长按电源键是进入/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java进行处理。
按电源键时,被interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)截获
//特殊处理主要是针对在锁屏或者屏幕不亮的情况的下收到特殊的键值,
//如音量键或者wake键。wake键是指能够点亮屏幕的键时的操作
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;//policyFlags位决定系统按键(如HOME等是否需要由系统处理)
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
final int scanCode = event.getScanCode();
if (SystemProperties.getInt("sys.quickboot.enable", 0) == 1) {// quickboot模式,长按电源键不会关机,进入low-power状态??
//现在手里没有真机,等拿到测试机试试!!!!!
if (keyCode == KeyEvent.KEYCODE_POWER && !interactive) {//!interactive表示屏幕没有唤醒
if(down){
acquireQuickBootWakeLock();//唤醒手机屏幕
mHandler.postDelayed(mQuickBootPowerLongPress, mLongPressPoweronTime);
//mLongPressPoweronTime的时间后,调用mQuickBootPowerLongPress这个线程
} else {
releaseQuickBootWakeLock();//释放手机屏幕
mHandler.removeCallbacks(mQuickBootPowerLongPress);
}
}
// ignore this event
return 0;
}
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
//...............
// Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();//该变量与屏幕唤醒有关系
//...............
// Handle special keys.
switch (keyCode) {
//如果是音量down,音量up,和菜单键
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
//.............
}
case KeyEvent.KEYCODE_HOME:
if (down && !interactive && mHomeWakeScreen) {
isWakeKey = true;//isWakeKey按home键时唤醒屏幕
}
break;
//.............
case KeyEvent.KEYCODE_POWER: {//按电源键,进入这里
if (mTopFullscreenOpaqueWindowState != null &&
(mTopFullscreenOpaqueWindowState.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0
&& mScreenOnFully){
return result;
}
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);//进入这个函数!
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
//.............
if (isWakeKey) {
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
}
return result;
}
通过判断KeyEvent.KEYCODE_POWER,进入interceptPowerKeyDown(event, interactive)这个函数。
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {//如果屏幕是黑的,唤醒屏幕
mPowerKeyWakeLock.acquire();
}
// Cancel multi-press detection timeout.
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);//MSG_POWER_DELAYED_PRESS里面有finishPowerKeyPress()的mPowerKeyPressCounter = 0;
}
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
if (panic && !WindowManagerPolicyControl.isImmersiveFiltersActive()) {
mHandler.post(mRequestTransientNav);//暂时的显示导航栏--返回之类的浮在界面底部的按钮,
//这些按钮一般是消失了,只有在滑动的时候出来
//找个测试机试试
}
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();//可进入触发截屏的函数
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telecomManager.silenceRinger();//电话响铃的时候,按电源键,电话铃声变为静音
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telecomManager.endCall();//在通话中,如果电源键挂断电话的设置是真,
//那么按电源键就挂断电话
}
}
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mScreenshotChordVolumeUpKeyTriggered;//貌似音量up或者音量down都能截屏,测试测试
if (!mPowerKeyHandled) {//如果电源键没有被处理
if (interactive) {//如果屏幕亮着
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {//长按电源进入
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);//获取MSG_POWER_LONG_PRESS这样的message对象
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {//如果屏幕是黑的
wakeUpFromPowerKey(event.getDownTime());//唤醒手机
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//........
case MSG_POWER_LONG_PRESS:
powerLongPress();
break;
//......
}
}
}
进入 powerLongPress()函数
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();//默认是LONG_PRESS_POWER_GLOBAL_ACTIONS
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
showGlobalActionsInternal();//进入这个函数
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(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}
根据 /home/wudao/android/system/frameworks/base/core/res/res/values/config.xml 里面的定义
1
长按电源键默认为 1, 进入 Global actions menu ,即进入 showGlobalActionsInternal(); 显示待操作的选项
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);//发送显示关闭系统的对话框的请求
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
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);
}
}
进入/frameworks/base/policy/src/com/android/internal/policy/impl/GlobalActions.java 文件里的 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 && mUiContext == null) {//如果有dialog显示的话,先把现在的dialog消除
mDialog.dismiss();
mDialog = null;
mDialog = createDialog();
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
mDialog = createDialog();
handleShow();
}
}
进入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 false;
}
};
onAirplaneModeChanged();
mItems = new ArrayList();//显示菜单的列表
String[] actionsArray;
if (mActions == null) {//mActions在GlobalActions初始化的时, mActions = Settings.Secure.getStringForUser(resolver,
//Settings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
actionsArray = mContext.getResources().getStringArray(
com.android.internal.R.array.config_globalActionsList);
} else {
actionsArray = mActions.split("\\|");
}
// Always add the power off option
mItems.add(new PowerAction());//在菜单添加关机选项
ArraySet addedKeys = new ArraySet();
for (int i = 0; i < actionsArray.length; i++) {
String actionKey = actionsArray[i];
if (addedKeys.contains(actionKey)) {
// If we already have added this, don't add it again.
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
continue;//之前添加过了关机
} else if (GLOBAL_ACTION_KEY_REBOOT.equals(actionKey)) {
mItems.add(new RebootAction());//添加重启
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
mItems.add(getScreenshotAction());//添加截屏
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
mItems.add(mAirplaneModeOn);//添加飞行
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
mItems.add(getBugReportAction());//bug report
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
if (mShowSilentToggle) {
mItems.add(mSilentModeAction);//silent mode
}
} else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
List users = ((UserManager) mContext.getSystemService(
Context.USER_SERVICE)).getUsers();
if (users.size() > 1) {
addUsersToMenu(mItems);//用户菜单
}
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
mItems.add(getSettingsAction());
} else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
mItems.add(getLockdownAction());
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
mAdapter = new MyAdapter();
AlertParams params = new AlertParams(getUiContext());
params.mAdapter = mAdapter;
params.mOnClickListener = this;
params.mForceInverseBackground = true;
GlobalActionsDialog dialog = new GlobalActionsDialog(getUiContext(), params);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.getListView().setItemsCanFocus(true);//对话框长按的话
dialog.getListView().setLongClickable(true);
dialog.getListView().setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView> parent, View view, int position,
long id) {
final Action action = mAdapter.getItem(position);
if (action instanceof LongPressAction) {
return ((LongPressAction) action).onLongPress();//进入action的onLongPress()
}
return false;
}
});
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
dialog.setOnDismissListener(this);
return dialog;
}
点击“关机”的时候,进入到PowerAction()这个函数
private final class PowerAction extends SinglePressAction implements LongPressAction {
private PowerAction() {
super(com.android.internal.R.drawable.ic_lock_power_off,
R.string.global_action_power_off);
}
@Override
public boolean onLongPress() {//长按进入安全重启模式
mWindowManagerFuncs.rebootSafeMode(true);
return true;
}
@Override
public boolean showDuringKeyguard() {
return true;
}
@Override
public boolean showBeforeProvisioning() {
return true;
}
@Override
public void onPress() {
final boolean quickbootEnabled = Settings.System.getInt(
mContext.getContentResolver(), "enable_quickboot", 0) == 1;
// go to quickboot mode if enabled
if (quickbootEnabled) {
startQuickBoot();
return;
}
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */);//一般进入这里关机
}
mWindowManagerFuncs.shutdown(false /* confirm */);函数是在/frameworks/base/core/java/android/view/WindowManagerPolicy.java里面一个接口
public interface WindowManagerFuncs {
//.............
/**
* Switch the keyboard layout for the given device.
* Direction should be +1 or -1 to go to the next or previous keyboard layout.
*/
public void switchKeyboardLayout(int deviceId, int direction);
public void shutdown(boolean confirm);
//........}
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
//...............
// Called by window manager policy. Not exposed externally.
@Override
public void shutdown(boolean confirm) {
ShutdownThread.shutdown(mContext, confirm);
}
//............
}
接下来便进入到了frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java中的shutdown函数。兜兜转转这么久,终于来到核心区了。
public static void shutdown(final Context context, boolean confirm) {
final Context uiContext = getUiContext(context);
mReboot = false;
mRebootSafeMode = false;
shutdownInner(uiContext, 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;
}
}
//下面判断关机菜单列表那边传过来的action是什么,如果是reboot,showRebootOption=true
boolean showRebootOption = false;
String[] actionsArray;
String actions = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
if (actions == null) {
actionsArray = context.getResources().getStringArray(
com.android.internal.R.array.config_globalActionsList);
} else {
actionsArray = actions.split("\\|");
}
for (int i = 0; i < actionsArray.length; i++) {
if (actionsArray[i].equals("reboot")) {
showRebootOption = true;
break;
}
}
final int longPressBehavior = context.getResources().getInteger(//在config.xml里面默认是1
com.android.internal.R.integer.config_longPressOnPowerBehavior);
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);//如果是正常关机,则是赋值这个shutdown_confirm,
//就是直接关机,不会再提示是否确认关机了
if (showRebootOption && !mRebootSafeMode) {
resourceId = com.android.internal.R.string.reboot_confirm;//如果是重启,resourceId则为这个值
}
Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
if (confirm) {//关机传进来的时候是false
//..............
} else {
beginShutdownSequence(context);////开始真正的关机步骤
}
}
beginShutdownSequence(context);函数
private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {//异步
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
return;
}
sIsStarted = true;
}
//acquire audio focus to make the other apps to stop playing muisc
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(null,//持续获得audio的focus,停止正在播放的音乐
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (!checkAnimationFileExist()) {////如果关机动画的文件不存在,就显示关机的进程框
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
ProgressDialog pd = new ProgressDialog(context);
if (mReboot) {
pd.setTitle(context.getText(com.android.internal.R.string.reboot_title));
pd.setMessage(context.getText(com.android.internal.R.string.reboot_progress));
} 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);
pd.show();
}
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");//PARTIAL_WAKE_LOCK保持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");//FULL_WAKE_LOCK,手机是完全唤醒模式,更好的用户体验
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() {
};
sInstance.start();//启动关机线程
}
在run()函数里面
/**
* 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();//里面有mActionDoneSync.notifyAll();mActionDoneSync是ShutThread的一个对象,就是唤醒wait的关机线程
}
};
/*
* 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);//把是否reboot写进reason中
}
/*
* If we are rebooting into safe mode, write a system property
* indicating so.
*/
if (mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
}
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);//发送关机广播后,要接受从应用程序那边返回的数据
//br接受到应用程序的反馈之后,唤醒关机线程
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);//wait关机线程,等待应用程序的反馈
} catch (InterruptedException e) {
}
}
}
Log.i(TAG, "Shutting down activity manager...");
//关闭activity的manager
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
Log.i(TAG, "Shutting down package manager...");
//关闭package的manager
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
String shutDownFile = null;
//showShutdownAnimation() is called from here to sync
//music and animation properly
//如果关机动画文件存在,锁住屏幕不旋转,显示关机动画
//根据实际操作判断,cm12.1里面没有关机动画,不进入这个if语句
if(checkAnimationFileExist()) {
lockDevice();
showShutdownAnimation();
if (!isSilentMode()
&& (shutDownFile = getShutdownMusicFilePath()) != null) {
isShutdownMusicPlaying = true;
shutdownMusicHandler.obtainMessage(0, shutDownFile).sendToTarget();
}
}
Log.i(TAG, "wait for shutdown music");
final long endTimeForMusic = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (isShutdownMusicPlaying) {
long delay = endTimeForMusic - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "play shutdown music timeout!");
break;
}
try {
mActionDoneSync.wait(delay);//等待关机音乐播放完毕,再继续执行本关机线程
} catch (InterruptedException e) {
}
}
if (!isShutdownMusicPlaying) {
Log.i(TAG, "play shutdown music complete.");
}
}
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);//函数执行关闭nfc,蓝牙,无线通信设备
// Shutdown MountService to ensure media is in a safe state
//关闭挂载服务,即usb的服务
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
actionDone();//等待mount服务关闭后,继续执行关机线程
}
};
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);//关闭mount
} 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);//让关机线程wait,直到observer观察到mount已关闭,才唤醒关机线程
} catch (InterruptedException e) {
}
}
}
rebootOrShutdown(mContext, mReboot, mRebootReason);//进入更深层的函数
}
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
deviceRebootOrShutdown(reboot, reason);//调用oem-services.jar里面rebootOrShutdown
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);//重启的
Log.e(TAG, "Reboot failed, will attempt shutdown instead");
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {//关机
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);//关机之前会震动一次
} catch (Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try {
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch (InterruptedException unused) {
}
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown();//关机
}
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
*/
public static void lowLevelShutdown() {
SystemProperties.set("sys.powerctl", "shutdown");//设置系统属性为shutdown
}
framework层的关机流程基本走完了。更深入的底层关机的有个参考链接
http://www.2cto.com/kf/201501/367859.html
等有时间了,自己再细细走一遍底层。