赞
踩
本文基于android 10源码分析
手机长按power键,弹出关机提示对话框,如下图
一、先来看长按power键执行的流程。
开机后先注册输入监听事件,长按power键时,kernel层会发出一个事件上来,该事件最终被InputDispatcher.handleReceiveCallback监听到
- frameworks\native\services\inputflinger\InputDispatcher.cpp
- int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
- InputDispatcher* d = static_cast<InputDispatcher*>(data);
- {
- ..........
- sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
- if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
- .......
- status_t status;
- for (;;) {
- uint32_t seq;
- bool handled;
- //收到完成分发的信号才跳出循环
- status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
- if (status) {
- break;
- }
- //完成分发循环
- d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
- gotOne = true;
- }
- ........
- }
- .........
- return 0; // remove the callback
- } // release lock

- frameworks\native\services\inputflinger\InputDispatcher.cpp
- void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, uint32_t seq, bool handled) {
- ......
- // 完成一次按键分发,通知其他系统组件并准备开始下一个调度周期
- onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
- }
- frameworks\native\services\inputflinger\InputDispatcher.cpp
- void InputDispatcher::onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
- commandEntry->connection = connection;
- commandEntry->eventTime = currentTime;
- commandEntry->seq = seq;
- commandEntry->handled = handled;
- }
- frameworks\native\services\inputflinger\InputDispatcher.cpp
- void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
- CommandEntry* commandEntry) {
- .........
- //按键事件
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {//触摸滑动事件
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
- } else {
- restartEvent = false;
- }
- // 开始下一次的按键分发
- startDispatchCycleLocked(now(), connection);
- }

- bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
- DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) {
- ..............................
- KeyEvent event;
- //对keyevent的结构体赋值,如按键的keyCode action downtime eventtime等
- initializeKeyEvent(&event, keyEntry);
- event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
-
- mLock.unlock();
- //继续分发事件
-
- mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
- &event, keyEntry->policyFlags, &event);
-
- ...............
-
- }

- android\frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
- bool NativeInputManager::dispatchUnhandledKey(const sp<IBinder>& token,
- const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
- ........
- if (policyFlags & POLICY_FLAG_TRUSTED) {
- ......
- if (keyEventObj) {
- //回调到JAVA层InputManagerService.java
- jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj,
- gServiceClassInfo.dispatchUnhandledKey,
- tokenObj, keyEventObj, policyFlags);
- if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
- fallbackKeyEventObj = nullptr;
- }
- ........
- }
- return result;
- }

事件是从native层的InputDispatcher.cpp一直传到java层,在native层主要做了keyevent的封装,循环等待下一次事件的分发。
二、从native调用到java层后,我们继续看看它的数据流向是怎么调用到关机提示框的
- frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
- //由native层com_android_server_input_InputManagerService.cpp的NativeInputManager::dispatchUnhandledKey回调
- private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
- return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
- }
mWindowManagerCallbacks是在SystemServer.startOtherServices得到InputManagerCallback并设置的,所以dispatchUnhandledKey是在InputManagerCallback.java
- frameworks\base\services\core\java\com\android\server\wm\InputManagerCallback.java
- public KeyEvent dispatchUnhandledKey(
- IBinder focus, KeyEvent event, int policyFlags) {
- WindowState windowState = mService.windowForClientLocked(null, focus, false);
- //mService.mPolicy是PhoneWindowManager的实例
- return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
- }
直接看它的调用栈:
PhoneWindowManager.dispatchUnhandledKey-->PhoneWindowManager.interceptFallback --> PhoneWindowManager.interceptKeyBeforeDispatching -->PhoneWindowManager.interceptPowerKeyDown -->PhoneWindowManager.powerLongPress -->PhoneWindowManager. showGlobalActionsInternal-->GlobalActions.showDialog -->LegacyGlobalActions.showDialog
最后走到LegacyGlobalActions类,该类是关机提示框的实现类,提示框的显示、逻辑处理都是在此实现,对话框显示的不仅仅是关机/重启,还有飞行模式、截图、锁定等,不同的手机开发商定制的功能也不同,对话框的创建逻辑
- frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
- private ActionsDialog 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) {
- ....................
- }
-
- @Override
- public boolean showDuringKeyguard() {
- return true;
- }
-
- @Override
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
- onAirplaneModeChanged();
-
- mItems = new ArrayList<Action>();
- String[] defaultActions = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_globalActionsList);
-
- ArraySet<String> addedKeys = new ArraySet<String>();
- for (int i = 0; i < defaultActions.length; i++) {
- String actionKey = defaultActions[i];
- if (addedKeys.contains(actionKey)) {
- ...................
- } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
- mItems.add(new RestartAction(mContext, mWindowManagerFuncs));//把重启添加到列表
- } else {
- Log.e(TAG, "Invalid global action key " + actionKey);
- }
- // Add here so we don't add more than one.
- addedKeys.add(actionKey);
- }
-
- ...............
- ActionsDialog dialog = new ActionsDialog(mContext, 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();
- }
- return false;
- }
- });
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-
- dialog.setOnDismissListener(this);
-
- return dialog;
- }

对话框Item的点击事件,点击事件后的onPress()是RestartAction里的onPress()
- frameworks\base\services\core\java\com\android\server\policy\LegacyGlobalActions.java
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
- dialog.dismiss();
- }
- mAdapter.getItem(which).onPress();//这里会走到RestartAction.onPress())
- }
在RestartAction.onPress()直接调用了mWindowManagerFuncs.reboot(false),mWindowManagerFuncs是WindowManagerService的实例,直接看它里面的reboot函数,该函数直接调用了ShutdownThread.reboot。
三、ShutdownThread是重启/关机的类,重启/关机的逻辑主要在此类实现。
先看看此类的基本结构,此类是final类,不能被其他类继承,也不能被其他类覆盖,属于线程类,继承Thread。
ShutdownThread.reboot进入到了shutdownInner然后调用ShutdownThread.beginShutdownSequence,在这里主要做了显示关机进度对话框、保持屏幕打开,启动线程
- frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
- private static void beginShutdownSequence(Context context) {
- ........
- //设置关机进度对话框
- sInstance.mProgressDialog = showShutdownDialog(context);
- sInstance.mContext = context;
- sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-
- // 确保不进入休眠
- 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;
- }
-
- //确保屏幕打开
- 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;
- }
- }
- .............
- };
- sInstance.start();//启动线程
- }

启动线程后,进入到run()
- frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
- public void run() {
- ...................
- //重启后是否进入安全模式
- if (mRebootSafeMode) {
- SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
- }
-
- //检测是否有关机动画,禁止屏幕旋转
- if (checkAnimationFileExist()) {
- freeze_orien_shutdownanim();
- }
-
- ............
- // 发送关机广播
- mActionDone = false;
- Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- if (checkAnimationFileExist()) {
- intent.putExtra("PLAY_SHUTDOWN_ANIMATION",1);
- }
- mContext.sendOrderedBroadcastAsUser(intent,
- UserHandle.ALL, null, br, mHandler, 0, null, null);
-
- //检查是否有关机动画
- if (checkAnimationFileExist()) {
- start_shutdownanim();//显示关机动画,----【见小节3.1】
- thaw_orien_shutdownanim();//解除禁止屏幕旋转
- }
- ..................
- if (am != null) {
- try {
- am.shutdown(MAX_BROADCAST_TIME);//关闭activityManager-----【见小节3.2】
- } catch (RemoteException e) {
- }
- }
- ................
- final PackageManagerService pm = (PackageManagerService)
- ServiceManager.getService("package");
- if (pm != null) {
- pm.shutdown();//关闭PackageManager ----------【见小节3.3】
- }
- ............
- shutdownRadios(MAX_RADIO_WAIT_TIME);//关闭射频
- ...........
- if (checkAnimationFileExist()) {
- wait_shutdownanim_end();//等待动画结束 -------------【见小节3.4】
- }
- mPowerManager.goToSleep(SystemClock.uptimeMillis());//关闭屏幕,进入休眠
- rebootOrShutdown(mContext, mReboot, mReason);//重启或关机 ------【见小节3.5】
- }

线程run主要是对关机进度、关机动画、关闭AMS、PMS、射频等,最后等待动画结束,关闭屏幕进入休眠,真正进入重启或关机
3.1 ShutdownThread.start_shutdownanim
- private static void start_shutdownanim() {
- try {
- SystemProperties.set(LOOP_COMPLETED_PROP_NAME, "false");
- SystemProperties.set("service.bootanim.exit", "0");
- SystemProperties.set("ctl.start", "shutdownanim");
- } catch (Exception e){
- Log.e(TAG,"shutdownanim command exe err!");
- }
- }
这里设置了两个属性,一个标记动画是否退出,一个是显示关机动画。属性“ctrl.start”和"ctrl.stop"是用来启动和停止服务,这里表示启动关机动画,然后显示关机动画的画面
3.2 ActivityManagerService.shutdown
- public boolean shutdown(int timeout) {
- //检测权限
- if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SHUTDOWN);
- }
-
- final boolean timedout = mAtmInternal.shuttingDown(mBooted, timeout);//关闭activity ------【见3.2.1】
-
- mAppOpsService.shutdown();//关闭op的服务,其实就是把应用的操作时间、uid等保存到 /data/system/appops.xml
- if (mUsageStatsService != null) {
- mUsageStatsService.prepareShutdown();//关闭使用状态服务,把状态信息写入到/data/system/users/0/app_idle_stats.xml
- }
- mBatteryStatsService.shutdown();//关闭电池状态服务 --------【见3.2.2】
- synchronized (this) {
- mProcessStats.shutdownLocked();//保存当前进程的状态,把进程信息写入到/data/system/procstats目录下
- }
-
- return timedout;
- }

3.2.1 ActivityTaskManagerService.ShuttingDown
- public boolean shuttingDown(boolean booted, int timeout) {
- synchronized (mGlobalLock) {
- mShuttingDown = true;
- mRootActivityContainer.prepareForShutdown();//屏幕进入休眠
- updateEventDispatchingLocked(booted);//关闭触摸、按键等事件的分发
- notifyTaskPersisterLocked(null, true);//更新最近任务 移除最近应用的缩略图、保存最近应用的信息到/data/system_ce/0/recent_tasks目录下
- return mStackSupervisor.shutdownLocked(timeout);//关闭activity栈管理
- }
- }
3.2.2 BatteryStatesService.shutdown
- public void shutdown() {
- Slog.w("BatteryStats", "Writing battery stats before shutdown...");
-
- syncStats("shutdown", BatteryExternalStatsWorker.UPDATE_ALL);
-
- synchronized (mStats) {
- //调用到BatteryStatsImpl.shutdownLocked,保存当前电池状态到/data/system/batterystats.bin,把之前的电池状态信息保存到/data/system/battery-history目录下
- mStats.shutdownLocked();
- }
- // 关闭当前线程池
- mWorker.shutdown();
- }
3.3 PackageManagerService.shutdown
- public void shutdown() {
- mPackageUsage.writeNow(mPackages);//保存应用使用的数据到/data/system/package-usage.list
- mCompilerStats.writeNow();//统计文件预编译的信息并保存到/data/system/package-cstats.list
- mDexManager.writePackageDexUsageNow();//把使用了dex的应用信息保存到/data/system/package-dex-usage.list
- PackageWatchdog.getInstance(mContext).writeNow();
-
- // This is the last chance to write out pending restriction settings
- synchronized (mPackages) {
- if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
- mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- for (int userId : mDirtyUsers) {
- mSettings.writePackageRestrictionsLPr(userId);//把应用的信息保存到/data/system/users/0/package-restrictions.xml
- }
- mDirtyUsers.clear();
- }
- }
- }

3.4 ShutdownThread.wait_shutdownanim_end
- frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
- private static final String LOOP_COMPLETED_PROP_NAME = "sys.anim_loop.completed";
- private static void wait_shutdownanim_end() {
- while(!SystemProperties.get(LOOP_COMPLETED_PROP_NAME, "false").equals("true")) {
- try {
- Thread.sleep(200);
- } catch (Exception e) {
- }
- }
- }
通过循环监听sys.anim_loop.completed的属性值来判断是否退出关机动画
3.5 ShutdownThread.rebootOrShutdown
- public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
- if (reboot) {
- Log.i(TAG, "Rebooting, reason: " + reason);
- PowerManagerService.lowLevelReboot(reason);//进入重启
- Log.e(TAG, "Reboot failed, will attempt shutdown instead");
- reason = null;
- } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {//如果是关机,则开启震动
- 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);
- }
- try {
- Thread.sleep(SHUTDOWN_VIBRATE_MS);
- } catch (InterruptedException unused) {
- }
- }
- // 进入关机
- Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown(reason);
- }

我们来看看进入重启lowLevelReboot函数做了什么
- base/services/core/java/com/android/server/power/PowerManagerService.java
- public static void lowLevelReboot(String reason) {
- if (reason == null) {
- reason = "";
- }
- //根据reason重启后进入哪一种模式
- if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
- sQuiescent = true;
- reason = "";
- } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
- sQuiescent = true;
- reason = reason.substring(0,
- reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
- }
-
- if (reason.equals(PowerManager.REBOOT_RECOVERY)
- || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
- reason = "recovery";
- }
-
- if (sQuiescent) {
- reason = reason + ",quiescent";
- }
-
- SystemProperties.set("sys.powerctl", "reboot," + reason);//设置sys.powerctl属性
- try {
- Thread.sleep(20 * 1000L);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
- }

可以看到我们可以根据参数reason来设置重启后让设备进入哪一种模式,最后把reboot和reason一起保存到属性sys.powerctl上,init进程监听到sys.powerctl被设置了,如果值是reboot则开启开机的流程。
如重启后需要进入recovery模式则只需把reason赋值为recovery,
在关机流程中,调用的是PowerManagerService.lowLevelShutdown函数,这个函数仅设置sys.powerctl的属性值为shutdown和reason。
四、为什么设置了sys.powerctl的属性设备就关机/重启了呢?继续跟随sys.powerctl的属性,看看做了哪些事情
- system/core/init/propery_service.cpp
- uint32_t HandlePropertySet(const std::string& name, const std::string& value,
- const std::string& source_context, const ucred& cr,
- SocketConnection* socket, std::string* error) {
- if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
- return ret;
- }
-
- if (StartsWith(name, "ctl.")) {//以ctl.开头的属性进入另外一个分支
- return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
- }
-
- // sys.powerctl is a special property that is used to make the device reboot. We want to log
- // any process that sets this property to be able to accurately blame the cause of a shutdown.
- if (name == "sys.powerctl") {//关注点
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
- std::string process_cmdline;
- std::string process_log_string;
- if (ReadFileToString(cmdline_path, &process_cmdline)) {//通过pid读取进程名
- // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
- // path.
- process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
- }
- LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
- << process_log_string;
- }
- .........
- return PropertySet(name, value, error);
- }

属性有改变时,就会触发property_changed
- system/core/init/init.cpp
- void property_changed(const std::string& name, const std::string& value) {
-
- if (name == "sys.powerctl") {
-
- shutdown_command = value;//属性值赋给shutdown_command
- do_shutdown = true;
- }
-
- if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
-
- if (waiting_for_prop) {
- if (wait_prop_name == name && wait_prop_value == value) {
- LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
- << "' took " << *waiting_for_prop;
- ResetWaitForProp();
- }
- }
- }

- system/core/init/init.cpp
- int SecondStageMain(int argc, char** argv) {
- ............
- while (true) {
- // By default, sleep until something happens.
- auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
-
- if (do_shutdown && !shutting_down) {
- do_shutdown = false;
- if (HandlePowerctlMessage(shutdown_command)) {//关机/重启消息---【见4.1小节】
- shutting_down = true;
- }
- }
-
- if (!(waiting_for_prop || Service::is_exec_service_running())) {
- am.ExecuteOneCommand();//只需命令,命令的发送是在HandlePowerctlMessage函数里封装的
- }
- if (!(waiting_for_prop || Service::is_exec_service_running())) {
- if (!shutting_down) {
- auto next_process_action_time = HandleProcessActions();
-
- // If there's a process that needs restarting, wake up in time for that.
- if (next_process_action_time) {
- epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
- *next_process_action_time - boot_clock::now());
- if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
- }
- }
-
- // If there's more work to do, wake up again immediately.
- if (am.HasMoreCommands()) epoll_timeout = 0ms;
- }
-
- if (auto result = epoll.Wait(epoll_timeout); !result) {//进入等待,不会消耗CPU,时间到达epoll_timeout后唤醒
- LOG(ERROR) << result.error();
- }
- }
-
- return 0;
- }

SecondStageMain是在开机阶段进行的,通过while进入死循环,epoll.wait进入等待,时间到达后唤醒
4.1小节
- system/core/init/reboot.cpp
- bool HandlePowerctlMessage(const std::string& command) {
- unsigned int cmd = 0;
- std::vector<std::string> cmd_params = Split(command, ",");
- std::string reboot_target = "";
- bool run_fsck = false;
- bool command_invalid = false;
-
- if (cmd_params.size() > 3) {
- command_invalid = true;
- } else if (cmd_params[0] == "shutdown") {
- cmd = ANDROID_RB_POWEROFF;//如果是手动关机,cmd_params.size为1
- if (cmd_params.size() == 2) {
- if (cmd_params[1] == "userrequested") {
- // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
- // Run fsck once the file system is remounted in read-only mode.
- run_fsck = true;
- } else if (cmd_params[1] == "thermal") {
- // Turn off sources of heat immediately.
- TurnOffBacklight();
- // run_fsck is false to avoid delay
- cmd = ANDROID_RB_THERMOFF;
- }
- }
- } else if (cmd_params[0] == "reboot") {
- cmd = ANDROID_RB_RESTART2;
- if (cmd_params.size() >= 2) {
- reboot_target = cmd_params[1];
- // adb reboot fastboot should boot into bootloader for devices not
- // supporting logical partitions.
- if (reboot_target == "fastboot" &&
- !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
- reboot_target = "bootloader";
- }
- // When rebooting to the bootloader notify the bootloader writing
- // also the BCB.
- if (reboot_target == "bootloader") {//重启进入bootloader
- std::string err;
- if (!write_reboot_bootloader(&err)) {
- LOG(ERROR) << "reboot-bootloader: Error writing "
- "bootloader_message: "
- << err;
- }
- } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
- reboot_target == "fastboot") {
- std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
- : reboot_target;
- const std::vector<std::string> options = {
- "--" + arg,
- };
- std::string err;
- if (!write_bootloader_message(options, &err)) {
- LOG(ERROR) << "Failed to set bootloader message: " << err;
- return false;
- }
- reboot_target = "recovery";
- }
-
- // If there is an additional parameter, pass it along
- if ((cmd_params.size() == 3) && cmd_params[2].size()) {
- reboot_target += "," + cmd_params[2];
- }
- }
- } else {
- command_invalid = true;
- }
- if (command_invalid) {
- LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
- return false;
- }
-
- LOG(INFO) << "Clear action queue and start shutdown trigger";
- ActionManager::GetInstance().ClearQueue();
- // Queue shutdown trigger first
- ActionManager::GetInstance().QueueEventTrigger("shutdown");
- // Queue built-in shutdown_done
- auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
- DoReboot(cmd, command, reboot_target, run_fsck);//做重启命令---【见4.2小节】
- return Success();
- };
- ..............
- return true;
- }

4.2小节
- static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) {
- ..................
- // 关闭步骤
- // 1. 关闭出关键的服务之外的所有服务
- if (shutdown_timeout > 0ms) {
- LOG(INFO) << "terminating init services";
-
- // Ask all services to terminate except shutdown critical ones.
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (!s->IsShutdownCritical()) s->Terminate();
- }
-
- int service_count = 0;
- // Only wait up to half of timeout here
- auto termination_wait_timeout = shutdown_timeout / 2;
- while (t.duration() < termination_wait_timeout) {
- ReapAnyOutstandingChildren();
-
- service_count = 0;
- for (const auto& s : ServiceList::GetInstance()) {
- // Count the number of services running except shutdown critical.
- // Exclude the console as it will ignore the SIGTERM signal
- // and not exit.
- // Note: SVC_CONSOLE actually means "requires console" but
- // it is only used by the shell.
- if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
- service_count++;
- }
- }
-
- if (service_count == 0) {
- // All terminable services terminated. We can exit early.
- break;
- }
-
- // Wait a bit before recounting the number or running services.
- std::this_thread::sleep_for(50ms);
- }
- LOG(INFO) << "Terminating running services took " << t
- << " with remaining services:" << service_count;
- }
-
- // minimum safety steps before restarting
- // 2. 关闭出关机之外的所有服务
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (!s->IsShutdownCritical()) s->Stop();
- }
- SubcontextTerminate();
- ReapAnyOutstandingChildren();
-
- // 3. 关闭ROM的所有分区
- Service* voldService = ServiceList::GetInstance().FindService("vold");
- if (voldService != nullptr && voldService->IsRunning()) {
- ShutdownVold();
- voldService->Stop();
- } else {
- LOG(INFO) << "vold not running, skipping vold shutdown";
- }
- // logcat stopped here
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (kill_after_apps.count(s->name())) s->Stop();
- }
- // 4. 卸载所有硬盘分区等
- {
- Timer sync_timer;
- LOG(INFO) << "sync() before umount...";
- sync();
- LOG(INFO) << "sync() before umount took" << sync_timer;
- }
- // 5. 清除缓存,关闭Zram分区
- KillZramBackingDevice();
-
- UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
- // Follow what linux shutdown is doing: one more sync with little bit delay
- {
- Timer sync_timer;
- LOG(INFO) << "sync() after umount...";
- sync();
- LOG(INFO) << "sync() after umount took" << sync_timer;
- }
- if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
- LogShutdownTime(stat, &t);
- // 重启
- RebootSystem(cmd, rebootTarget);//进入到了linux和bootable的关机流程.
- abort();
- }

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