在Android关机中插入脚本

一、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 */
806	async_synchronize_full();
807	free_initmem();
808	mark_rodata_ro();
809	system_state = SYSTEM_RUNNING;
810	numa_default_policy();
811
812	log_boot("Kernel_init_done");
813
814	current->signal->flags |= SIGNAL_UNKILLABLE;
815
816	if (ramdisk_execute_command) {
817		run_init_process(ramdisk_execute_command);
818		printk(KERN_WARNING "Failed to execute %s\n",
819				ramdisk_execute_command);
820	}
821
822	/*
823	 * We try each of these until one succeeds.
824	 *
825	 * The Bourne shell can be used instead of init if we are
826	 * trying to recover a really broken machine.
827	 */
828	if (execute_command) {
829		run_init_process(execute_command);
830		printk(KERN_WARNING "Failed to execute %s.  Attempting "
831					"defaults...\n", execute_command);
832	}
833	run_init_process("/sbin/init");
834	run_init_process("/etc/init");
835	run_init_process("/bin/init");
836	run_init_process("/bin/sh");
837
838	panic("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{
796	argv_init[0] = init_filename;
797	kernel_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}
199
200static 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;
107
108    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
109        sync();
110
111    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
112        remount_ro();
113
114    switch (cmd) {
115        case ANDROID_RB_RESTART:
116            ret = reboot(RB_AUTOBOOT);
117            break;
118
119        case ANDROID_RB_POWEROFF:
120            ret = reboot(RB_POWER_OFF);
121            break;
122
123        case ANDROID_RB_RESTART2:
124            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
125                           LINUX_REBOOT_CMD_RESTART2, arg);
126            break;
127
128        default:
129            ret = -1;
130    }
131
132    return ret;
133}

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

28#include <unistd.h>
29#include <sys/reboot.h>
30
31int 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/sh
echo "I am myclose.sh open"
./system/bin/vibrator_test
echo "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上面就好,相当的美妙。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值