在Android关机中插入脚本

来源:互联网 发布:linux 资源暂时不可用 编辑:程序博客网 时间:2024/04/29 10:27

一、Android开机运行脚本流程

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

static noinline int init_post(void)804{805/* need to finish all async __init code before freeing the memory */806async_synchronize_full();807free_initmem();808mark_rodata_ro();809system_state = SYSTEM_RUNNING;810numa_default_policy();811812log_boot("Kernel_init_done");813814current->signal->flags |= SIGNAL_UNKILLABLE;815816if (ramdisk_execute_command) {817run_init_process(ramdisk_execute_command);818printk(KERN_WARNING "Failed to execute %s\n",819ramdisk_execute_command);820}821822/*823 * We try each of these until one succeeds.824 *825 * The Bourne shell can be used instead of init if we are826 * trying to recover a really broken machine.827 */828if (execute_command) {829run_init_process(execute_command);830printk(KERN_WARNING "Failed to execute %s.  Attempting "831"defaults...\n", execute_command);832}833run_init_process("/sbin/init");834run_init_process("/etc/init");835run_init_process("/bin/init");836run_init_process("/bin/sh");837838panic("No init found.  Try passing init= option to kernel. "839      "See Linux Documentation/init.txt for guidance.");840}

794static void run_init_process(const char *init_filename)795{796argv_init[0] = init_filename;797kernel_execve(init_filename, argv_init, envp_init);798}

二、Android关机流程简介

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

三、定位到jni层

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

                                      frameworks/base/services/jni/com_android_server_power_PowerManagerService.cpp

196static void nativeShutdown(JNIEnv *env, jclass clazz) {197    android_reboot(ANDROID_RB_POWEROFF, 0, 0);198}199200static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {201    if (reason == NULL) {202        android_reboot(ANDROID_RB_RESTART, 0, 0);203    } else {204        const char *chars = env->GetStringUTFChars(reason, NULL);205        android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);206        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.207    }208    jniThrowIOException(env, errno);209}
     在上面代码中,我们发现不管是nativeShutdown 还是nativeReboot函数最终都调用了android_reboot函数。

四、进入android_reboot函数

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

int android_reboot(int cmd, int flags, char *arg)105{106    int ret;107108    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))109        sync();110111    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))112        remount_ro();113114    switch (cmd) {115        case ANDROID_RB_RESTART:116            ret = reboot(RB_AUTOBOOT);117            break;118119        case ANDROID_RB_POWEROFF:120            ret = reboot(RB_POWER_OFF);121            break;122123        case ANDROID_RB_RESTART2:124            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,125                           LINUX_REBOOT_CMD_RESTART2, arg);126            break;127128        default:129            ret = -1;130    }131132    return ret;133}

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

28#include <unistd.h>29#include <sys/reboot.h>3031int reboot (int  mode)32{33    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );34}
     因此,我们想要关机时候插入脚本的话,就可以选择在android_reboot函数或者在reboot函数中做一些愉快的操作。

五、插入脚本

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

     2.准备工作

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

#!/bin/shecho "I am myclose.sh open"./system/bin/vibrator_testecho "I am myclose.sh close"
        (2)然后加入一个.bin文件,该文件的作用也就是控制震动马达震动10S,vibrator_test:

#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#include <unistd.h>#include <string.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>int main(){        int fd;        int ret;        char data[1];        if((fd=open("/sys/class/timed_output/vibrator/vibr_on",O_WRONLY))==-1){                printf("open memdev WRONG!\n");                perror("open");        }        else                printf("open memdev SUCCESS!\n");        data[0] = '1';        write(fd, &data,sizeof(data));        sleep(10);        data[0] = '0';        write(fd, &data,sizeof(data));        close(fd);        return 0;}
     3.修改android_reboot

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

int android_reboot(int cmd, int flags, char *arg){        int ret;        SLOGD("yulinghan i am here!!!!,cmd = %d",cmd);        pid_t pc,pid;        pid = getpid();        pc = fork();        if(pc<0){                exit(1);        }        else if(pc == 0){                SLOGD("yulinghan Child ID is %d,father id is %d,cmd = %d",getpid(),getppid(),cmd);                execl("/system/bin/sh","sh","/system/bin/myclose",NULL);                exit(0);        }        else{                pid = waitpid(pc, NULL, 0);                                SLOGD("yulinghan I am father,my id is %d,cmd = %d",getpid(),cmd);                if (!(flags & ANDROID_RB_FLAG_NO_SYNC))                        sync();                if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))                        remount_ro();                switch (cmd) {                        case ANDROID_RB_RESTART:                                SLOGD("yulinghan ANDROID_RB_RESTART");                                ret = reboot(RB_AUTOBOOT);                                break;                        case ANDROID_RB_POWEROFF:                                SLOGD("yulinghan ANDROID_RB_POWEROFF");                                ret = reboot(RB_POWER_OFF);                                break;                        case ANDROID_RB_RESTART2:                                SLOGD("yulinghan ANDROID_RB_RESTART2");                                ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,                                                LINUX_REBOOT_CMD_RESTART2, arg);                                break;                        default:                                SLOGD("yulinghan default\n");                                ret = -1;                }                return ret;        }}
    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
原创粉丝点击