• android L 关机流程图


    下面是简单的流程图,从Java到kernel层。

    ShutdownThread.java文件

    stop playing music,因为后面可能要playing shutdown music.

    代码如下:(我在Android6.0上沒有看到調用requestAudioFocus的代碼)

    复制代码
        private static void beginShutdownSequence(Context context) {  
          ....  
                //acquire audio focus to make the other apps to stop playing muisc  
                mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);  
                mAudioManager.requestAudioFocus(null,  
                        AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);  
    复制代码

    show system dialog to indicate phone is shutting down,如果没有关机动画的话,要show一个关机提示出来。

    代码如下:

    复制代码
     1     if (!checkAnimationFileExist()) {  
     2         // throw up an indeterminate system dialog to indicate radio is  
     3         // shutting down.  
     4         ProgressDialog pd = new ProgressDialog(context);  
     5         pd.setTitle(context.getText(com.android.internal.R.string.power_off));  
     6         pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));  
     7         pd.setIndeterminate(true);  
     8         pd.setCancelable(false);  
     9         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
    10       
    11         pd.show();  
    12     }  
    复制代码

    Hold the wakelock,make sure we never fall asleep again,抓锁防止机器关机过程中休眠

    代码如下:

    1     sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(  
    2             PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");//这个只是锁住cpu不进入休眠,但screen是off的,需full锁来保证screen常亮  
    3     sInstance.mCpuWakeLock.setReferenceCounted(false);  
    4     sInstance.mCpuWakeLock.acquire();  

    make sure the screen stays on,再抓一个full锁,防止屏幕半暗

    代码如下:

    1     sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(  
    2             PowerManager.FULL_WAKE_LOCK, TAG + "-screen");//保持srceen常亮  
    3     sInstance.mScreenWakeLock.setReferenceCounted(false);  
    4     sInstance.mScreenWakeLock.acquire();  

    sending shutdown broadcast,发出广播,通知各app该保存数据赶紧的,我要关机了

    代码如下:

    1     Intent intent = new Intent(Intent.ACTION_SHUTDOWN);  
    2     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);  
    3     mContext.sendOrderedBroadcastAsUser(intent,//发广播  
    4             UserHandle.ALL, null, br, mHandler, 0, null, null);  

     shutdown activity manager,关闭activity manager,即关闭AppOpsService,UsageStatsService,BatteryStatsService

    注意:Android L 与KK在关闭UsageStatsService上有所区别

    代码如下:

    [ActivityManagerService.java]

    复制代码
    1     final IActivityManager am =  
    2                 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));  
    3             if (am != null) {  
    4                 try {  
    5                     am.shutdown(MAX_BROADCAST_TIME);  
    6                 } catch (RemoteException e) {  
    7                 }  
    8             }  
    复制代码

    shutdown package manager,保存app使用时间到 disk里,这是android L新增的功能。

    代码如下:

    [PackageManagerService.java]

    1     final PackageManagerService pm = (PackageManagerService)  
    2         ServiceManager.getService("package");  
    3     if (pm != null) {  
    4         pm.shutdown();  
    5     }  

     show shutdown animation,播放关机动画了

    代码如下:

    复制代码
     1     private static void showShutdownAnimation() {  
     2         /* 
     3          * When boot completed, "service.bootanim.exit" property is set to 1. 
     4          * Bootanimation checks this property to stop showing the boot animation. 
     5          * Since we use the same code for shutdown animation, we 
     6          * need to reset this property to 0. If this is not set to 0 then shutdown 
     7          * will stop and exit after displaying the first frame of the animation 
     8          */  
     9         SystemProperties.set("service.bootanim.exit", "0");  
    10       
    11         SystemProperties.set("ctl.start", "bootanim");//也是用bootanim进程,跟开关动画一样的方式。  
    12     }  
    复制代码

    shutdown radio[NFC,BT,MODEM],注意这里关闭modem这块与andorid KK的不一样。

    代码如下:

    shutdownRadios(MAX_RADIO_WAIT_TIME);

     
    shutdown MountService,特别这里会导致关机失败。

    代码如下:

    复制代码
     1     // Set initial variables and time out time.  
     2     mActionDone = false;  
     3     final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;  
     4     synchronized (mActionDoneSync) {  
     5         try {  
     6             final IMountService mount = IMountService.Stub.asInterface(  
     7                     ServiceManager.checkService("mount"));  
     8             if (mount != null) {  
     9                 mount.shutdown(observer);  
    10             } else {  
    11                 Log.w(TAG, "MountService unavailable for shutdown");  
    12             }  
    13         } catch (Exception e) {  
    14             Log.e(TAG, "Exception during MountService shutdown", e);  
    15         }  
    16         while (!mActionDone) {  
    17             long delay = endShutTime - SystemClock.elapsedRealtime();  
    18             if (delay <= 0) {  
    19                 Log.w(TAG, "Shutdown wait timed out");  
    20                 break;  
    21             }  
    22             try {  
    23                 mActionDoneSync.wait(delay);  
    24             } catch (InterruptedException e) {  
    25             }  
    26         }  
    27     }  
    复制代码

    走完上层关机流程,下面就要执行关机动作了。

    代码如下:

    复制代码
     1     public static void rebootOrShutdown(boolean reboot, String reason) {  
     2         deviceRebootOrShutdown(reboot, reason);  
     3         if (reboot) {  
     4             Log.i(TAG, "Rebooting, reason: " + reason);  
     5             PowerManagerService.lowLevelReboot(reason);//重启, 其中reason字符串可以爲空、“bootloader”、“recovery”, 在手機下次啓動中LK會根據這些值使手機進入不同的模式
     6             Log.e(TAG, "Reboot failed, will attempt shutdown instead");  
     7         } else if (SHUTDOWN_VIBRATE_MS > 0) {  
     8             // vibrate before shutting down  
     9             Vibrator vibrator = new SystemVibrator();  
    10             try {  
    11                 vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);  
    12             } catch (Exception e) {  
    13                 // Failure to vibrate shouldn't interrupt shutdown.  Just log it.  
    14                 Log.w(TAG, "Failed to vibrate during shutdown.", e);  
    15             }  
    16       
    17             // vibrator is asynchronous so we need to wait to avoid shutting down too soon.  
    18             try {  
    19                 Thread.sleep(SHUTDOWN_VIBRATE_MS);  
    20             } catch (InterruptedException unused) {  
    21             }  
    22         }  
    23       
    24         // Shutdown power  
    25         Log.i(TAG, "Performing low-level shutdown...");  
    26         PowerManagerService.lowLevelShutdown();//关机  
    27     }  
    复制代码

     从代码上看始终会走到lowLevelShutdown(),但如果是重启就不会,lowLevelReboot()就停止了。

    lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,其实都只是设置一个属性:SystemProperties.set("sys.powerctl", "xxx");

    正是这个动作触发关机流程往下走,这涉及到init进程的4大功能,请参考我的另一篇文章Android的init进程

    sys.powerctl属性触发开关在init.rc定义

        on property:sys.powerctl=*  
            powerctl ${sys.powerctl}  

     我们来解读这句话,on property:sys.powerctl=*表示当属性sys.powerctl设置为任何值是都会跑到这里,触发动作是powerctl ${sys.powerctl},这个动作的意思是调用powerctl指令,并把sys.powerctl的值传给它。powerctl指令在init 进程会执行。

    从下面的表可知,powerctl对应的操作是do_powerctl

    [system/core/init/keywords.h]

    KEYWORD(powerctl,    COMMAND, 1, do_powerctl)  

     
    do_powerctl的实现

    代码如下:

    [system/core/init/builtins.c]

    复制代码
     1 int do_powerctl(int nargs, char **args)
     2 {
     3     char command[PROP_VALUE_MAX];
     4     int res;
     5     int len = 0;
     6     int cmd = 0;
     7     const char *reboot_target;
     8 
     9     res = expand_props(command, args[1], sizeof(command));  //args中存放的是: shutdown 或者 reboot 或者 reboot,bootloader 或者 reboot,recovery
    10     if (res) {
    11         ERROR("powerctl: cannot expand '%s'
    ", args[1]);
    12         return -EINVAL;
    13     }
    14 
    15     if (strncmp(command, "shutdown", 8) == 0) {
    16         cmd = ANDROID_RB_POWEROFF;
    17         len = 8;
    18     } else if (strncmp(command, "reboot", 6) == 0) {
    19         cmd = ANDROID_RB_RESTART2;
    20         len = 6;
    21     } else {
    22         ERROR("powerctl: unrecognized command '%s'
    ", command);
    23         return -EINVAL;
    24     }
    25 
    26     if (command[len] == ',') {
    27         char prop_value[PROP_VALUE_MAX] = {0};
    28         reboot_target = &command[len + 1];  // 存放reboot的reason,也就是下次手機重啓將要進入的模式
    29 
    30         if ((property_get("init.svc.recovery", prop_value) == 0) &&
    31             (strncmp(reboot_target, "keys", 4) == 0)) {
    32             ERROR("powerctl: permission denied
    ");
    33             return -EINVAL;
    34         }
    35     } else if (command[len] == '') {  // 如果reason爲空,對於reboot來說,下次手機會正常啓機
    36         reboot_target = "";
    37     } else {
    38         ERROR("powerctl: unrecognized reboot target '%s'
    ", &command[len]);
    39         return -EINVAL;
    40     }
    41 
    42     return android_reboot(cmd, 0, reboot_target);
    43 }
    复制代码

    它调用android_reboot()函数,实现如下:

    [system/core/libcutils/android_reboot.c]

    复制代码
     1 int android_reboot(int cmd, int flags UNUSED, const char *arg)
     2 {
     3     int ret;
     4 
     5     sync();
     6     remount_ro();
     7 
     8     switch (cmd) {
     9         case ANDROID_RB_RESTART:
    10             ret = reboot(RB_AUTOBOOT);
    11             break;
    12 
    13         case ANDROID_RB_POWEROFF:
    14             ret = reboot(RB_POWER_OFF);
    15             break;
    16 
    17         case ANDROID_RB_RESTART2:  // arg中存放的是reboot的reason,如bootloader、recovery
    18             ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
    19                            LINUX_REBOOT_CMD_RESTART2, arg);
    20             break;
    21 
    22         default:
    23             ret = -1;
    24     }
    25 
    26     return ret;
    27 }
    复制代码

     
    从这里看出它的主要工作:

    sync() 回写block设备的内容,这是阻塞型操作。

    remount_ro() 把block设备remount成ro,这里有个关键LOG:SysRq : Emergency Remount R/O,这是在logkit所能看到的最后一句LOG,因为remount成ro了,后面的LOG要通过last kmsg技术导出来。

    reboot()或者syscall(__NR_reboot....,这点与android KK不同,这边直接用syscall功能,KK则通过汇编。

    后面syscall(__NR_reboot...知道,直接调用了linux的__NR_reboot系统调用,这个系统调用会跑哪里?后面会讲。

    reboot()这个函数实现如下:

    [bionic/libc/bionic/reboot.cpp]

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

     
    调用了__reboot,它在汇编实现 如下:

    [bionic/libc/arch-arm/syscalls/__reboot.S]

    复制代码
     1     ENTRY(__reboot)  
     2         mov     ip, r7  
     3         ldr     r7, =__NR_reboot      //也跑到__NR_reboot系统调用  
     4         swi     #0  
     5         mov     r7, ip  
     6         cmn     r0, #(MAX_ERRNO + 1)  
     7         bxls    lr  
     8         neg     r0, r0  
     9         b       __set_errno_internal  
    10     END(__reboot)  
    复制代码

    __NR_reboot对应的内核入口在哪里?

    如下:

    [bionic/libc/kernel/uapi/asm-generic/unistd.h]

        #define __NR_reboot 142  

     它在内核入口如下:

    注:bionic/libc/kernel/uapi/asm-generic/unistd.h与kernel/include/uapi/asm-generic/unistd.h是对应的,方便以后代码追踪

    [kernel/include/uapi/asm-generic/unistd.h]

    1     #define __NR_reboot 142  
    2     __SYSCALL(__NR_reboot, sys_reboot)  

     __NR_reboot 映射到 sys_reboot

    grep 下sys_reboot 找不到,其实在这里

    用SYSCALL_DEFINE定义

    [kernel/kernel/reboot.c]

    复制代码
     1 /*
     2  * Reboot system call: for obvious reasons only root may call it,
     3  * and even root needs to set up some magic numbers in the registers
     4  * so that some mistake won't make this reboot the whole machine.
     5  * You can also set the meaning of the ctrl-alt-del-key here.
     6  *
     7  * reboot doesn't sync: do that yourself before calling this.
     8  */
     9 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
    10         void __user *, arg)
    11 {
    12     struct pid_namespace *pid_ns = task_active_pid_ns(current);
    13     char buffer[256];
    14     int ret = 0;
    15 
    16     /* We only trust the superuser with rebooting the system. */
    17     if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
    18         return -EPERM;
    19 
    20     /* For safety, we require "magic" arguments. */
    21     if (magic1 != LINUX_REBOOT_MAGIC1 ||
    22             (magic2 != LINUX_REBOOT_MAGIC2 &&
    23             magic2 != LINUX_REBOOT_MAGIC2A &&
    24             magic2 != LINUX_REBOOT_MAGIC2B &&
    25             magic2 != LINUX_REBOOT_MAGIC2C))
    26         return -EINVAL;
    27 
    28     /*
    29      * If pid namespaces are enabled and the current task is in a child
    30      * pid_namespace, the command is handled by reboot_pid_ns() which will
    31      * call do_exit().
    32      */
    33     ret = reboot_pid_ns(pid_ns, cmd);
    34     if (ret)
    35         return ret;
    36 
    37     /* Instead of trying to make the power_off code look like
    38      * halt when pm_power_off is not set do it the easy way.
    39      */
    40     if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
    41         cmd = LINUX_REBOOT_CMD_HALT;
    42 
    43     mutex_lock(&reboot_mutex);
    44     switch (cmd) {
    45     case LINUX_REBOOT_CMD_RESTART:
    46         kernel_restart(NULL);
    47         break;
    48 
    49     case LINUX_REBOOT_CMD_CAD_ON:
    50         C_A_D = 1;
    51         break;
    52 
    53     case LINUX_REBOOT_CMD_CAD_OFF:
    54         C_A_D = 0;
    55         break;
    56 
    57     case LINUX_REBOOT_CMD_HALT:
    58         kernel_halt();
    59         do_exit(0);
    60         panic("cannot halt");
    61 
    62     case LINUX_REBOOT_CMD_POWER_OFF:
    63         kernel_power_off();
    64         do_exit(0);
    65         break;
    66 
    67     case LINUX_REBOOT_CMD_RESTART2:
    68         ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
    69         if (ret < 0) {
    70             ret = -EFAULT;
    71             break;
    72         }
    73         buffer[sizeof(buffer) - 1] = '';
    74 
    75         kernel_restart(buffer);
    76         break;
    77 
    78 #ifdef CONFIG_KEXEC
    79     case LINUX_REBOOT_CMD_KEXEC:
    80         ret = kernel_kexec();
    81         break;
    82 #endif
    83 
    84 #ifdef CONFIG_HIBERNATION
    85     case LINUX_REBOOT_CMD_SW_SUSPEND:
    86         ret = hibernate();
    87         break;
    88 #endif
    89 
    90     default:
    91         ret = -EINVAL;
    92         break;
    93     }
    94     mutex_unlock(&reboot_mutex);
    95     return ret;
    96 }
    复制代码

    有很多分支,我们只关心kernel_power_off()和kernel_restart()两函数就行

    如下:

    kernel_power_off:

    复制代码
     1     void kernel_power_off(void)  
     2     {  
     3         kernel_shutdown_prepare(SYSTEM_POWER_OFF);//关闭外设  
     4         if (pm_power_off_prepare)  
     5             pm_power_off_prepare();   
     6         migrate_to_reboot_cpu();   // 比如執行reboot命令的進程運行在CPU1上,而將來CPU1會先於CPU0被停止,故需要將當前進程轉移至CPU0上
     7         syscore_shutdown();//关闭syscore  
     8         printk(KERN_EMERG "Power down.
    ");//关键打印  
     9         kmsg_dump(KMSG_DUMP_POWEROFF);  
    10         machine_power_off();  
    11     }  
    复制代码

    kernel_restart:

    复制代码
     1     void kernel_restart(char *cmd)  
     2     {  
     3         kernel_restart_prepare(cmd);//关闭外设  
     4         migrate_to_reboot_cpu();  
     5         syscore_shutdown();//关闭syscore  
     6         if (!cmd)  
     7             printk(KERN_EMERG "Restarting system.
    ");//关键打印  
     8         else  
     9             printk(KERN_EMERG "Restarting system with command '%s'.
    ", cmd);  
    10         kmsg_dump(KMSG_DUMP_RESTART);  
    11         machine_restart(cmd);  
    12     }  
    复制代码

    都执行XX_prepare()函数

    复制代码
    1     static void kernel_shutdown_prepare(enum system_states state)  
    2     {  
    3         blocking_notifier_call_chain(&reboot_notifier_list,  
    4             (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);  
    5         system_state = state;  
    6         usermodehelper_disable();  
    7         device_shutdown();  
    8     }  
    复制代码

     上面的第3行會遍歷reboot_notifier_list鏈表,向其中註冊的每一個notifier_block發送SYS_POWER_OFF事件。

    在我們的驅動程序中可以調用如下函數將notifier_block註冊到系統中:

    复制代码
     1 /**
     2  *    register_reboot_notifier - Register function to be called at reboot time
     3  *    @nb: Info about notifier function to be called
     4  *
     5  *    Registers a function with the list of functions
     6  *    to be called at reboot time.
     7  *
     8  *    Currently always returns zero, as blocking_notifier_chain_register()
     9  *    always returns zero.
    10  */
    11 int register_reboot_notifier(struct notifier_block *nb)
    12 {
    13     return blocking_notifier_chain_register(&reboot_notifier_list, nb);
    14 }
    15 EXPORT_SYMBOL(register_reboot_notifier);
    复制代码

    在第7行中調用了device_shutdown()函數,如下:

    复制代码
     1 /**
     2  * device_shutdown - call ->shutdown() on each device to shutdown.
     3  */
     4 void device_shutdown(void)
     5 {
     6     struct device *dev, *parent;
     7 
     8     spin_lock(&devices_kset->list_lock);
     9     /*
    10      * Walk the devices list backward, shutting down each in turn.
    11      * Beware that device unplug events may also start pulling
    12      * devices offline, even as the system is shutting down.
    13      */
    14     while (!list_empty(&devices_kset->list)) {
    15         dev = list_entry(devices_kset->list.prev, struct device,
    16                 kobj.entry);
    17                 ......
    18 
    19         if (dev->bus && dev->bus->shutdown) {   // 如 i2c_bus_type
    20             if (initcall_debug)
    21                 dev_info(dev, "shutdown
    ");
    22             dev->bus->shutdown(dev);
    23         } else if (dev->driver && dev->driver->shutdown) {  // 如spi_bus_type、usb_bus_type
    24             if (initcall_debug)
    25                 dev_info(dev, "shutdown
    ");
    26             dev->driver->shutdown(dev);
    27         }
    28                 ......
    29     }
    30     spin_unlock(&devices_kset->list_lock);
    31 }
    32                         
    复制代码

    kernel_restart_prepare:

    复制代码
    1     void kernel_restart_prepare(char *cmd)  
    2     {  
    3         blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);  
    4         system_state = SYSTEM_RESTART;  
    5         usermodehelper_disable();  
    6         device_shutdown();  
    7     }  
    复制代码

    除了前面不同,都调用了device_shutdown()函数,关闭外设。

    machine_power_off() machine_resestart()函数实现

    machine_power_off:

    复制代码
    1     void machine_power_off(void)  
    2     {  
    3         preempt_disable();  
    4         smp_send_stop();  
    5       
    6         if (pm_power_off)  
    7             pm_power_off();//关机  
    8     }  
    复制代码

     其中,第4行的smp_send_stop會將除CPU0之外的CPU全部stop。
     

    machine_restart:

    复制代码
     1     void machine_restart(char *cmd)  
     2     {  
     3         preempt_disable();  
     4         smp_send_stop();  
     5       
     6         /* Flush the console to make sure all the relevant messages make it 
     7          * out to the console drivers */  
     8         arm_machine_flush_console();  
     9       
    10         arm_pm_restart(reboot_mode, cmd);//重启  
    11       
    12         /* Give a grace period for failure to restart of 1s */  
    13         mdelay(1000);  
    14       
    15         /* Whoops - the platform was unable to reboot. Tell the user! */  
    16         printk("Reboot failed -- System halted
    ");  
    17         local_irq_disable();  
    18         while (1);  
    19     }  
    复制代码

    pm_power_offf() arm_pm_restart()都是一个函数指针

    赋值如下:

    [kernel/drivers/power/reset/msm-poweroff.c]

    1     pm_power_off = do_msm_poweroff;  
    2     arm_pm_restart = do_msm_restart;  

    高通平台的关机代码与之前有所不同,现在文件msm-poweroff.c以前是restart.c。

    do_msm_poweroff()与do_msm_restart()实现如下:

    do_msm_poweroff:

    复制代码
     1     static void do_msm_poweroff(void)  
     2     {  
     3     ....  
     4         pr_notice("Powering off the SoC
    ");//关键打印  
     5     #ifdef CONFIG_MSM_DLOAD_MODE  
     6         set_dload_mode(0);//关机,所以dloadmode是0  
     7     #endif  
     8         qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);//配置PMIC,是关机  
     9     .....  
    10         /* MSM initiated power off, lower ps_hold */  
    11         __raw_writel(0, msm_ps_hold);//拉 PS_HOLD,执行关机动作。  
    12       
    13         mdelay(10000);  
    14         pr_err("Powering off has failed
    ");  
    15         return;  
    16     }  
    复制代码

    do_msm_restart:

     
    复制代码
     1     static void msm_restart_prepare(const char *cmd)  
     2     {  
     3     #ifdef CONFIG_MSM_DLOAD_MODE  
     4       
     5         /* Write download mode flags if we're panic'ing 
     6          * Write download mode flags if restart_mode says so 
     7          * Kill download mode if master-kill switch is set 
     8          */  
     9       
    10         set_dload_mode(download_mode &&  
    11                 (in_panic || restart_mode == RESTART_DLOAD));//设置dload  
    12     #endif  
    13       
    14         /* Hard reset the PMIC unless memory contents must be maintained. */  
    15         if (get_dload_mode() || (cmd != NULL && cmd[0] != ''))  
    16             qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);//设置PIMC为热重启  
    17         else  
    18             qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);//设置PIMC为硬重启  
    19       
    20         if (cmd != NULL) {  
    21             if (!strncmp(cmd, "bootloader", 10)) {  
    22                 __raw_writel(0x77665500, restart_reason);//写一些东东到IMEM,用于bootloader,recovery等  
    23             } else if (!strncmp(cmd, "recovery", 8)) {  
    24                 __raw_writel(0x77665502, restart_reason);  
    25             } else if (!strcmp(cmd, "rtc")) {  
    26                 __raw_writel(0x77665503, restart_reason);  
    27             } else if (!strncmp(cmd, "oem-", 4)) {  
    28                 unsigned long code;  
    29                 int ret;  
    30                 ret = kstrtoul(cmd + 4, 16, &code);  
    31                 if (!ret)  
    32                     __raw_writel(0x6f656d00 | (code & 0xff),  
    33                              restart_reason);  
    34             } else if (!strncmp(cmd, "edl", 3)) {  
    35                 enable_emergency_dload_mode();  
    36             } else {  
    37                 __raw_writel(0x77665501, restart_reason);  
    38             }  
    39         }  
    40       
    41     .....  
    42       
    43     }  
    复制代码

    do_msm_poweroff()与do_msm_restart()都设置了dload,PMIC,唯一不同的是do_msm_restart()里 多了一个__raw_writel的动作,即reason写入IMEM,目的在于重启进入sbl1时判断应该进入那种模式,如我们开发用的 bootloader模式,恢复出厂设置的recovery模式等。


    完了 

  • 相关阅读:
    java_web连接SQL_server详细步骤
    探索需求-设计前的质量之二
    EF三种编程方式详细图文教程(C#+EF)之Code First
    EF三种编程方式详细图文教程(C#+EF)之Model First
    EF三种编程方式详细图文教程(C#+EF)之Database First
    探索需求-设计前的质量之一
    编写有效用例之三
    编写有效用例之二
    golang 环境安装
    golang 命令详解
  • 原文地址:https://www.cnblogs.com/zhangyubao/p/7016980.html
Copyright © 2020-2023  润新知