android 关机流程 二

在run()方法中也會做一些reboot之前的清除工作,关掉要关的服务等。

  1. public void run() {    
  2.        BroadcastReceiver br = new BroadcastReceiver() {    
  3.            @Override public void onReceive(Context context, Intent intent) {    
  4.                // We don't allow apps to cancel this, so ignore the result.    
  5.                actionDone();    
  6.            }    
  7.        };    
  8.     
  9.              ......省略    
  10.        // Set initial variables and time out time.    
  11.        mActionDone = false;    
  12.        final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;    
  13.        synchronized (mActionDoneSync) {    
  14.            try {    
  15.                final IMountService mount = IMountService.Stub.asInterface(    
  16.                       ServiceManager.checkService("mount"));    
  17.                if (mount != null) {    
  18.                    mount.shutdown(observer);    
  19.               } else {    
  20.                    Log.w(TAG, "MountService unavailable for shutdown");    
  21.                }    
  22.            } catch (Exception e) {    
  23.                Log.e(TAG, "Exception during MountService shutdown", e);    
  24.            }    
  25.            while (!mActionDone) {    
  26.                long delay = endShutTime - SystemClock.elapsedRealtime();    
  27.                if (delay <= 0) {    
  28.                    Log.w(TAG, "Shutdown wait timed out");    
  29.                    break;    
  30.                }    
  31.                try {    
  32.                    mActionDoneSync.wait(delay);    
  33.                } catch (InterruptedException e) {    
  34.                }    
  35.            }    
  36.       }    
  37.     
  38.        rebootOrShutdown(mReboot, mRebootReason);//又繞到rebootOrShutdown函數    

此线程中的动作为:

(1)  广播全局事件,ACTION_SHUTDOWN Intent

(2)  shutdown  ActivityManager 服务

(3)  停止电话服务 (radio phone service)

(4)  停止mount 服务

(5)  最后调用 rebootOrShutdown(mReboot, mRebootReason);


在rebootOrShutdown(mReboot,mRebootReason);中


  
  
  1. public static void rebootOrShutdown(boolean reboot, String reason) {  
  2.     if (reboot) {  
  3.         Log.i(TAG, "Rebooting, reason: " + reason);  
  4.         try {  
  5.            PowerManagerService.lowLevelReboot(reason);//我們偉進來的reboot參數為true,所以走這一支  
  6.         } catch (Exception e) {  
  7.             Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);  
  8.        }  
  9.     } else if (SHUTDOWN_VIBRATE_MS > 0) {  
  10.         // vibrate before shutting down  
  11.        Vibrator vibrator = new SystemVibrator();  
  12.         try {  
  13.             vibrator.vibrate(SHUTDOWN_VIBRATE_MS);  
  14.         } catch (Exception e) {  
  15.             // Failure to vibrate shouldn't interrupt shutdown.  Just log it.  
  16.            Log.w(TAG, "Failed to vibrate during shutdown.", e);  
  17.         }  
  18.   
  19.         // vibrator is asynchronous so we need to wait to avoid shutting down too soon.  
  20.        try {  
  21.             Thread.sleep(SHUTDOWN_VIBRATE_MS);  
  22.         } catch (InterruptedException unused) {  
  23.         }  
  24.    }  
  25.   
  26.     // Shutdown power  
  27.     Log.i(TAG, "Performing low-level shutdown...");  
  28.     PowerManagerService.lowLevelShutdown();//如果我們偉進來的reboot為false那就是關機  
  29. }  
调用PowerManagerService.lowLevelShutdown();
此函数在frameworks/base/services/java/com/android/server/PowerManagerService.java中

又回到了PowerManagerService.
其實就是要開一個線程來在reboot之前把要做的一些工作先做完。
好吧,我們來看一下lowLevelReboot.

  1. public static void lowLevelReboot(String reason) throws IOException {    
  2.     nativeReboot(reason);//哈哈,還是要進入到時JNI    
  3. }  

lowLevelReboot调用了 JNI 方法 nativeReboot

lowLevelReboot定义在

/frameworks/base/services/jni/com_android_server_PowerManagerService.cpp中

  1. static void nativeReboot(JNIEnv *env, jobject clazz, jstring reason) {    
  2.     if (reason == NULL) {    
  3.         android_reboot(ANDROID_RB_RESTART, 0, 0);//這兒是直接重啟,因為沒有偉reason,    
  4.     } else {    
  5.         const char *chars = env->GetStringUTFChars(reason, NULL);    
  6.         android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);//這兒一般是上面偉入了recovery而重啟進入recovery,主要是oat或手機重置    
  7.         env->ReleaseStringUTFChars(reason, chars);  // In case it fails.    
  8.     }    
  9.     jniThrowIOException(env, errno);    
  10. }    

上面的android_reboot
在/system/core/libcutils/android_reboot.c中。
接下來我們就看一下android_reboot()又做些什麽。
  1. int android_reboot(int cmd, int flags, char *arg)    
  2. {    
  3.     int ret;    
  4.     
  5.     if (!(flags & ANDROID_RB_FLAG_NO_SYNC))    
  6.         sync();    
  7.     
  8.     if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))    
  9.         remount_ro();    
  10.     
  11.     switch (cmd) {    
  12.         case ANDROID_RB_RESTART://我們一般的重啟就是偉一這個,從上面的代碼有體現    
  13.             ret = reboot(RB_AUTOBOOT);    
  14.             break;    
  15.     
  16.         case ANDROID_RB_POWEROFF://shutdown走的是這兒,其實reboot和shutdown就很相似,從powermanagerservice中才都是call了nativeReboot    
  17.             ret = reboot(RB_POWER_OFF);    
  18.             break;    
  19.     
  20.         case ANDROID_RB_RESTART2://當一開始偉入了recovery時會走這兒    
  21.            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,    
  22.                            LINUX_REBOOT_CMD_RESTART2, arg);    
  23.             break;    
  24.     
  25.         default:    
  26.             ret = -1;    
  27.     }    
  28.     
  29.     return ret;    
  30. }    

上面的 reboot(RB_AUTOBOOT)又会call到/bionic/libc/unistd/reboot.c
  1. int reboot (int  mode)    
  2. {    
  3.     return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );    
  4.     //這兒的__reboot和上面的case ANDROID_RB_RESTART2的__reboot就是一樣的    
  5. }    

__reboot就到了/bionic/libc/arch-arm/syscalls/__reboot.S
这是一個内联汇编的函数。
通過swi軟中斷來重啟設備。
到此android部份的代碼重啟流程就大致完成。
其實我們剛才也注意到shutdown和reboot差不多走一樣的路線下來。
  1. ENTRY(__reboot)    
  2.     .save   {r4, r7}    
  3.     stmfd   sp!, {r4, r7}    
  4.     ldr     r7, =__NR_reboot    
  5.     swi     #0    
  6.     ldmfd   sp!, {r4, r7}    
  7.     movs    r0, r0    
  8.     bxpl    lr    
  9.     b       __set_syscall_errno    
  10. END(__reboot)    


可以看出来,这里将__reboot的实现映射到了__NR_reboot, 

而在bionic/libc/sys/linux-syscalls.h能够找到:

 #define __NR_reboot (__NR_SYSCALL_BASE + 88)

其被指定了一个固定的偏移量,在被调用的时候就是通过这个偏移量去内核中寻找对应的入口的,

由此可见,内核中一定有着相同的定义,否则将不能成功调用。

内核中对syscall偏移量的定义在内核源码中的arch/arm/include/asm/unistd.h,

相关信息完全一致。

已经找到了内核中的对应映射,那么下一步就要去找寻真正的实现函数了,

在include/asm-generic/unistd.h中可以找到内核对__NR_reboot的syscall函数映射,即


  1. /* kernel/sys.c */   
  2. #define __NR_setpriority 140 __SYSCALL(__NR_setpriority, sys_setpriority)  
  3. #define __NR_getpriority 141 __SYSCALL(__NR_getpriority, sys_getpriority)   
  4. #define __NR_reboot 142 __SYSCALL(__NR_reboot, sys_reboot)  

kernel/sys.c

在进入这个文件前,我们先去include/linux/syscalls.h中查看一下sys_reboot的定义:


  1. asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user *arg);  

与__reboot的调用参数一致。 



进入sys.c文件后,并没有找到名为sys_reboot的函数,而通过仔细查找,

发现一个很有趣的函数,其定义为

  1. SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg),  

对比__reboot的参数,能够符合。究竟是不是这个函数?

同样在include/linux/syscalls.h文件中,能够找到这样几个定义:


  1. #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)   
  2. #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)   
  3. #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)   
  4. #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)   
  5. #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)  
  6.  #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) ...   
  7. #define SYSCALL_DEFINEx(x, sname, ...) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) ...   
  8. #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))  

整合后等价于:


  1. #define SYSCALL_DEFINE4(name, ...) \ asmlinkage long sys##_name(__SC_DECL##4(__VA_ARGS__))  

这样就不难看出,

  1. SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)  

就是sys_reboot,也就是上层调用的__reboot的最终实现。函数实现如下:


4 。内核部分。 kernel/sys.c

其中,

  1. if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)  
  2. cmd = LINUX_REBOOT_CMD_HALT;  
  3.   
  4. lock_kernel();  
  5. switch (cmd) {  
  6. case LINUX_REBOOT_CMD_RESTART:  
  7. kernel_restart(NULL);  
  8. break;  
  9.   
  10. case LINUX_REBOOT_CMD_CAD_ON:  
  11. C_A_D = 1;  
  12. break;  
  13.   
  14. case LINUX_REBOOT_CMD_CAD_OFF:  
  15. C_A_D = 0;  
  16. break;  
  17.   
  18. case LINUX_REBOOT_CMD_HALT:  
  19. kernel_halt();  
  20. unlock_kernel();  
  21. do_exit(0);  
  22. break;  
  23.   
  24. case LINUX_REBOOT_CMD_POWER_OFF:  
  25. printk("test powe down in %s(%d)\n", __FILE__, __LINE__);  
  26. kernel_power_off();  
  27. unlock_kernel();  
  28. do_exit(0);  

猜你喜欢

转载自blog.csdn.net/a1028732302/article/details/43586251