android 7.0 关机流程详细分析
android 关机流程详细分析。前面有提到过android事件上报流程,InputReaderThread 从EventHub读到按键事件后,交给InputDispatcher 往上上报,我们从这里跟踪一下长按power键关键流程,
frameworks/native/services/inputflinger/InputDispatcher.cpp
?1 2 3 4 5 | void InputDispatcher::notifyKey( const NotifyKeyArgs* args) { … mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); … } |
这里的mPolicy是NativeInputManager对象.
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 } … } |
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
?1 2 3 | // Native callback. 1871 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 1872 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); |
1 | } |
这个mWindowManagerCallbacks 是通过下面的接口设置的。
?1 | inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); |
frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
?1 2 3 | 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.java ?1 | final WindowManagerPolicy mPolicy = new PhoneWindowManager(); |
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { case KeyEvent.KEYCODE_POWER: { 5815 result &= ~ACTION_PASS_TO_USER; 5816 isWakeKey = false ; // wake-up will be handled separately 5817 if (down) { 5818 interceptPowerKeyDown(event, interactive); 5819 } else { 5820 interceptPowerKeyUp(event, interactive, canceled); 5821 } 5822 break ; 5823 } } |
1 | private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { |
1 2 3 4 5 6 7 8 9 10 11 | ... 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 } |
1 | } |
1 2 3 4 5 6 7 8 9 10 | private class PolicyHandler extends Handler { ... 746 @Override 747 public void handleMessage(Message msg) { 748 switch (msg.what) { case MSG_POWER_LONG_PRESS: 790 powerLongPress(); 791 break ; } } |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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());会弹出选择界面。
frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java ?1 2 3 4 5 6 7 8 9 10 11 12 | 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 completes 178 mHandler.sendEmptyMessage(MESSAGE_SHOW); 179 } else { 180 handleShow(); 181 } 182 } |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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() == 1 203 && mAdapter.getItem( 0 ) instanceof SinglePressAction 204 && !(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 } |
?
1 2 3 4 5 6 7 8 | 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 } } |
1 2 3 4 5 6 7 | private final class PowerAction extends SinglePressAction implements LongPressAction { @Override 376 public void onPress() { 377 // shutdown by making sure radio and power are handled accordingly. 378 mWindowManagerFuncs.shutdown( false /* confirm */ ); 379 } 380 } |
如果点击关机按钮,就会走到onPress(),调用WindowManagerservice的shutdown接口。
?1 2 3 4 5 | // Called by window manager policy. Not exposed externally. 5823 @Override 5824 public void shutdown( boolean confirm) { 5825 ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); 5826 } |
1 2 3 4 5 6 | 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 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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(mRebootSafeMode 166 ? com.android.internal.R.string.reboot_safemode_title 167 : 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 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 shutdown 342 sInstance.mHandler = new Handler() { 343 }; 344 sInstance.start(); 345 } |
1 | private static final ShutdownThread sInstance = new ShutdownThread(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 power 667 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 ?1 2 3 4 5 6 | 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中。
?1 2 3 4 | { "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字符串。
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | static int do_powerctl( const std::vector 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 中有声明
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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
?1 2 3 4 5 6 7 8 | #include 30 #include |
又调用到了__reboot(),在__reboot.s中用汇编实现,不同的cpu架构在不同目录下,比如32为arm平台。
bionic/libc/arch-arm/syscalls/__reboot.S ?1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 3 #include < private bionic_asm.h= "" > 4 5 ENTRY(__reboot) 6 mov ip, r7 7 .cfi_register r7, ip 8 ldr r7, =__NR_reboot 9 swi # 0 10 mov r7, ip 11 .cfi_restore r7 12 cmn r0, #(MAX_ERRNO + 1 ) 13 bxls lr 14 neg r0, r0 15 b __set_errno_internal 16 END(__reboot) private > |
这里又将__reboot的实现映射到了__NR_reboot。
bionic/libc/kernel/uapi/asm-generic/unistd.h ?1 2 3 4 5 | /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ 219 #define __NR_rt_sigreturn 139 220 #define __NR_setpriority 140 221 #define __NR_getpriority 141 222 #define __NR_reboot 142 |
__NR_reboot对应的系统调用声明在Unistd.h中
linux-4.10/include/uapi/asm-generic/unistd.h ?1 2 3 4 5 6 7 8 9 10 | #define __NR_rt_sigreturn 139 419 __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn) 420 421 /* kernel/sys.c */ 422 #define __NR_setpriority 140 423 __SYSCALL(__NR_setpriority, sys_setpriority) 424 #define __NR_getpriority 141 425 __SYSCALL(__NR_getpriority, sys_getpriority) 426 #define __NR_reboot 142 427 __SYSCALL(__NR_reboot, sys_reboot) |
对应的函数是sys_reboot(),声明在linux-4.10\include\linux\syscalls.h
?
1 2 3 4 5 6 7 | 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。
/*
add by puo补充一点,这里sys_reboot的实现其实就是 SYSCALL_DEFINE4(reboot,
int
, magic1,
int
, magic2, unsigned
int
, cmd,
void
__user *, arg); 自己看SYSCALL_DEFINE4的宏定义实现就知道了。
*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 } |
bionic/libc/include/sys/reboot.h ?
1 2 3 4 5 6 7 | /* use glibc names as well */ 37 38 #define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART 39 #define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT 40 #define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON 41 #define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF 42 #define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** 253 * kernel_power_off - power_off the system 254 * 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); |
kernel/kernel/exit.c
do_exit
exit_notify(tsk, group_dead);
forget_original_parent(tsk, &dead);
reaper = find_child_reaper(father);
panic("Attempted to kill init! exitcode=0x%08x\n",father->signal->group_exit_code ?: father->exit_code);
更多相关文章
- Android使用UncaughtExceptionHandler捕获全局异常
- android自定义Dialog实现底部弹窗
- [置顶] 电源管理之android内核suspend to disk的实现(六)--STD执行
- Android(安卓)Fragment详解(二):Fragment创建及其生命周期
- Android中statfs使用注意事项
- Android(安卓)中使用自定义字体的方法
- Android(安卓)Sensor HAL层分析
- Android(安卓)自定义手写签名并保存到sdcard中(可以保存背景图)
- android 自定义 view 实现表盘效果