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