日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android L 关机流程图

發布時間:2025/5/22 编程问答 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android L 关机流程图 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載: http://blog.csdn.net/hovan/article/details/42495379

?

下面是簡單的流程圖,從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'\n", 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'\n", 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\n"); 33 return -EINVAL; 34 } 35 } else if (command[len] == '\0') { // 如果reason爲空,對於reboot來說,下次手機會正常啓機 36 reboot_target = ""; 37 } else { 38 ERROR("powerctl: unrecognized reboot target '%s'\n", &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] = '\0'; 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.\n");//關鍵打印 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.\n");//關鍵打印 8 else 9 printk(KERN_EMERG "Restarting system with command '%s'.\n", 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\n"); 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\n"); 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\n"); 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\n");//關鍵打印 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\n"); 15 return; 16 }

do_msm_restart:

1 static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) 2 ... 3 4 pr_notice("Going down for restart now\n");//關鍵打印 5 6 msm_restart_prepare(cmd);//重啟準備前動作 7 8 #ifdef CONFIG_MSM_DLOAD_MODE 9 /* 10 * Trigger a watchdog bite here and if this fails, 11 * device will take the usual restart path. 12 */ 13 14 if (WDOG_BITE_ON_PANIC && in_panic) 15 msm_trigger_wdog_bite(); 16 #endif 17 18 .... 19 halt_spmi_pmic_arbiter(); 20 __raw_writel(0, msm_ps_hold);//拉PS_HOLD重啟 21 22 mdelay(10000); 23 }

?
msm_restart_prepare()實現

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] != '\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模式等。


完了

總結

以上是生活随笔為你收集整理的android L 关机流程图的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。