### 关机流程
#### 背景
常见的关机方式有常按电源键,下拉菜单栏点关机或者重启,或者adb命令关机,本质这几个最终都会调用ShutdownThread.reboot或者shutdown方法来关机或者重启。
#### 具体流程
##### 常按电源关机流程
常按电源后会产生按键事件,InputReaderThread从EventHub读到此事件后会交给InputDispather.cpp再继续往上报
`frameworks/native/services/inputflinger/InputDispatcher.cpp`
```c++
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
…
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
…
}
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy),
//省略
```
这个mPolicy指的就是`com_android_server_input_InputManagerService.cpp`的NativeInputManager
`frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp`
```c++
class NativeInputManager :
public virtual InputDispatcherPolicyInterface{
//省略
}
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
//...
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
//...
}
int register_android_server_InputManager(JNIEnv* env) {
//...
jclass clazz;
FIND_CLASS(clazz, "com/android/server/input/InputManagerService");
gServiceClassInfo.clazz = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
//...
}
```
可以看到调用了gServiceClassInfo.interceptKeyBeforeQueueing,其中gServiceClassInfo即是java层的InputManagerService,所以这里会调用到InputManagerService.interceptKeyBeforeQueueing,相当于从JNI层调用到java层。这里不止点电源键是这样的流程,所有的key事件,比如点home,back,或者手动触发的keycode事件,都会走这个流程。
`InputManagerService.java`
```java
// Native callback.
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
```
`InputManagerCallback.java`
```java
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
```
`PhoneWindowManager.java`
```java
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
//...
case KeyEvent.KEYCODE_POWER: {
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
//...
}
```
按下电源后会有几种场景,比如熄屏,弹出是否关机或重启,直接关机等。所以interceptPowerKeyDown会去做这些逻辑。
```java
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
//...
if (hasLongPressOnPowerBehavior()) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
powerLongPress();
} else {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
if (hasVeryLongPressOnPowerBehavior()) {
Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
longMsg.setAsynchronous(true);
mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
}
}
}
//...
}
private class PolicyHandler extends Handler {
//...
case MSG_POWER_LONG_PRESS:
powerLongPress();
break;
//...
}
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Global Actions");
showGlobalActionsInternal();
break;
//...
}
void showGlobalActionsInternal() {
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
// since it took two seconds of long press to bring this up,
// poke the wake lock so they have some time to see the dialog.
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
```
发了个MSG_POWER_LONG_PRESS事件到hander处理,之后powerLongPress()->showGlobalActionsInternal()->mGlobalActions.showDialog()。
`LegacyGlobalActions`
```java
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
handleShow();
}
}
private void handleShow() {
awakenIfNecessary();
mDialog = createDialog();
prepareDialog();
// If we only have 1 item and it's a simple press action, just do this action.
if (mAdapter.getCount() == 1
&& mAdapter.getItem(0) instanceof SinglePressAction
&& !(mAdapter.getItem(0) instanceof LongPressAction)) {
((SinglePressAction) mAdapter.getItem(0)).onPress();
} else {
if (mDialog != null) {
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("LegacyGlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mDialog.getWindow().getDecorView().setSystemUiVisibility(
View.STATUS_BAR_DISABLE_EXPAND);
}
}
}
private ActionsDialog createDialog() {
//...
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
mItems.add(new PowerAction(mContext, mWindowManagerFuncs));
}
//...
}
```
showDialog最终都会调到handleShow,这里会根据actionKey创建相应的dialog,这里是电源的长按事件,会创建PowerAction,并执行其onPress方法
`PowerAction`
```java
public final class PowerAction extends SinglePressAction implements LongPressAction {
@Override
public void onPress() {
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */);
}
}
```
执行wms的shutdown方法
`WindowManagerService`
```java
@Override
public void shutdown(boolean confirm) {
// Pass in the UI context, since ShutdownThread requires it (to show UI).
ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
```
终于到主角ShutdownThread.shutdown方法。
##### 下拉菜单栏点关机或重启
这种一般是厂商自己定制ui,屏幕上点关机后弹出是否确定关机或者重启,点确定关机后发送广播
```java
private void rebootDevice(){
Intent localIntent = new Intent("android.intent.action.REBOOT");
localIntent.putExtra("android.intent.extra.KEY_CONFIRM", false);
localIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(localIntent);
}
```
ShutdownActivity会来处理此action
```xml
<activity android:name="com.android.internal.app.ShutdownActivity"
android:permission="android.permission.SHUTDOWN"
android:theme="@style/Theme.NoDisplay"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
```
`ShutdownActivity`
```java
public class ShutdownActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
Thread thr = new Thread("ShutdownActivity") {
@Override
public void run() {
IPowerManager pm = IPowerManager.Stub.asInterface(
ServiceManager.getService(Context.POWER_SERVICE));
try {
if (mReboot) {
pm.reboot(mConfirm, null, false);
} else {
pm.shutdown(mConfirm, reason, false);
}
} catch (RemoteException e) {
}
}
};
thr.start();
finish();
}
}
```
根据是否重启调用了PowerManagerManager.reboot或者shutdown
`PowerManagerService`
```java
@Override // Binder call
public void shutdown(boolean confirm, String reason, boolean wait) {
try {
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
@Nullable final String reason, boolean wait) {
//...
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
ShutdownThread.rebootSafeMode(getUiContext(), confirm);
} else if (haltMode == HALT_MODE_REBOOT) {
ShutdownThread.reboot(getUiContext(), reason, confirm);
} else {
ShutdownThread.shutdown(getUiContext(), reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(UiThread.getHandler(), runnable);
msg.setAsynchronous(true);
UiThread.getHandler().sendMessage(msg);
//...
}
```
看到最终还是ShutdownThread.shutdown或者reboot。
##### Framework层shutdown流程
`ShutdownThread`
```java
public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;
mReason = reason;
shutdownInner(context, confirm);
}
private static void shutdownInner(final Context context, boolean confirm) {
//...
if (confirm) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
sConfirmDialog = new AlertDialog.Builder(context)
.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off)
.setMessage(resourceId)
.setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
beginShutdownSequence(context);
}
})
.setNegativeButton(com.android.internal.R.string.no, null)
.create();
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
} else {
beginShutdownSequence(context);
}
}
```
这里confirm一般为false,代表是否需要再确认。最终都会到beginShutdownSequence去真正执行关机
```java
private static void beginShutdownSequence(Context context) {
// ...
//关机进度的弹框,不允许cancel
sInstance.mProgressDialog = showShutdownDialog(context);
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
//...
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start();
}
private static final ShutdownThread sInstance = new ShutdownThread();
```
弹出关机进度的弹框,并启动新线程ShutdownThread,执行start后到ShutdownThread.run
```java
public void run() {
//...
//发送关机广播
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
//...
//关闭ams
final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
//...
//关闭pms
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
//...
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
//...
// Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason);
}
```
run里还是做了很多清理工作,比如关了ams和pms,最后执行rebootOrShutdown
```java
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
//...震动 记录关机或重启日志
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);
}
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
```
只是往`sys.powerctl`系统属性里设置了shutdown,+reason,重启同理,传的是reboot,+reason。
##### Native层shutdown流程
当sys.powerctl系统属性改变时,会触发property_changed事件
`system/core/init/init.cpp`
```c++
void PropertyChanged(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
// commands to be executed.
if (name == "sys.powerctl") {
trigger_shutdown(value);
}
if (property_triggers_enabled) {
ActionManager::GetInstance().QueuePropertyChange(name, value);
WakeMainInitThread();
}
prop_waiter_state.CheckAndResetWait(name, value);
}
trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
static class ShutdownState {
public:
void TriggerShutdown(const std::string& command) {
// We can't call HandlePowerctlMessage() directly in this function,
// because it modifies the contents of the action queue, which can cause the action queue
// to get into a bad state if this function is called from a command being executed by the
// action queue. Instead we set this flag and ensure that shutdown happens before the next
// command is run in the main init loop.
auto lock = std::lock_guard{shutdown_command_lock_};
shutdown_command_ = command;
do_shutdown_ = true;
WakeMainInitThread();
}
std::optional<std::string> CheckShutdown() {
auto lock = std::lock_guard{shutdown_command_lock_};
if (do_shutdown_ && !IsShuttingDown()) {
return shutdown_command_;
}
return {};
}
} shutdown_state;
```
trigger_shutdown调用到shutdown_state.TriggerShutdown,这里注释写了没有直接调用HandlePowerctlMessage方法,因为这样可能会导致状态混乱,但是再下个命令执行前会执行这个方法。
`system/core/init/reboot.cpp`
```c++
void HandlePowerctlMessage(const std::string& command) {
//...
// Queue built-in shutdown_done
auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
DoReboot(cmd, command, reboot_target, run_fsck);
return Result<void>{};
};
//...
}
```
最终调到DoReboot去真正关机
```c++
static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& reboot_target,
bool run_fsck) {
// ...
// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
if (shutdown_timeout > 0ms) {
StopServicesAndLogViolations(stop_first, shutdown_timeout / 2, true /* SIGTERM */);
}
// 2 Send SIGKILL to ones that didn't terminate cleanly.
StopServicesAndLogViolations(stop_first, 0ms, false /* SIGKILL */);
SubcontextTerminate();
// Reap subcontext pids.
ReapAnyOutstandingChildren();
// 3. send volume abort_fuse and volume shutdown to vold
Service* vold_service = ServiceList::GetInstance().FindService("vold");
if (vold_service != nullptr && vold_service->IsRunning()) {
// Manually abort FUSE connections, since the FUSE daemon is already dead
// at this point, and unmounting it might hang.
CallVdc("volume", "abort_fuse");
CallVdc("volume", "shutdown");
vold_service->Stop();
} else {
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
StopServices(kDebuggingServices, 0ms, false /* SIGKILL */);
// 4. sync, try umount, and optionally run fsck for user shutdown
{
Timer sync_timer;
LOG(INFO) << "sync() before umount...";
sync();
LOG(INFO) << "sync() before umount took" << sync_timer;
}
// 5. drop caches and disable zram backing device, if exist
KillZramBackingDevice();
LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t;
// 6. unmount active apexes, otherwise they might prevent clean unmount of /data.
if (auto ret = UnmountAllApexes(); !ret.ok()) {
LOG(ERROR) << ret.error();
}
UmountStat stat =
TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore);
// 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);
// Send signal to terminate reboot monitor thread.
reboot_monitor_run = false;
sem_post(&reboot_semaphore);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, reboot_target);
abort();
}
```
注释写的还是比较清晰的,整理下:
1.向所有services发送terminate信号, 并等待其退出
2.如果services没有主动退出, 则发送kill信号, 强制杀掉service
3.给vold发送shutdown命令, 主动卸载挂载的设备,例如SD卡
4.执行sync操作,同步文件系统
5.调用kernel reboot系统调用
`system/core/init/reboot_utils.cpp`
```c++
void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
switch (cmd) {
case ANDROID_RB_POWEROFF:
reboot(RB_POWER_OFF);
break;
}
//...
}
```
##### Kernel层处理reboot流程
没找到代码。
1. kernel_restart_prepare
这里面会调用device_shutdown, 运行每个设备驱动注册的shutdown回调, 把驱动给停掉
2. syscore_shutdown
调用注册的syscore的shutdown回调。 syscore作为低功耗流程的一部分,其涉及的文件主要有syscore_ops.h和syscore.c,这一级别的回调函数是在完全屏蔽中断的场景下进行的。
3. machine_restart
不同cpu架构可能不同,向其他cpu 发送ipi中断, 让其他cpu 都停止。其他cpu 收到对应的终端后, 会进入wfe模式。
主要关闭所有驱动和cpu,完成真正的关机。
#### 总结
1. 不管用户是长按电源键还是点厂商的关机图标等,一般会先弹框让用户确认,确定后最终都会调到ShutdownThread.shutdown或者reboot方法
2. 启动新线程后先发送关机广播,震动,并关闭ams,pms等,再调用powermanagerservice的lowLevelShutdown,这里只是往sys.powerctl系统属性中写入shutdown或者reboot参数
3. jni层会监听这个属性的改变,一旦改变会调用PropertyChanged方法,最终调用DoReboot去关机,这里会把所有的服务关闭,卸载挂载的设备,比如sd卡等,最后调用RebootSystem到kernel层去真正关机
4. kernel层会调用kernel_restart_prepare和machine_restart等去关闭驱动和cpu等,完成真正的关机。
1059

被折叠的 条评论
为什么被折叠?



