Android 关机流程解析

  
第一章 引言   
第二章 关机流程   
2.1    PhonewindowManager   
2.2    PhoneWindowManager.interceptKeyBeforeQueueing   
2.3    PhoneWindowManager.interceptPowerKeyDown   
2.4    PhoneWindowManager.powerLongPress()   
2.5    PowerAction.onPress()   
2.6    WindowManagerService.shutdown   
2.7    ShutdownThread.shutdown()   
2.8    ShutdownThread.shutdownInner()   
2.9    ShutdownThread.beginShutdownSequence()   
2.10    ShutdowmThread.run()   
2.11    ShutdownThread.rebootOrShutdown()   


 
第一章 引言
在开始分析关机流程之前,我们先总结几个关机的关键字,以便我们加深我们对关机流程的理解,关键字如下:
InputReader,ShutdownThread,LIGHTS
Line 5981: 05-28 15:24:36.220   838   996 D InputReader: processEventsLocked: type=3 Count=3 code=57 value=-1 deviceId=6 //通常我们以最后一个InputReader输出作为关机的起始时间;
Line 5992: 05-28 15:24:36.248   838   838 D ShutdownThread: Attempting to use SysUI shutdown UI //我们可以通过ShutdownThread的log打印确定这段时间内是否有异常;
Line 5993: 05-28 15:24:36.248   838   838 D ShutdownThread: SysUI handling shutdown UI
Line 6000: 05-28 15:24:36.256   838  5800 I ShutdownThread: Sending shutdown broadcast...
Line 6126: 05-28 15:24:36.605   838  5800 I ShutdownThread: Shutting down activity manager...
Line 7120: 05-28 15:24:38.212   838  5800 I ShutdownThread: Shutting down package manager...
Line 7138: 05-28 15:24:38.249   838  5866 I ShutdownThread: Waiting for Radio...
Line 7139: 05-28 15:24:38.249   838  5866 I ShutdownThread: Radio shutdown complete.
Line 7361: 05-28 15:24:38.759   838  5800 I ShutdownThread: Performing low-level shutdown...
Line 7458: 05-28 15:24:39.027   434   434 D LIGHTS  : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=0 //最后一句lights的打印此时屏幕灭屏,我们通常观察的关机结束以此为准; 
第二章 关机流程
2.1    PhonewindowManager
Android 系统的关机流程是从用户按 power 键开始的,所有的按键处理都是通过 PhoneWindowManager.interceptKeyBeforeQueueing() 方法进行处理。
2.2    PhoneWindowManager.interceptKeyBeforeQueueing
257  public class PhoneWindowManager extends AbsPhoneWindowManager implements WindowManagerPolicy {
3817      public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
…….
// Handle special keys.
3909          switch (keyCode) {
......
case KeyEvent.KEYCODE_POWER: {
4029                  EventLogTags.writeInterceptPower(
4030                          KeyEvent.actionToString(event.getAction()),
4031                          mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
4032                  // Any activity on the power button stops the accessibility shortcut
4033                  cancelPendingAccessibilityShortcutAction();
4034                  result &= ~ACTION_PASS_TO_USER;
4035                  isWakeKey = false; // wake-up will be handled separately
4036                  if (down) {
4037                      /*SPRD : add power debug log start*/
4038                      Slog.d(TAG, "Receive Input KeyEvent of Powerkey down");
4039                      /*SPRD : add power debug log end*/
4040                      interceptPowerKeyDown(event, interactive);
4041                  } else {
4042                      /*SPRD : add power debug log start*/
4043                      Slog.d(TAG, "Receive Input KeyEvent of Powerkey up");
4044                      /*SPRD : add power debug log end*/
4045                      interceptPowerKeyUp(event, interactive, canceled);
4046                  }
4047                  break;
4048              }

2.3    PhoneWindowManager.interceptPowerKeyDown
946      private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
......
// Latch power key state to detect screenshot chord.
960          if (interactive && !mScreenshotChordPowerKeyTriggered
961                  && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
962              mScreenshotChordPowerKeyTriggered = true;
963              mScreenshotChordPowerKeyTime = event.getDownTime();
964              interceptScreenshotChord();
965              interceptRingerToggleChord();
966          }
967  
968          // Stop ringing or end call if configured to do so when power is pressed.
969          TelecomManager telecomManager = getTelecommService();
970          boolean hungUp = false;
971          if (telecomManager != null) {
972              if (telecomManager.isRinging()) {
973                  // Pressing Power while there's a ringing incoming
974                  // call should silence the ringer.
975                  telecomManager.silenceRinger();
976              } else if ((mIncallPowerBehavior
977                      & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
978                      && telecomManager.isInCall() && interactive) {
979                  // Otherwise, if "Power button ends call" is enabled,
980                  // the Power button will hang up any current active call.
981                  hungUp = telecomManager.endCall();
982              }
983          }
……
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
1004                  || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
1005          if (!mPowerKeyHandled) {
1006              if (interactive) {
1007                  // When interactive, we're already awake.
1008                  // Wait for a long press or for the button to be released to decide what to do.
1009                  if (hasLongPressOnPowerBehavior()) {
1010                      if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
1011                          powerLongPress();//长按power键,核心
1012                      } else {
……
} else {
1026                  wakeUpFromPowerKey(event.getDownTime());
1027  
1028                  if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
1029                      if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
1030                          powerLongPress();//长按power键,核心
1031                      } else {
……
  mBeganFromNonInteractive = true;
1045                  } else {
……

1052                      }
1053                  }
1054              }
1055          }
1056      }

2.4    PhoneWindowManager.powerLongPress()
3    private void powerLongPress() {
4    1267          final int behavior = getResolvedLongPressOnPowerBehavior();
5    1268          switch (behavior) {
6    1269              case LONG_PRESS_POWER_NOTHING:
7    1270                  break;
8    1271              case LONG_PRESS_POWER_GLOBAL_ACTIONS://原生会走这个case
9    1272                  mPowerKeyHandled = true;
10    1273                  performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
11    1274                          "Power - Long Press - Global Actions");
12    1275                  showGlobalActionsInternal();//调用showlobalactioninternal
13    1276                  break;
powerLongPress() 有两个核心方法,getResolvedLongPressOnPowerBehavior() 和 showGlobalActionsInternal(),在此不再做分解分析。
2.5    PowerAction.onPress()
25  public final class PowerAction extends SinglePressAction implements LongPressAction {
@Override
57      public void onPress() {
58          // shutdown by making sure radio and power are handled accordingly.
59          mWindowManagerFuncs.shutdown(false /* confirm */);
60      }
61  }
2.6    WindowManagerService.shutdown
public class WindowManagerService extends AbsWindowManagerService
290          implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
……
// Called by window manager policy.  Not exposed externally.
  public void shutdown(boolean confirm) {
3174          // Pass in the UI context, since ShutdownThread requires it (to show UI).
//调用shutdownThread.shutdown()方法
3175          ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),
3176                  PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
3177      }
2.7    ShutdownThread.shutdown()
就像在第一章引言所述,整体的关机流程是通过shutdownThread线程实现。
62  public final class ShutdownThread extends Thread {
  public static void shutdown(final Context context, String reason, boolean confirm) {
153          mReboot = false;
154          mRebootSafeMode = false;
155          mReason = reason;
156          shutdownInner(context, confirm);//内部调用shytdownInner()方法
157      }


2.8    ShutdownThread.shutdownInner()
private static void shutdownInner(final Context context, boolean confirm) {
183          // ShutdownThread is called from many places, so best to verify here that the context passed
184          // in is themed.
185          context.assertRuntimeOverlayThemable();
186  
187          // ensure that only one thread is trying to power down.
188          // any additional calls are just returned
189          synchronized (sIsStartedGuard) {
190              if (sIsStarted) {
191                  Log.d(TAG, "Request to shutdown already running, returning.");
192                  return;
193              }
194          }
195  //获取用户长按power键的处理方式
196          final int longPressBehavior = context.getResources().getInteger(
197                          com.android.internal.R.integer.config_longPressOnPowerBehavior);
198          final int resourceId = mRebootSafeMode
199                  ? com.android.internal.R.string.reboot_safemode_confirm
200                  /*UNISOC bug 908624,add confirm dialog.*/
201                  : (mReboot
202                  ? com.android.internal.R.string.reboot_device_confirm
203                  /*UNISOC bug 908624,add confirm dialog.*/
204                  : (longPressBehavior == 2
205                          ? com.android.internal.R.string.shutdown_confirm_question
206                          : com.android.internal.R.string.shutdown_confirm));
207  
208          Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
……
if (confirm) {//弹出关机,重启对话框,用户选择
215              final CloseDialogReceiver closer = new CloseDialogReceiver(context);//注册关机广播
216              if (sConfirmDialog != null) {
217                  sConfirmDialog.dismiss();
218              }
219  
220              //bug:1162804 add dark theme.
221              if (sInstance.mUiModeManager == null) {
222                  sInstance.mUiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE);
223              }
224              if (sInstance.mUiModeManager != null && sInstance.mPowerManager != null &&(sInstance.mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES
225                      || sInstance.mPowerManager.isPowerSaveMode())) {
226                  sInstance.mThemeResId = AlertDialog.THEME_DEVICE_DEFAULT_DARK;
227              } else {
228                  sInstance.mThemeResId = AlertDialog.THEME_DEVICE_DEFAULT_LIGHT;
229              }
230  //创建关机Dialog
231              sConfirmDialog = new AlertDialog.Builder(context, sInstance.mThemeResId)
232                      .setTitle(mRebootSafeMode
233                              ? com.android.internal.R.string.reboot_safemode_title
234                              /*UNISOC bug 908624*/
235                              :(mReboot
236                              ? com.android.internal.R.string.reboot_device_title
237                              /*UNISOC bug 908624*/
238                              : com.android.internal.R.string.power_off))
239                      .setMessage(resourceId)
240                      .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
241                          public void onClick(DialogInterface dialog, int which) {
242                              beginShutdownSequence(context);//执行shutdownsequence方法,开始关机的流程
243                          }
244                      })
245                      .setNegativeButton(com.android.internal.R.string.no, null)
246                      .create();
247              closer.dialog = sConfirmDialog;
248              sConfirmDialog.setOnDismissListener(closer);
249              sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
250              sConfirmDialog.show();
251          } else {
252              beginShutdownSequence(context);
253          }
254      }
2.9    ShutdownThread.beginShutdownSequence()
我们一般可以在这个方法里添加关机动画,在这里加入的sprd的关机动画
private static void beginShutdownSequence(Context context) {
420          synchronized (sIsStartedGuard) {
421              if (sIsStarted) {
422                  Log.d(TAG, "Shutdown sequence already running, returning.");
423                  return;
424              }
425              sIsStarted = true;
426          }
427  
428          // SPRD:add for shutdownanim
429          if (shutdownAnim.hasShutdownAnimation() &&
430                  !(mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE))) {
431              shutdownAnim.playShutdownAnimation();
432          } else {
433              sInstance.mProgressDialog = showShutdownDialog(context);
434          }
435          sInstance.mContext = context;
436  
437          // make sure we never fall asleep again
438          sInstance.mCpuWakeLock = null;
439          try {
440              sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
441                      PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
442              sInstance.mCpuWakeLock.setReferenceCounted(false);
443              sInstance.mCpuWakeLock.acquire();
444          } catch (SecurityException e) {
445              Log.w(TAG, "No permission to acquire wake lock", e);
446              sInstance.mCpuWakeLock = null;
447          }
……
} else {
//启动关机线程,执行Run()方法
475              sInstance.mHandler = new Handler() {
476              };
477              sInstance.start();
478          }
479      }
480     

2.10 ShutdowmThread.run()
492      public void run() {
……
{
511              String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
512              SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
//保存关机的原因
513          }
514  
515          /*
516           * If we are rebooting into safe mode, write a system property
517           * indicating so.
518           */
519          if (mRebootSafeMode) {
520              SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
521          }
522  
523          metricStarted(METRIC_SEND_BROADCAST);
524          shutdownTimingLog.traceBegin("SendShutdownBroadcast");
525          Log.i(TAG, "Sending shutdown broadcast...");
526  
527          // First send the high-level shut down broadcast.
528          mActionDone = false;
529          Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
530          intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
//发送关机广播
531          mContext.sendOrderedBroadcastAsUser(intent,
532                  UserHandle.ALL, null, br, mHandler, 0, null, null);
533  
534          final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
535          synchronized (mActionDoneSync) {
536              while (!mActionDone) {
537                  long delay = endTime - SystemClock.elapsedRealtime();
538                  if (delay <= 0) {
539                      Log.w(TAG, "Shutdown broadcast timed out");
540                      break;
541                  } else if (mRebootHasProgressBar) {
542                      int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
543                              BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
544                      sInstance.setRebootProgress(status, null);
545                  }
546                  try {
547                      mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
548                  } catch (InterruptedException e) {
549                  }
550              }
551          }
552          if (mRebootHasProgressBar) {
553              sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
554          }
555          shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
//sendshutsownbroadcast 关机广播耗时
556          metricEnded(METRIC_SEND_BROADCAST);
557  
558          Log.i(TAG, "Shutting down activity manager...");
559          shutdownTimingLog.traceBegin("ShutdownActivityManager");
560          metricStarted(METRIC_AM);
561  
562          final IActivityManager am =
563                  IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
564          if (am != null) {
565              try {
566                  am.shutdown(MAX_BROADCAST_TIME);//关闭activitymanagerservice服务
567              } catch (RemoteException e) {
568              }
569          }
570          if (mRebootHasProgressBar) {
571              sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
572          }
573          shutdownTimingLog.traceEnd();// ShutdownActivityManager
574          metricEnded(METRIC_AM);
575  
576          Log.i(TAG, "Shutting down package manager...");
577          shutdownTimingLog.traceBegin("ShutdownPackageManager");
578          metricStarted(METRIC_PM);
579  
580          final PackageManagerService pm = (PackageManagerService)
581              ServiceManager.getService("package");
582          if (pm != null) {
583              pm.shutdown();//关闭packageManagerService服务
584          }
585          if (mRebootHasProgressBar) {
586              sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
587          }
588          shutdownTimingLog.traceEnd(); // ShutdownPackageManager
589          metricEnded(METRIC_PM);
590  
591          // Shutdown radios.
592          shutdownTimingLog.traceBegin("ShutdownRadios");
593          metricStarted(METRIC_RADIOS);
594          shutdownRadios(MAX_RADIO_WAIT_TIME);
595          if (mRebootHasProgressBar) {
596              sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
597          }
598          shutdownTimingLog.traceEnd(); // ShutdownRadios
599          metricEnded(METRIC_RADIOS);
600  
601          if (mRebootHasProgressBar) {
602              sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
603  
604              // If it's to reboot to install an update and uncrypt hasn't been
605              // done yet, trigger it now.
606              uncrypt();
607          }
608  
609          shutdownTimingLog.traceEnd(); // SystemServerShutdown
610          metricEnded(METRIC_SYSTEM_SERVER);
611          saveMetrics(mReboot, mReason);
612          // SPRD:add for shutdownanim
613          shutdownAnim.waitForBootanim();
614          // Remaining work will be done by init, including vold shutdown
615          rebootOrShutdown(mContext, mReboot, mReason);//执行rebootOrShutdown方法()
616         }

2.11 ShutdownThread.rebootOrShutdown() 
当前方法决定是关机还是重启
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
739          if (reboot) {//判断是否重启
740              Log.i(TAG, "Rebooting, reason: " + reason);
741              PowerManagerService.lowLevelReboot(reason);
742              Log.e(TAG, "Reboot failed, will attempt shutdown instead");
743              reason = null;
744          } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
745              // vibrate before shutting down
746              Vibrator vibrator = new SystemVibrator(context);
747              try {
//关机之前震动
748                  vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
749              } catch (Exception e) {
750                  // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
751                  Log.w(TAG, "Failed to vibrate during shutdown.", e);
752              }
753  
754              // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
755              try {
756                  Thread.sleep(SHUTDOWN_VIBRATE_MS);
757              } catch (InterruptedException unused) {
758              }
759          }
760          // Shutdown power
761          Log.i(TAG, "Performing low-level shutdown...");
//调用lowLevelSgutdwon方法,shutdown power
762          PowerManagerService.lowLevelShutdown(reason);
763      }

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值