(android 关机/重启)Android关机/重启流程解析 (2)-----实例解析(多种实现方式)

来源:互联网 发布:java基础教程 pdf 编辑:程序博客网 时间:2024/05/29 15:24

介入方法1(java)接口java实现的方式


--------------------------------上层空间--------------------------------

1.frameworks/base/core/java/android/os/PowerManager.java

////在PowerManager的API文档中,给出了一个关机/重启接口:

        public void reboot (String reason)

////接口的作用就是重启设备,而且,就算重启成功了也没有返回值。

                    需要包含REBOOT权限,也就是android.permission.REBOOT

                    唯一参数reason代表需要的特定重启模式,比如recovery,当然也可以为null



介入方法2(java)接口:java实现的方式

(adb:    adb shell setprop sys.powerctl  reboot,handoff_resolution_enable)

SystemProperties.set("ctl.start", "shutdown");///关机

&& SystemProperties.set("sys.powerctl", "reboot," + reason);///重启

((具体实现例子详见附页2))

4.frameworks/base/services/java/com/android/server/pm/ShutdownThread.java

public static void rebootOrShutdown(boolean reboot, String reason) {
        if (reboot) {
            Log.i(TAG, "Rebooting, reason: " + reason);
            if ( (reason != null) && reason.equals("recovery") ) {
                delayForPlayAnimation();
            }
            try {
                PowerManagerService.lowLevelReboot(reason);
            } catch (Exception e) {
                Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
            }
        } else if (SHUTDOWN_VIBRATE_MS > 0) {
            // vibrate before shutting down
            Vibrator vibrator = new SystemVibrator();
            try {
                vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
            } catch (Exception e) {
                // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
                Log.w(TAG, "Failed to vibrate during shutdown.", e);
            }

            // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
            try {
                Thread.sleep(SHUTDOWN_VIBRATE_MS);
            } catch (InterruptedException unused) {
            }
        }

        delayForPlayAnimation();
        // Shutdown power
        // power off auto test, don't modify
        Log.i(TAG, "Performing low-level shutdown...");
        //PowerManagerService.lowLevelShutdown();////已经注释掉了
        //add your func: HDMI off
        //add for MFR
        try {
            if (ImHDMI == null)
                ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        ImHDMI.hdmiPowerEnable(false);

        //unmout data/cache partitions while performing shutdown

        SystemProperties.set("ctl.start", "shutdown");////直接关机shutdown操作

        /* sleep for a long time, prevent start another service */
        try {
            Thread.currentThread().sleep(Integer.MAX_VALUE);
        } catch ( Exception e) {
            Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");
        }
    }


}


public static void lowLevelShutdown() {
        SystemProperties.set("sys.powerctl", "shutdown");////直接关机
    }

    /**
     * Low-level function to reboot the device. On success, this function
     * doesn't return. If more than 5 seconds passes from the time,
     * a reboot is requested, this method returns.
     *
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     */
    public static void lowLevelReboot(String reason){
        if (reason == null) {
            reason = "";
        }
        SystemProperties.set("sys.powerctl", "reboot," + reason);///重启
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

【注解:】

        关机流程中最后是通过修改Android属性进行关机操作(SystemProperties.java通过JNI调用访问系统属性)。

        当然我们也可以通过adb命令修改Android系统属性执行关机操作,例如adb shell setpro sys.powerctl shutdown。

         这里我们简单介绍下修改Android属性关机的原理或流程。

native_set()<SystemProperties.java>--->SystemProperties_set()<android_os_SystemProperties.cpp>

这是SystemProperties.java类中设置系统函数的方法。



介入方法3(JNI-ndk)接口java实现的方式

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


  1. static JNINativeMethod gPowerManagerServiceMethods[] = {   
  2.     /* name, signature, funcPtr */  
  3.     ...  
  4.     { "nativeShutdown""()V",  
  5.             (void*) nativeShutdown },  
  6.     { "nativeReboot""(Ljava/lang/String;)V",  
  7.             (void*) nativeReboot },  
  8.     ...  
  9. };  


这两个好哥俩的实现也是在一起的:(定义如下)

  1. static void nativeShutdown(JNIEnv *env, jobject clazz) {  
  2.     android_reboot(ANDROID_RB_POWEROFF, 0, 0);  ////直接关机
  3. }  
  4.  
  1. static void nativeReboot(JNIEnv *env, jobject clazz, jstring reason) {  
  2.     if (reason == NULL) {  
  3.         android_reboot(ANDROID_RB_RESTART, 0, 0);  //////无reboot reason的重启
  4.     } else {  
  5.         const char *chars = env->GetStringUTFChars(reason, NULL);  
  6.         android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars); //////有reboot reason的重启
  7.         env->ReleaseStringUTFChars(reason, chars);  // In case it fails.  
  8.     }  
  9.     jniThrowIOException(env, errno);  

可以看到无论是关机还是重启,都是调用android_reboot来实现的,只是参数不一样而已。

6.system/core/libcutils/android_reboot.c

      int android_reboot(int cmd, int flags, char *arg)
{
    int ret;

    sync();
    remount_ro();

    switch (cmd) {
        case ANDROID_RB_RESTART://普通重启
            ret = reboot(RB_AUTOBOOT);
            break;

        case ANDROID_RB_POWEROFF://///直接关机
            ret = reboot(RB_POWER_OFF);
            break;

        case ANDROID_RB_RESTART2:
            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,///有参数的重启直接走这里
                           LINUX_REBOOT_CMD_RESTART2, arg);
            break;

        default:
            ret = -1;
    }

    return ret;
}



介入方法4(kernel)接口(或者是adb 入口方法:adb reboot  xx,etc)

(具体实现例子详见附页4)

7.bionic/libc/unistd/reboot.c   ///A:\v387-debug\my-ap\bionic\libc\bionic\reboot.c

  1. int reboot (int  mode)   
  2. {  
  3.     return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );  

--------------------------------KERNEL域--------------------------------

8.__reboot通过syscall来到内核

这里用一些篇幅简要介绍syscall,以后遇到类似的东西更好追踪一些。

第七步中的__reboot在arm架构的实现是这样的(bionic/libc/arch-arm/syscalls/__reboot.S)

/////home/tonylau/tony-workspace/v387-debug/my-ap/bionic/libc/arch-arm/syscalls/__reboot.S


9.kernel/sys.c

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

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


SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)就是sys_reboot


。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。(以下省略......)




xx.最终调用@@@@kernel/meditek/kernel/kernel/system.c

void arch_reset(char mode, const char *cmd)

{
    char reboot = 0;
    int res=0;
    struct wd_api*wd_api = NULL;
    
    res = get_wd_api(&wd_api);
    printk("arch_reset: cmd = %s\n", cmd ? : "NULL");


    if (cmd && !strcmp(cmd, "charger")) {//////
        /* do nothing */
    } else if (cmd && !strcmp(cmd, "recovery")) {/////如果传下来的字符串是recovery=>就在RTC寄存器里设置某个特定值,

                                                              当uboot里读取RTC寄存器的时候如果获取了这个特定值,那就可以起recovery这个动作了
        rtc_mark_recovery();
    } else if (cmd && !strcmp(cmd, "bootloader")){//////////
            rtc_mark_fast();    
    }
            #ifdef MTK_KERNEL_POWER_OFF_CHARGING
           else if (cmd && !strcmp(cmd, "kpoc")){ rtc_mark_kpoc(); }///////
            #endif
    else {
        reboot = 1;
    }


    if(res){
        printk("arch_reset, get wd api error %d\n",res);
    } else {
        wd_api->wd_sw_reset(reboot);
    }
}




附页2:

 private OnClickListener ButtonSetResolution = new OnClickListener(){        @Override        public void onClick(View view) {            try {                Class<?> c = Class.forName("android.os.SystemProperties");                Object object1 = c.newInstance();                java.lang.reflect.Method getmethod = c.getDeclaredMethod("get", String.class);                java.lang.reflect.Method setmethod = c.getDeclaredMethod("set", String.class, String.class);                setmethod.invoke(object1, "sys.powerctl", "reboot,handoff_resolution_enable");   ////2015-06-03                //setmethod.invoke(object1, "sys.lucid.PowerXtend.loglevel", Integer.toString(1));            } catch (Exception e) {                e.printStackTrace();            }        }    };


附页4:refer http://blog.sina.com.cn/s/blog_474928c90100zxkb.html

1、在Android源码目录中的packages/apps/下创建一个目录,例如:Hello2、编写Android.mk文件:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= shutdown.cLOCAL_MODULE:= shutdown LOCAL_PRELINK_MODULE:= falseLOCAL_SHARED_LIBRARIES:= libutilsinclude $(BUILD_EXECUTABLE)3、编写shutdown.c源文件,如下:


#include <stdio.h>#include <stdlib.h>#include <utils/Log.h>#include <sys/reboot.h>#ifndef LOG_TAG#define LOG_TAG "dxyh"#endifint main(int argc, char **argv){int retval;if ((retval = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,RB_POWER_OFF, NULL)) < 0) {LOGE("Try to shutdown the machine failed!");exit(EXIT_FAILURE);}return 0;}

<span style="color:#000000;"><span style="font-size:16px"><span style="background:none repeat scroll 0% 0% transparent">4</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">、</span><span style="font-size:16px">mm</span></span></span><span style="color:#000000;"><span style="font-size:16px"><span style="background:none repeat scroll 0% 0% transparent">5</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">、将生成的</span><span style="font-size:16px">shutdown</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">可执行程序推入到</span><span style="font-size:16px">pad</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">中的</span><span style="font-size:16px">/system/bin</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">下即可。</span></span></span><span style="color:#000000;"><span style="font-size:16px"><span style="background:none repeat scroll 0% 0% transparent">6</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">、然后就可以和其他命令一样运行了,例如</span><span style="font-size:16px">adb shell shutdown</span></span><span style="background:none repeat scroll 0% 0% transparent"><span style="font-size:16px">。</span></span></span>

0 0
原创粉丝点击