在Android关机中插入脚本

来源:互联网 发布:centos一键smtp 编辑:程序博客网 时间:2024/05/01 18:51

一、Android开机运行脚本流程

      在Android启动的过程中,在kernel/init/main.c中的start_kernel->rest_init->kernel_init->init_post->run_init_process("/sbin/init")中启动了init相关脚本, 

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static noinline int init_post(void)  
  2. 804{  
  3. 805 /* need to finish all async __init code before freeing the memory */  
  4. 806 async_synchronize_full();  
  5. 807 free_initmem();  
  6. 808 mark_rodata_ro();  
  7. 809 system_state = SYSTEM_RUNNING;  
  8. 810 numa_default_policy();  
  9. 811  
  10. 812 log_boot("Kernel_init_done");  
  11. 813  
  12. 814 current->signal->flags |= SIGNAL_UNKILLABLE;  
  13. 815  
  14. 816 if (ramdisk_execute_command) {  
  15. 817     run_init_process(ramdisk_execute_command);  
  16. 818     printk(KERN_WARNING "Failed to execute %s\n",  
  17. 819             ramdisk_execute_command);  
  18. 820 }  
  19. 821  
  20. 822 /*  
  21. 823  * We try each of these until one succeeds.  
  22. 824  *  
  23. 825  * The Bourne shell can be used instead of init if we are  
  24. 826  * trying to recover a really broken machine.  
  25. 827  */  
  26. 828 if (execute_command) {  
  27. 829     run_init_process(execute_command);  
  28. 830     printk(KERN_WARNING "Failed to execute %s.  Attempting "  
  29. 831                 "defaults...\n", execute_command);  
  30. 832 }  
  31. 833 run_init_process("/sbin/init");  
  32. 834 run_init_process("/etc/init");  
  33. 835 run_init_process("/bin/init");  
  34. 836 run_init_process("/bin/sh");  
  35. 837  
  36. 838 panic("No init found.  Try passing init= option to kernel. "  
  37. 839       "See Linux Documentation/init.txt for guidance.");  
  38. 840}  

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 794static void run_init_process(const char *init_filename)  
  2. 795{  
  3. 796 argv_init[0] = init_filename;  
  4. 797 kernel_execve(init_filename, argv_init, envp_init);  
  5. 798}  

二、Android关机流程简介

    看这个看完这篇博客关机流程分析,我们基本上对关机流程有一个初步的认识,现在我们往流程中插入shell脚本,使用和开机时候相类似的办法来做。

三、定位到jni层

     首先在blog中我们了解到,在关机或者重启的时候最终会分别调用jni层的如下函数,路径为:                   

                                      frameworks/base/services/jni/com_android_server_power_PowerManagerService.cpp

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 196static void nativeShutdown(JNIEnv *env, jclass clazz) {  
  2. 197    android_reboot(ANDROID_RB_POWEROFF, 0, 0);  
  3. 198}  
  4. 199  
  5. 200static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {  
  6. 201    if (reason == NULL) {  
  7. 202        android_reboot(ANDROID_RB_RESTART, 0, 0);  
  8. 203    } else {  
  9. 204        const char *chars = env->GetStringUTFChars(reason, NULL);  
  10. 205        android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);  
  11. 206        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.  
  12. 207    }  
  13. 208    jniThrowIOException(env, errno);  
  14. 209}  
     在上面代码中,我们发现不管是nativeShutdown 还是nativeReboot函数最终都调用了android_reboot函数。

四、进入android_reboot函数

     对应路径:
     system/core/libcutils/android_reboot.c

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int android_reboot(int cmd, int flags, char *arg)  
  2. 105{  
  3. 106    int ret;  
  4. 107  
  5. 108    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))  
  6. 109        sync();  
  7. 110  
  8. 111    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))  
  9. 112        remount_ro();  
  10. 113  
  11. 114    switch (cmd) {  
  12. 115        case ANDROID_RB_RESTART:  
  13. 116            ret = reboot(RB_AUTOBOOT);  
  14. 117            break;  
  15. 118  
  16. 119        case ANDROID_RB_POWEROFF:  
  17. 120            ret = reboot(RB_POWER_OFF);  
  18. 121            break;  
  19. 122  
  20. 123        case ANDROID_RB_RESTART2:  
  21. 124            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,  
  22. 125                           LINUX_REBOOT_CMD_RESTART2, arg);  
  23. 126            break;  
  24. 127  
  25. 128        default:  
  26. 129            ret = -1;  
  27. 130    }  
  28. 131  
  29. 132    return ret;  
  30. 133}  

      在这个函数中,重启或者关机都进入这里,当然细心的童鞋,应该已经发现了,在这里面,switch对应的所有分支选择也都将进入reboot函数,reboot函数非常简单,如下所示路径:bionic/libc/unistd/reboot.c

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 28#include <unistd.h>  
  2. 29#include <sys/reboot.h>  
  3. 30  
  4. 31int reboot (int  mode)  
  5. 32{  
  6. 33    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );  
  7. 34}  
     因此,我们想要关机时候插入脚本的话,就可以选择在android_reboot函数或者在reboot函数中做一些愉快的操作。

五、插入脚本

     1.需要点的技能点
          需要一些小知识如下:fork,execl族,shell脚本和.bin文件,相信大家的技能树上都有的。。。。

     2.准备工作

         (1)首先需要一个测试的脚本,名称为myclose:         

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #!/bin/sh  
  2. echo "I am myclose.sh open"  
  3. ./system/bin/vibrator_test  
  4. echo "I am myclose.sh close"  
        (2)然后加入一个.bin文件,该文件的作用也就是控制震动马达震动10S,vibrator_test:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <time.h>  
  5. #include <unistd.h>  
  6. #include <string.h>  
  7. #include <sys/ioctl.h>  
  8. #include <sys/types.h>  
  9. #include <sys/stat.h>  
  10. #include <fcntl.h>  
  11. #include <errno.h>  
  12.   
  13. int main()  
  14. {  
  15.         int fd;  
  16.         int ret;  
  17.         char data[1];  
  18.   
  19.         if((fd=open("/sys/class/timed_output/vibrator/vibr_on",O_WRONLY))==-1){  
  20.                 printf("open memdev WRONG!\n");  
  21.                 perror("open");  
  22.         }  
  23.         else  
  24.                 printf("open memdev SUCCESS!\n");  
  25.         data[0] = '1';  
  26.         write(fd, &data,sizeof(data));  
  27.         sleep(10);  
  28.         data[0] = '0';  
  29.         write(fd, &data,sizeof(data));  
  30.         close(fd);  
  31.         return 0;  
  32. }  
     3.修改android_reboot

     对它的修改很简单,也就是首先使用fork生成一个子进程,然后用execl族取代子进程,运行myclose的脚本文件,父进程等待子进程执行完了之后,在继续剩下的关机流程,
注:不要使用vfork,这样会导致android_reboot传进来的参数cmd自己就发生变化,就算不操作cmd,求大神指导原因。。。。
修改后的android_reboot函数如下:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int android_reboot(int cmd, int flags, char *arg)  
  2. {  
  3.         int ret;  
  4.   
  5.         SLOGD("yulinghan i am here!!!!,cmd = %d",cmd);  
  6.   
  7.         pid_t pc,pid;  
  8.         pid = getpid();  
  9.   
  10.         pc = fork();  
  11.         if(pc<0){  
  12.                 exit(1);  
  13.         }  
  14.         else if(pc == 0){  
  15.                 SLOGD("yulinghan Child ID is %d,father id is %d,cmd = %d",getpid(),getppid(),cmd);  
  16.                 execl("/system/bin/sh","sh","/system/bin/myclose",NULL);  
  17.                 exit(0);  
  18.         }  
  19.         else{  
  20.                 pid = waitpid(pc, NULL, 0);  
  21.                   
  22.                 SLOGD("yulinghan I am father,my id is %d,cmd = %d",getpid(),cmd);  
  23.                 if (!(flags & ANDROID_RB_FLAG_NO_SYNC))  
  24.                         sync();  
  25.   
  26.                 if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))  
  27.                         remount_ro();  
  28.   
  29.                 switch (cmd) {  
  30.                         case ANDROID_RB_RESTART:  
  31.                                 SLOGD("yulinghan ANDROID_RB_RESTART");  
  32.                                 ret = reboot(RB_AUTOBOOT);  
  33.                                 break;  
  34.   
  35.                         case ANDROID_RB_POWEROFF:  
  36.                                 SLOGD("yulinghan ANDROID_RB_POWEROFF");  
  37.                                 ret = reboot(RB_POWER_OFF);  
  38.                                 break;  
  39.                         case ANDROID_RB_RESTART2:  
  40.                                 SLOGD("yulinghan ANDROID_RB_RESTART2");  
  41.                                 ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,  
  42.                                                 LINUX_REBOOT_CMD_RESTART2, arg);  
  43.                                 break;  
  44.   
  45.                         default:  
  46.                                 SLOGD("yulinghan default\n");  
  47.                                 ret = -1;  
  48.                 }  
  49.   
  50.                 return ret;  
  51.         }  
  52. }  
    4.结果测试

      (1)修改android_reboot之后重新编译,编译成库,push进手机或者直接编译系统都行。。
      (2)adb push 将脚本myclose和执行文件vibrator_test放到/system/bin/ 目录下,注意修改他们的执行权限。
      ( 3)执行reboot,测试效果如下:

 


      (4)输入reboot命令之后,首先打印了 "I am myclose.sh open"
           然后开始执行 ./system/bin/vibrator_test
          手机在震动了10s之后,再打印了 "I am myclose.sh close",之后才重启。
   5.j结束语
        在加入了这个myclose脚本之后,如果想在关机流程中加入想执行的操作,直接将该操作加在myclose上面就好,相当的美妙。。

0 0
原创粉丝点击