当前位置:   article > 正文

详解Android 关机/重启流程_android 关机流程

android 关机流程

本文基于android 10源码分析

手机长按power键,弹出关机提示对话框,如下图

一、先来看长按power键执行的流程。

开机后先注册输入监听事件,长按power键时,kernel层会发出一个事件上来,该事件最终被InputDispatcher.handleReceiveCallback监听到

  1. frameworks\native\services\inputflinger\InputDispatcher.cpp
  2. int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
  3. InputDispatcher* d = static_cast<InputDispatcher*>(data);
  4. {
  5. ..........
  6. sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
  7. if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
  8. .......
  9. status_t status;
  10. for (;;) {
  11. uint32_t seq;
  12. bool handled;
  13. //收到完成分发的信号才跳出循环
  14. status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
  15. if (status) {
  16. break;
  17. }
  18. //完成分发循环
  19. d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
  20. gotOne = true;
  21. }
  22. ........
  23. }
  24. .........
  25. return 0; // remove the callback
  26. } // release lock
  1. frameworks\native\services\inputflinger\InputDispatcher.cpp
  2. void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
  3. const sp<Connection>& connection, uint32_t seq, bool handled) {
  4. ......
  5. // 完成一次按键分发,通知其他系统组件并准备开始下一个调度周期
  6. onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
  7. }
  1. frameworks\native\services\inputflinger\InputDispatcher.cpp
  2. void InputDispatcher::onDispatchCycleFinishedLocked(
  3. nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
  4. CommandEntry* commandEntry = postCommandLocked(
  5. & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
  6. commandEntry->connection = connection;
  7. commandEntry->eventTime = currentTime;
  8. commandEntry->seq = seq;
  9. commandEntry->handled = handled;
  10. }
  1. frameworks\native\services\inputflinger\InputDispatcher.cpp
  2. void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
  3. CommandEntry* commandEntry) {
  4. .........
  5. //按键事件
  6. if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
  7. KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
  8. restartEvent = afterKeyEventLockedInterruptible(connection,
  9. dispatchEntry, keyEntry, handled);
  10. } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {//触摸滑动事件
  11. MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
  12. restartEvent = afterMotionEventLockedInterruptible(connection,
  13. dispatchEntry, motionEntry, handled);
  14. } else {
  15. restartEvent = false;
  16. }
  17. // 开始下一次的按键分发
  18. startDispatchCycleLocked(now(), connection);
  19. }
  1. bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
  2. DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) {
  3. ..............................
  4. KeyEvent event;
  5. //对keyevent的结构体赋值,如按键的keyCode action downtime eventtime等
  6. initializeKeyEvent(&event, keyEntry);
  7. event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
  8. mLock.unlock();
  9. //继续分发事件
  10. mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
  11. &event, keyEntry->policyFlags, &event);
  12. ...............
  13. }
  1. android\frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
  2. bool NativeInputManager::dispatchUnhandledKey(const sp<IBinder>& token,
  3. const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
  4. ........
  5. if (policyFlags & POLICY_FLAG_TRUSTED) {
  6. ......
  7. if (keyEventObj) {
  8. //回调到JAVA层InputManagerService.java
  9. jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj,
  10. gServiceClassInfo.dispatchUnhandledKey,
  11. tokenObj, keyEventObj, policyFlags);
  12. if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
  13. fallbackKeyEventObj = nullptr;
  14. }
  15. ........
  16. }
  17. return result;
  18. }

事件是从native层的InputDispatcher.cpp一直传到java层,在native层主要做了keyevent的封装,循环等待下一次事件的分发。

二、从native调用到java层后,我们继续看看它的数据流向是怎么调用到关机提示框的

  1. frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
  2. //由native层com_android_server_input_InputManagerService.cpp的NativeInputManager::dispatchUnhandledKey回调
  3. private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
  4. return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
  5. }

mWindowManagerCallbacks是在SystemServer.startOtherServices得到InputManagerCallback并设置的,所以dispatchUnhandledKey是在InputManagerCallback.java

  1. frameworks\base\services\core\java\com\android\server\wm\InputManagerCallback.java
  2. public KeyEvent dispatchUnhandledKey(
  3. IBinder focus, KeyEvent event, int policyFlags) {
  4. WindowState windowState = mService.windowForClientLocked(null, focus, false);
  5. //mService.mPolicy是PhoneWindowManager的实例
  6. return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
  7. }

直接看它的调用栈:

PhoneWindowManager.dispatchUnhandledKey-->PhoneWindowManager.interceptFallback --> PhoneWindowManager.interceptKeyBeforeDispatching -->PhoneWindowManager.interceptPowerKeyDown -->PhoneWindowManager.powerLongPress -->PhoneWindowManager. showGlobalActionsInternal-->GlobalActions.showDialog -->LegacyGlobalActions.showDialog

最后走到LegacyGlobalActions类,该类是关机提示框的实现类,提示框的显示、逻辑处理都是在此实现,对话框显示的不仅仅是关机/重启,还有飞行模式、截图、锁定等,不同的手机开发商定制的功能也不同,对话框的创建逻辑

  1. frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
  2. private ActionsDialog createDialog() {
  3. // Simple toggle style if there's no vibrator, otherwise use a tri-state
  4. if (!mHasVibrator) {
  5. mSilentModeAction = new SilentModeToggleAction();
  6. } else {
  7. mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
  8. }
  9. //飞行模式相关
  10. mAirplaneModeOn = new ToggleAction(
  11. R.drawable.ic_lock_airplane_mode,
  12. R.drawable.ic_lock_airplane_mode_off,
  13. R.string.global_actions_toggle_airplane_mode,
  14. R.string.global_actions_airplane_mode_on_status,
  15. R.string.global_actions_airplane_mode_off_status) {
  16. ....................
  17. }
  18. @Override
  19. public boolean showDuringKeyguard() {
  20. return true;
  21. }
  22. @Override
  23. public boolean showBeforeProvisioning() {
  24. return false;
  25. }
  26. };
  27. onAirplaneModeChanged();
  28. mItems = new ArrayList<Action>();
  29. String[] defaultActions = mContext.getResources().getStringArray(
  30. com.android.internal.R.array.config_globalActionsList);
  31. ArraySet<String> addedKeys = new ArraySet<String>();
  32. for (int i = 0; i < defaultActions.length; i++) {
  33. String actionKey = defaultActions[i];
  34. if (addedKeys.contains(actionKey)) {
  35. ...................
  36. } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
  37. mItems.add(new RestartAction(mContext, mWindowManagerFuncs));//把重启添加到列表
  38. } else {
  39. Log.e(TAG, "Invalid global action key " + actionKey);
  40. }
  41. // Add here so we don't add more than one.
  42. addedKeys.add(actionKey);
  43. }
  44. ...............
  45. ActionsDialog dialog = new ActionsDialog(mContext, params);
  46. dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
  47. dialog.getListView().setItemsCanFocus(true);
  48. dialog.getListView().setLongClickable(true);
  49. dialog.getListView().setOnItemLongClickListener(//对话框长按事件
  50. new AdapterView.OnItemLongClickListener() {
  51. @Override
  52. public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
  53. long id) {
  54. final Action action = mAdapter.getItem(position);
  55. if (action instanceof LongPressAction) {
  56. return ((LongPressAction) action).onLongPress();
  57. }
  58. return false;
  59. }
  60. });
  61. dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  62. dialog.setOnDismissListener(this);
  63. return dialog;
  64. }

对话框Item的点击事件,点击事件后的onPress()是RestartAction里的onPress()

  1. frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
  2. @Override
  3. public void onClick(DialogInterface dialog, int which) {
  4. if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
  5. dialog.dismiss();
  6. }
  7. mAdapter.getItem(which).onPress();//这里会走到RestartAction.onPress())
  8. }

在RestartAction.onPress()直接调用了mWindowManagerFuncs.reboot(false),mWindowManagerFuncs是WindowManagerService的实例,直接看它里面的reboot函数,该函数直接调用了ShutdownThread.reboot。

三、ShutdownThread是重启/关机的类,重启/关机的逻辑主要在此类实现。

先看看此类的基本结构,此类是final类,不能被其他类继承,也不能被其他类覆盖,属于线程类,继承Thread。

ShutdownThread.reboot进入到了shutdownInner然后调用ShutdownThread.beginShutdownSequence,在这里主要做了显示关机进度对话框、保持屏幕打开,启动线程

  1. frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
  2. private static void beginShutdownSequence(Context context) {
  3. ........
  4. //设置关机进度对话框
  5. sInstance.mProgressDialog = showShutdownDialog(context);
  6. sInstance.mContext = context;
  7. sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  8. // 确保不进入休眠
  9. sInstance.mCpuWakeLock = null;
  10. try {
  11. sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
  12. PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
  13. sInstance.mCpuWakeLock.setReferenceCounted(false);
  14. sInstance.mCpuWakeLock.acquire();
  15. } catch (SecurityException e) {
  16. Log.w(TAG, "No permission to acquire wake lock", e);
  17. sInstance.mCpuWakeLock = null;
  18. }
  19. //确保屏幕打开
  20. sInstance.mScreenWakeLock = null;
  21. if (sInstance.mPowerManager.isScreenOn()) {
  22. try {
  23. sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
  24. PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
  25. sInstance.mScreenWakeLock.setReferenceCounted(false);
  26. sInstance.mScreenWakeLock.acquire();
  27. } catch (SecurityException e) {
  28. Log.w(TAG, "No permission to acquire wake lock", e);
  29. sInstance.mScreenWakeLock = null;
  30. }
  31. }
  32. .............
  33. };
  34. sInstance.start();//启动线程
  35. }

启动线程后,进入到run()

  1. frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
  2. public void run() {
  3. ...................
  4. //重启后是否进入安全模式
  5. if (mRebootSafeMode) {
  6. SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
  7. }
  8. //检测是否有关机动画,禁止屏幕旋转
  9. if (checkAnimationFileExist()) {
  10. freeze_orien_shutdownanim();
  11. }
  12. ............
  13. // 发送关机广播
  14. mActionDone = false;
  15. Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
  16. intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
  17. if (checkAnimationFileExist()) {
  18. intent.putExtra("PLAY_SHUTDOWN_ANIMATION",1);
  19. }
  20. mContext.sendOrderedBroadcastAsUser(intent,
  21. UserHandle.ALL, null, br, mHandler, 0, null, null);
  22. //检查是否有关机动画
  23. if (checkAnimationFileExist()) {
  24. start_shutdownanim();//显示关机动画,----【见小节3.1】
  25. thaw_orien_shutdownanim();//解除禁止屏幕旋转
  26. }
  27. ..................
  28. if (am != null) {
  29. try {
  30. am.shutdown(MAX_BROADCAST_TIME);//关闭activityManager-----【见小节3.2】
  31. } catch (RemoteException e) {
  32. }
  33. }
  34. ................
  35. final PackageManagerService pm = (PackageManagerService)
  36. ServiceManager.getService("package");
  37. if (pm != null) {
  38. pm.shutdown();//关闭PackageManager ----------【见小节3.3】
  39. }
  40. ............
  41. shutdownRadios(MAX_RADIO_WAIT_TIME);//关闭射频
  42. ...........
  43. if (checkAnimationFileExist()) {
  44. wait_shutdownanim_end();//等待动画结束 -------------【见小节3.4】
  45. }
  46. mPowerManager.goToSleep(SystemClock.uptimeMillis());//关闭屏幕,进入休眠
  47. rebootOrShutdown(mContext, mReboot, mReason);//重启或关机 ------【见小节3.5】
  48. }

线程run主要是对关机进度、关机动画、关闭AMS、PMS、射频等,最后等待动画结束,关闭屏幕进入休眠,真正进入重启或关机

3.1 ShutdownThread.start_shutdownanim

  1. private static void start_shutdownanim() {
  2. try {
  3. SystemProperties.set(LOOP_COMPLETED_PROP_NAME, "false");
  4. SystemProperties.set("service.bootanim.exit", "0");
  5. SystemProperties.set("ctl.start", "shutdownanim");
  6. } catch (Exception e){
  7. Log.e(TAG,"shutdownanim command exe err!");
  8. }
  9. }

这里设置了两个属性,一个标记动画是否退出,一个是显示关机动画。属性“ctrl.start”和"ctrl.stop"是用来启动和停止服务,这里表示启动关机动画,然后显示关机动画的画面

3.2 ActivityManagerService.shutdown

  1. public boolean shutdown(int timeout) {
  2. //检测权限
  3. if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
  4. != PackageManager.PERMISSION_GRANTED) {
  5. throw new SecurityException("Requires permission "
  6. + android.Manifest.permission.SHUTDOWN);
  7. }
  8. final boolean timedout = mAtmInternal.shuttingDown(mBooted, timeout);//关闭activity ------【见3.2.1】
  9. mAppOpsService.shutdown();//关闭op的服务,其实就是把应用的操作时间、uid等保存到 /data/system/appops.xml
  10. if (mUsageStatsService != null) {
  11. mUsageStatsService.prepareShutdown();//关闭使用状态服务,把状态信息写入到/data/system/users/0/app_idle_stats.xml
  12. }
  13. mBatteryStatsService.shutdown();//关闭电池状态服务 --------【见3.2.2】
  14. synchronized (this) {
  15. mProcessStats.shutdownLocked();//保存当前进程的状态,把进程信息写入到/data/system/procstats目录下
  16. }
  17. return timedout;
  18. }

3.2.1 ActivityTaskManagerService.ShuttingDown

  1. public boolean shuttingDown(boolean booted, int timeout) {
  2. synchronized (mGlobalLock) {
  3. mShuttingDown = true;
  4. mRootActivityContainer.prepareForShutdown();//屏幕进入休眠
  5. updateEventDispatchingLocked(booted);//关闭触摸、按键等事件的分发
  6. notifyTaskPersisterLocked(null, true);//更新最近任务 移除最近应用的缩略图、保存最近应用的信息到/data/system_ce/0/recent_tasks目录下
  7. return mStackSupervisor.shutdownLocked(timeout);//关闭activity栈管理
  8. }
  9. }

3.2.2 BatteryStatesService.shutdown

  1. public void shutdown() {
  2. Slog.w("BatteryStats", "Writing battery stats before shutdown...");
  3. syncStats("shutdown", BatteryExternalStatsWorker.UPDATE_ALL);
  4. synchronized (mStats) {
  5. //调用到BatteryStatsImpl.shutdownLocked,保存当前电池状态到/data/system/batterystats.bin,把之前的电池状态信息保存到/data/system/battery-history目录下
  6. mStats.shutdownLocked();
  7. }
  8. // 关闭当前线程池
  9. mWorker.shutdown();
  10. }

3.3 PackageManagerService.shutdown

  1. public void shutdown() {
  2. mPackageUsage.writeNow(mPackages);//保存应用使用的数据到/data/system/package-usage.list
  3. mCompilerStats.writeNow();//统计文件预编译的信息并保存到/data/system/package-cstats.list
  4. mDexManager.writePackageDexUsageNow();//把使用了dex的应用信息保存到/data/system/package-dex-usage.list
  5. PackageWatchdog.getInstance(mContext).writeNow();
  6. // This is the last chance to write out pending restriction settings
  7. synchronized (mPackages) {
  8. if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
  9. mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
  10. for (int userId : mDirtyUsers) {
  11. mSettings.writePackageRestrictionsLPr(userId);//把应用的信息保存到/data/system/users/0/package-restrictions.xml
  12. }
  13. mDirtyUsers.clear();
  14. }
  15. }
  16. }

3.4 ShutdownThread.wait_shutdownanim_end

  1. frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
  2. private static final String LOOP_COMPLETED_PROP_NAME = "sys.anim_loop.completed";
  3. private static void wait_shutdownanim_end() {
  4. while(!SystemProperties.get(LOOP_COMPLETED_PROP_NAME, "false").equals("true")) {
  5. try {
  6. Thread.sleep(200);
  7. } catch (Exception e) {
  8. }
  9. }
  10. }

通过循环监听sys.anim_loop.completed的属性值来判断是否退出关机动画

3.5 ShutdownThread.rebootOrShutdown

  1. public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
  2. if (reboot) {
  3. Log.i(TAG, "Rebooting, reason: " + reason);
  4. PowerManagerService.lowLevelReboot(reason);//进入重启
  5. Log.e(TAG, "Reboot failed, will attempt shutdown instead");
  6. reason = null;
  7. } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {//如果是关机,则开启震动
  8. Vibrator vibrator = new SystemVibrator(context);
  9. try {
  10. vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
  11. } catch (Exception e) {
  12. // Failure to vibrate shouldn't interrupt shutdown. Just log it.
  13. Log.w(TAG, "Failed to vibrate during shutdown.", e);
  14. }
  15. try {
  16. Thread.sleep(SHUTDOWN_VIBRATE_MS);
  17. } catch (InterruptedException unused) {
  18. }
  19. }
  20. // 进入关机
  21. Log.i(TAG, "Performing low-level shutdown...");
  22. PowerManagerService.lowLevelShutdown(reason);
  23. }

我们来看看进入重启lowLevelReboot函数做了什么

  1. base/services/core/java/com/android/server/power/PowerManagerService.java
  2. public static void lowLevelReboot(String reason) {
  3. if (reason == null) {
  4. reason = "";
  5. }
  6. //根据reason重启后进入哪一种模式
  7. if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
  8. sQuiescent = true;
  9. reason = "";
  10. } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
  11. sQuiescent = true;
  12. reason = reason.substring(0,
  13. reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
  14. }
  15. if (reason.equals(PowerManager.REBOOT_RECOVERY)
  16. || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
  17. reason = "recovery";
  18. }
  19. if (sQuiescent) {
  20. reason = reason + ",quiescent";
  21. }
  22. SystemProperties.set("sys.powerctl", "reboot," + reason);//设置sys.powerctl属性
  23. try {
  24. Thread.sleep(20 * 1000L);
  25. } catch (InterruptedException e) {
  26. Thread.currentThread().interrupt();
  27. }
  28. Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
  29. }

可以看到我们可以根据参数reason来设置重启后让设备进入哪一种模式,最后把reboot和reason一起保存到属性sys.powerctl上,init进程监听到sys.powerctl被设置了,如果值是reboot则开启开机的流程。

如重启后需要进入recovery模式则只需把reason赋值为recovery,

在关机流程中,调用的是PowerManagerService.lowLevelShutdown函数,这个函数仅设置sys.powerctl的属性值为shutdown和reason。

四、为什么设置了sys.powerctl的属性设备就关机/重启了呢?继续跟随sys.powerctl的属性,看看做了哪些事情

  1. system/core/init/propery_service.cpp
  2. uint32_t HandlePropertySet(const std::string& name, const std::string& value,
  3. const std::string& source_context, const ucred& cr,
  4. SocketConnection* socket, std::string* error) {
  5. if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
  6. return ret;
  7. }
  8. if (StartsWith(name, "ctl.")) {//以ctl.开头的属性进入另外一个分支
  9. return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
  10. }
  11. // sys.powerctl is a special property that is used to make the device reboot. We want to log
  12. // any process that sets this property to be able to accurately blame the cause of a shutdown.
  13. if (name == "sys.powerctl") {//关注点
  14. std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
  15. std::string process_cmdline;
  16. std::string process_log_string;
  17. if (ReadFileToString(cmdline_path, &process_cmdline)) {//通过pid读取进程名
  18. // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
  19. // path.
  20. process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
  21. }
  22. LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
  23. << process_log_string;
  24. }
  25. .........
  26. return PropertySet(name, value, error);
  27. }

属性有改变时,就会触发property_changed

  1. system/core/init/init.cpp
  2. void property_changed(const std::string& name, const std::string& value) {
  3. if (name == "sys.powerctl") {
  4. shutdown_command = value;//属性值赋给shutdown_command
  5. do_shutdown = true;
  6. }
  7. if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
  8. if (waiting_for_prop) {
  9. if (wait_prop_name == name && wait_prop_value == value) {
  10. LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
  11. << "' took " << *waiting_for_prop;
  12. ResetWaitForProp();
  13. }
  14. }
  15. }
  1. system/core/init/init.cpp
  2. int SecondStageMain(int argc, char** argv) {
  3. ............
  4. while (true) {
  5. // By default, sleep until something happens.
  6. auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
  7. if (do_shutdown && !shutting_down) {
  8. do_shutdown = false;
  9. if (HandlePowerctlMessage(shutdown_command)) {//关机/重启消息---【见4.1小节】
  10. shutting_down = true;
  11. }
  12. }
  13. if (!(waiting_for_prop || Service::is_exec_service_running())) {
  14. am.ExecuteOneCommand();//只需命令,命令的发送是在HandlePowerctlMessage函数里封装的
  15. }
  16. if (!(waiting_for_prop || Service::is_exec_service_running())) {
  17. if (!shutting_down) {
  18. auto next_process_action_time = HandleProcessActions();
  19. // If there's a process that needs restarting, wake up in time for that.
  20. if (next_process_action_time) {
  21. epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
  22. *next_process_action_time - boot_clock::now());
  23. if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
  24. }
  25. }
  26. // If there's more work to do, wake up again immediately.
  27. if (am.HasMoreCommands()) epoll_timeout = 0ms;
  28. }
  29. if (auto result = epoll.Wait(epoll_timeout); !result) {//进入等待,不会消耗CPU,时间到达epoll_timeout后唤醒
  30. LOG(ERROR) << result.error();
  31. }
  32. }
  33. return 0;
  34. }

SecondStageMain是在开机阶段进行的,通过while进入死循环,epoll.wait进入等待,时间到达后唤醒

4.1小节

  1. system/core/init/reboot.cpp
  2. bool HandlePowerctlMessage(const std::string& command) {
  3. unsigned int cmd = 0;
  4. std::vector<std::string> cmd_params = Split(command, ",");
  5. std::string reboot_target = "";
  6. bool run_fsck = false;
  7. bool command_invalid = false;
  8. if (cmd_params.size() > 3) {
  9. command_invalid = true;
  10. } else if (cmd_params[0] == "shutdown") {
  11. cmd = ANDROID_RB_POWEROFF;//如果是手动关机,cmd_params.size为1
  12. if (cmd_params.size() == 2) {
  13. if (cmd_params[1] == "userrequested") {
  14. // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
  15. // Run fsck once the file system is remounted in read-only mode.
  16. run_fsck = true;
  17. } else if (cmd_params[1] == "thermal") {
  18. // Turn off sources of heat immediately.
  19. TurnOffBacklight();
  20. // run_fsck is false to avoid delay
  21. cmd = ANDROID_RB_THERMOFF;
  22. }
  23. }
  24. } else if (cmd_params[0] == "reboot") {
  25. cmd = ANDROID_RB_RESTART2;
  26. if (cmd_params.size() >= 2) {
  27. reboot_target = cmd_params[1];
  28. // adb reboot fastboot should boot into bootloader for devices not
  29. // supporting logical partitions.
  30. if (reboot_target == "fastboot" &&
  31. !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
  32. reboot_target = "bootloader";
  33. }
  34. // When rebooting to the bootloader notify the bootloader writing
  35. // also the BCB.
  36. if (reboot_target == "bootloader") {//重启进入bootloader
  37. std::string err;
  38. if (!write_reboot_bootloader(&err)) {
  39. LOG(ERROR) << "reboot-bootloader: Error writing "
  40. "bootloader_message: "
  41. << err;
  42. }
  43. } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
  44. reboot_target == "fastboot") {
  45. std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
  46. : reboot_target;
  47. const std::vector<std::string> options = {
  48. "--" + arg,
  49. };
  50. std::string err;
  51. if (!write_bootloader_message(options, &err)) {
  52. LOG(ERROR) << "Failed to set bootloader message: " << err;
  53. return false;
  54. }
  55. reboot_target = "recovery";
  56. }
  57. // If there is an additional parameter, pass it along
  58. if ((cmd_params.size() == 3) && cmd_params[2].size()) {
  59. reboot_target += "," + cmd_params[2];
  60. }
  61. }
  62. } else {
  63. command_invalid = true;
  64. }
  65. if (command_invalid) {
  66. LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
  67. return false;
  68. }
  69. LOG(INFO) << "Clear action queue and start shutdown trigger";
  70. ActionManager::GetInstance().ClearQueue();
  71. // Queue shutdown trigger first
  72. ActionManager::GetInstance().QueueEventTrigger("shutdown");
  73. // Queue built-in shutdown_done
  74. auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
  75. DoReboot(cmd, command, reboot_target, run_fsck);//做重启命令---【见4.2小节】
  76. return Success();
  77. };
  78. ..............
  79. return true;
  80. }

4.2小节

  1. static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
  2. bool runFsck) {
  3. ..................
  4. // 关闭步骤
  5. // 1. 关闭出关键的服务之外的所有服务
  6. if (shutdown_timeout > 0ms) {
  7. LOG(INFO) << "terminating init services";
  8. // Ask all services to terminate except shutdown critical ones.
  9. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  10. if (!s->IsShutdownCritical()) s->Terminate();
  11. }
  12. int service_count = 0;
  13. // Only wait up to half of timeout here
  14. auto termination_wait_timeout = shutdown_timeout / 2;
  15. while (t.duration() < termination_wait_timeout) {
  16. ReapAnyOutstandingChildren();
  17. service_count = 0;
  18. for (const auto& s : ServiceList::GetInstance()) {
  19. // Count the number of services running except shutdown critical.
  20. // Exclude the console as it will ignore the SIGTERM signal
  21. // and not exit.
  22. // Note: SVC_CONSOLE actually means "requires console" but
  23. // it is only used by the shell.
  24. if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
  25. service_count++;
  26. }
  27. }
  28. if (service_count == 0) {
  29. // All terminable services terminated. We can exit early.
  30. break;
  31. }
  32. // Wait a bit before recounting the number or running services.
  33. std::this_thread::sleep_for(50ms);
  34. }
  35. LOG(INFO) << "Terminating running services took " << t
  36. << " with remaining services:" << service_count;
  37. }
  38. // minimum safety steps before restarting
  39. // 2. 关闭出关机之外的所有服务
  40. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  41. if (!s->IsShutdownCritical()) s->Stop();
  42. }
  43. SubcontextTerminate();
  44. ReapAnyOutstandingChildren();
  45. // 3. 关闭ROM的所有分区
  46. Service* voldService = ServiceList::GetInstance().FindService("vold");
  47. if (voldService != nullptr && voldService->IsRunning()) {
  48. ShutdownVold();
  49. voldService->Stop();
  50. } else {
  51. LOG(INFO) << "vold not running, skipping vold shutdown";
  52. }
  53. // logcat stopped here
  54. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  55. if (kill_after_apps.count(s->name())) s->Stop();
  56. }
  57. // 4. 卸载所有硬盘分区等
  58. {
  59. Timer sync_timer;
  60. LOG(INFO) << "sync() before umount...";
  61. sync();
  62. LOG(INFO) << "sync() before umount took" << sync_timer;
  63. }
  64. // 5. 清除缓存,关闭Zram分区
  65. KillZramBackingDevice();
  66. UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
  67. // Follow what linux shutdown is doing: one more sync with little bit delay
  68. {
  69. Timer sync_timer;
  70. LOG(INFO) << "sync() after umount...";
  71. sync();
  72. LOG(INFO) << "sync() after umount took" << sync_timer;
  73. }
  74. if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
  75. LogShutdownTime(stat, &t);
  76. // 重启
  77. RebootSystem(cmd, rebootTarget);//进入到了linux和bootable的关机流程.
  78. abort();
  79. }

五、总结:

android的重启/关机流程从上到下,首先是在kernal层上报事件,frawework的native层InputRead读取到事件后分发给InputDispatcher,InputDispatcher把事件继续传递给java层,java层先做关机对话框显示,用户选择重启/关机后则进入到ShutdownThread类,重启/关机的逻辑是在该线程类里实现的,主要做了显示关机进度、关机动画、关闭屏幕、保存应用状态、保存电池信息等,然后直接通过sys.powerctl把关机/重启/重启后的进入的模式的值写入到属性值里 。在系统开机时通过死循环来来监听sys.powerctl的变化,并引入epoll.wait来挂起,等待时间到达后再唤醒,最后关闭所有服务、清除缓存、卸载分区等五个步骤后,进入linux和bootable的关机流程。可以看到,设置sys.powerctl的属性后是关机的关键,可以用这个属性避开权限的限制等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/945204
推荐阅读
相关标签
  

闽ICP备14008679号