android 关机流程详细分析
来源:互联网 发布:男网络歌手好听的歌曲 编辑:程序博客网 时间:2024/05/21 22:57
前面的博客有提到过android事件上报流程,InputReaderThread 从EventHub读到按键事件后,交给InputDispatcher 往上上报,我们从这里跟踪一下长按power键关键流程,
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {…mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);…}
这里的mPolicy是NativeInputManager对象.
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {… jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);886 jint wmActions;887 if (keyEventObj) {888 wmActions = env->CallIntMethod(mServiceObj,889 gServiceClassInfo.interceptKeyBeforeQueueing,890 keyEventObj, policyFlags);891 if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {892 wmActions = 0;893 }894 android_view_KeyEvent_recycle(env, keyEventObj);895 env->DeleteLocalRef(keyEventObj);896 } else {897 ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");898 wmActions = 0;899 }…}这里会call到java层,call 到InputManagerService里面。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.1871 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {1872 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
这个mWindowManagerCallbacks 是通过下面的接口设置的。
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());继续追查下去,就是一个InputMonitor 实例。
frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); }
这里的mService就是WindowManagerService。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javafinal WindowManagerPolicy mPolicy = new PhoneWindowManager();所以这个mPolicy就是PhoneWindowManager对象。
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { case KeyEvent.KEYCODE_POWER: {5815 result &= ~ACTION_PASS_TO_USER;5816 isWakeKey = false; // wake-up will be handled separately5817 if (down) {5818 interceptPowerKeyDown(event, interactive);5819 } else {5820 interceptPowerKeyUp(event, interactive, canceled);5821 }5822 break;5823 }}
继续走到interceptPowerKeyDown()函数里面。private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
...if (interactive) {1087 // When interactive, we're already awake.1088 // Wait for a long press or for the button to be released to decide what to do.1089 if (hasLongPressOnPowerBehavior()) {1090 Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);1091 msg.setAsynchronous(true);1092 mHandler.sendMessageDelayed(msg,1093 ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());1094 }1095 }
}这里面判断是长按power键后会发一个MSG_POWER_LONG_PRESS消息出来,我们看一下它的处理。
private class PolicyHandler extends Handler {...746 @Override747 public void handleMessage(Message msg) {748 switch (msg.what) { case MSG_POWER_LONG_PRESS:790 powerLongPress();791 break;}}
private void powerLongPress() {1255 final int behavior = getResolvedLongPressOnPowerBehavior();1256 switch (behavior) {1257 case LONG_PRESS_POWER_NOTHING:1258 break;1259 case LONG_PRESS_POWER_GLOBAL_ACTIONS:1260 mPowerKeyHandled = true;1261 if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {1262 performAuditoryFeedbackForAccessibilityIfNeed();1263 }1264 showGlobalActionsInternal();1265 break;1273 }1274 }
接下来会走到showGlobalActionsInternal()函数里面。 void showGlobalActionsInternal() {1389 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);1390 if (mGlobalActions == null) {1391 mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);1392 }1393 final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();1394 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());1395 if (keyguardShowing) {1396 // since it took two seconds of long press to bring this up,1397 // poke the wake lock so they have some time to see the dialog.1398 mPowerManager.userActivity(SystemClock.uptimeMillis(), false);1399 }1400 }
showDialog(keyguardShowing, isDeviceProvisioned());会弹出选择界面。
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {172 mKeyguardShowing = keyguardShowing;173 mDeviceProvisioned = isDeviceProvisioned;174 if (mDialog != null) {175 mDialog.dismiss();176 mDialog = null;177 // Show delayed, so that the dismiss of the previous dialog completes178 mHandler.sendEmptyMessage(MESSAGE_SHOW);179 } else {180 handleShow();181 }182 }
private void handleShow() {197 awakenIfNecessary();198 mDialog = createDialog();199 prepareDialog();200 201 // If we only have 1 item and it's a simple press action, just do this action.202 if (mAdapter.getCount() == 1203 && mAdapter.getItem(0) instanceof SinglePressAction204 && !(mAdapter.getItem(0) instanceof LongPressAction)) {205 ((SinglePressAction) mAdapter.getItem(0)).onPress();206 } else {207 WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();208 attrs.setTitle("GlobalActions");209 mDialog.getWindow().setAttributes(attrs);210 mDialog.show();211 mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);212 }213 }
createDialog()里面很重要的一点是创建了多项选项按钮,并绑定了对应的处理函数。private GlobalActionsDialog createDialog() { if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {281 mItems.add(new PowerAction());282 } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {283 mItems.add(mAirplaneModeOn);284 } }
关机对应的是PowerAction 。private final class PowerAction extends SinglePressAction implements LongPressAction { @Override376 public void onPress() {377 // shutdown by making sure radio and power are handled accordingly.378 mWindowManagerFuncs.shutdown(false /* confirm */);379 }380 }
如果点击关机按钮,就会走到onPress(),调用WindowManagerservice的shutdown接口。
// Called by window manager policy. Not exposed externally.5823 @Override5824 public void shutdown(boolean confirm) {5825 ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);5826 }frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public static void shutdown(final Context context, String reason, boolean confirm) {133 mReboot = false;134 mRebootSafeMode = false;135 mReason = reason;136 shutdownInner(context, confirm);137 }
static void shutdownInner(final Context context, boolean confirm) {...159 if (confirm) {160 final CloseDialogReceiver closer = new CloseDialogReceiver(context);161 if (sConfirmDialog != null) {162 sConfirmDialog.dismiss();163 }164 sConfirmDialog = new AlertDialog.Builder(context)165 .setTitle(mRebootSafeMode166 ? com.android.internal.R.string.reboot_safemode_title167 : com.android.internal.R.string.power_off)168 .setMessage(resourceId)169 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {170 public void onClick(DialogInterface dialog, int which) {171 beginShutdownSequence(context);172 }173 })174 .setNegativeButton(com.android.internal.R.string.no, null)175 .create();176 closer.dialog = sConfirmDialog;177 sConfirmDialog.setOnDismissListener(closer);178 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);179 sConfirmDialog.show();180 } else {181 beginShutdownSequence(context);182 }183 }如果confirm为true,则弹出确认对话框,总之最终会走beginShutdownSequence(context) 进行接下来的关机流程。
private static void beginShutdownSequence(Context context) {...276 if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {...301 } else {302 pd.setTitle(context.getText(com.android.internal.R.string.power_off));303 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));304 pd.setIndeterminate(true);305 }306 pd.setCancelable(false);307 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);308 309 pd.show();310 ...341 // start the thread that initiates shutdown342 sInstance.mHandler = new Handler() {343 };344 sInstance.start();345 }pd.show(); 显示关机的进度界面, sInstance.start(); 会启动另外一个线程,走接下来的关机流程。
private static final ShutdownThread sInstance = new ShutdownThread();
358 public void run() {359 ...384 Log.i(TAG, "Sending shutdown broadcast...");385 386 // First send the high-level shut down broadcast.387 mActionDone = false;388 Intent intent = new Intent(Intent.ACTION_SHUTDOWN);389 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);390 mContext.sendOrderedBroadcastAsUser(intent,391 UserHandle.ALL, null, br, mHandler, 0, null, null);392 393 ...497 rebootOrShutdown(mContext, mReboot, mReason);498 }
ShutdownThread启动之后,就会跑它的run()函数,做了很多工作,发送关机广播,做一些状态检查和清理工作。 public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {644 if (reboot) {645 Log.i(TAG, "Rebooting, reason: " + reason);646 PowerManagerService.lowLevelReboot(reason);647 Log.e(TAG, "Reboot failed, will attempt shutdown instead");648 reason = null;649 } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {...664 }665 666 // Shutdown power667 Log.i(TAG, "Performing low-level shutdown...");668 PowerManagerService.lowLevelShutdown(reason);669 }
最后又跑到PowerManagerService 的lowLevelShutdown()。
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java public static void lowLevelShutdown(String reason) {2787 if (reason == null) {2788 reason = "";2789 }2790 SystemProperties.set("sys.powerctl", "shutdown," + reason);2791 }
很多人疑惑SystemProperties.set("sys.powerctl", "shutdown,"+ reason);又跑到了哪里?
首先sys.powerctl 在init.rc中有配置,它是一类特殊的property,可以认为是command。
它对应的处理函数定义在/system/core/init/builtins.cpp中。
{"mount", {3, kMax, do_mount}}, {"umount", {1, 1, do_umount}}, {"powerctl", {1, 1, do_powerctl}}, {"restart", {1, 1, do_restart}},
所以接着会调到do_powerctl(),注意传下来的参数有shutdown,所以cmd是ANDROID_RB_POWEROFF,reboot_target是上面传的reason字符串。
static int do_powerctl(const std::vector<std::string>& args) {696 const char* command = args[1].c_str();697 int len = 0;698 unsigned int cmd = 0;699 const char *reboot_target = "";700 void (*callback_on_ro_remount)(const struct mntent*) = NULL;701 702 if (strncmp(command, "shutdown", 8) == 0) {703 cmd = ANDROID_RB_POWEROFF;704 len = 8;705 } else if (strncmp(command, "reboot", 6) == 0) {706 cmd = ANDROID_RB_RESTART2;707 len = 6;708 }...763 return android_reboot_with_callback(cmd, 0, reboot_target,764 callback_on_ro_remount);765 }
函数和cmd值在/system/core/include/cutils/android_reboot.h 中有声明
int android_reboot_with_callback(213 int cmd, int flags __unused, const char *arg,214 void (*cb_on_remount)(const struct mntent*))215 {216 int ret;217 remount_ro(cb_on_remount);218 switch (cmd) {219 case ANDROID_RB_RESTART:220 ret = reboot(RB_AUTOBOOT);221 break;222 223 case ANDROID_RB_POWEROFF:224 ret = reboot(RB_POWER_OFF);225 break;226 227 case ANDROID_RB_RESTART2:228 ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,229 LINUX_REBOOT_CMD_RESTART2, arg);230 break;231 232 default:233 ret = -1;234 }235 236 return ret;237 }
所以最后又调用到了reboot()函数,传入的参数是RB_POWER_OFF。
reboot()定义在/bionic/libc/bionic/reboot.cpp
#include <unistd.h>30 #include <sys/reboot.h>31 32 extern "C" int __reboot(int, int, int, void*);33 34 int reboot(int mode) {35 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);36 }
又调用到了__reboot(),在__reboot.s中用汇编实现,不同的cpu架构在不同目录下,比如32为arm平台。
bionic/libc/arch-arm/syscalls/__reboot.S3 #include <private/bionic_asm.h>4 5 ENTRY(__reboot)6 mov ip, r77 .cfi_register r7, ip8 ldr r7, =__NR_reboot9 swi #010 mov r7, ip11 .cfi_restore r712 cmn r0, #(MAX_ERRNO + 1)13 bxls lr14 neg r0, r015 b __set_errno_internal16 END(__reboot)
这里又将__reboot的实现映射到了__NR_reboot。
bionic/libc/kernel/uapi/asm-generic/unistd.h/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */219 #define __NR_rt_sigreturn 139220 #define __NR_setpriority 140221 #define __NR_getpriority 141222 #define __NR_reboot 142
__NR_reboot对应的系统调用声明在Unistd.h中
linux-4.10/include/uapi/asm-generic/unistd.h #define __NR_rt_sigreturn 139419 __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)420 421 /* kernel/sys.c */422 #define __NR_setpriority 140423 __SYSCALL(__NR_setpriority, sys_setpriority)424 #define __NR_getpriority 141425 __SYSCALL(__NR_getpriority, sys_getpriority)426 #define __NR_reboot 142427 __SYSCALL(__NR_reboot, sys_reboot)
对应的函数是sys_reboot(),声明在linux-4.10\include\linux\syscalls.h
struct timespec __user *interval);311 asmlinkage long sys_setpriority(int which, int who, int niceval);312 asmlinkage long sys_getpriority(int which, int who);313 314 asmlinkage long sys_shutdown(int, int);315 asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,316 void __user *arg);
sys_reboot()的定义在linux-4.10.3\kernel\reboot.c。
280 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,281 void __user *, arg)282 {283 ...314 mutex_lock(&reboot_mutex);315 switch (cmd) {316 case LINUX_REBOOT_CMD_RESTART:317 kernel_restart(NULL);318 break;319 320 case LINUX_REBOOT_CMD_CAD_ON:321 C_A_D = 1;322 break;323 324 case LINUX_REBOOT_CMD_CAD_OFF:325 C_A_D = 0;326 break;327 328 case LINUX_REBOOT_CMD_HALT:329 kernel_halt();330 do_exit(0);331 panic("cannot halt");332 333 case LINUX_REBOOT_CMD_POWER_OFF:334 kernel_power_off();335 do_exit(0);336 break; ...361 default:362 ret = -EINVAL;363 break;364 }365 mutex_unlock(&reboot_mutex);366 return ret;367 }
mode从上面传下来的值是RB_POWER_OFF。bionic/libc/include/sys/reboot.h
/* use glibc names as well */37 38 #define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART39 #define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT40 #define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON41 #define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF42 #define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
所以接下来走到kernel_power_off(); /**253 *kernel_power_off - power_off the system254 *255 *Shutdown everything and perform a clean system power_off.256 */257 void kernel_power_off(void)258 {259 kernel_shutdown_prepare(SYSTEM_POWER_OFF);260 if (pm_power_off_prepare)261 pm_power_off_prepare();262 migrate_to_reboot_cpu();263 syscore_shutdown();264 pr_emerg("Power down\n");265 kmsg_dump(KMSG_DUMP_POWEROFF);266 machine_power_off();267 }268 EXPORT_SYMBOL_GPL(kernel_power_off);
走到这里就不再继续往下看了。
- android 关机流程详细分析
- android 关机 流程分析
- android 关机 流程分析
- android 关机 流程分析
- Android 关机流程分析
- android 关机流程分析
- android 关机 流程分析
- android 关机 流程分析
- android 关机 流程分析
- android 关机 流程分析
- android 关机 流程分析
- android 关机流程分析
- android系统关机流程分析
- Android 系统关机流程分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- Unity 显示FPS
- java知识
- Hadoop MapReduce 简单案例--求平均值
- 计算机二级易混点
- 表格布局注册页面
- android 关机流程详细分析
- Unsupported major.minor version 51.0
- 高德地图开发Key的申请
- 习题6-1 平衡的括号(Parentheses Balance, UVa 673)
- Eclipse+Maven创建webapp项目<一>
- LinkedBlockingQueue 与PriorityQueue -- JAVA 基础
- 494. Target Sum(M)
- [设计模式]动态代理模式
- (双重循环之)c语言回顾之冒泡排序