详解Android 关机/重启流程

本文基于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的属性后是关机的关键,可以用这个属性避开权限的限制等。

相关推荐

  1. Android SystemUI关机的UI

    2023-12-13 16:56:01       17 阅读
  2. CentOS 7关机命令详解

    2023-12-13 16:56:01       16 阅读
  3. androidapp

    2023-12-13 16:56:01       42 阅读
  4. android

    2023-12-13 16:56:01       34 阅读
  5. Linux-----4、关机|

    2023-12-13 16:56:01       49 阅读
  6. Linux之关机

    2023-12-13 16:56:01       6 阅读
  7. C#实现windows系统关机

    2023-12-13 16:56:01       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-13 16:56:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-13 16:56:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-13 16:56:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-13 16:56:01       20 阅读

热门阅读

  1. Spring框架中的8种设计模式

    2023-12-13 16:56:01       37 阅读
  2. 每日一练 | 华为认证真题练习Day29

    2023-12-13 16:56:01       41 阅读
  3. 选择排序

    2023-12-13 16:56:01       39 阅读
  4. 【Android】通知(未完待续)

    2023-12-13 16:56:01       43 阅读
  5. PHP中什么是命名空间(Namespace)?

    2023-12-13 16:56:01       43 阅读
  6. 多个变量存储同一个地址

    2023-12-13 16:56:01       39 阅读
  7. 只需六个简单步骤即可开发自定义应用程序

    2023-12-13 16:56:01       28 阅读
  8. ADC芯片用途在哪些行业?

    2023-12-13 16:56:01       31 阅读
  9. LeeCode刷题

    2023-12-13 16:56:01       38 阅读