前面已经讲到了lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,都只是设置一个属性:SystemProperties.set(sys.powerctl, xxx);这里从这继续往下讲:
sys.powerctl属性触发开关在init.rc定义:
on property:sys.powerctl=*
powerctl ${sys.powerctl}
从下面的表可知,powerctl对应的操作是do_powerctl
[system/core/init/keywords.h]
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
794 int do_powerctl(int nargs, char **args)
795 {
796 char command[PROP_VALUE_MAX];
797 int res;
798 int len = 0;
799 int cmd = 0;
800 char *reboot_target;
801
802 res = expand_props(command, args[1], sizeof(command));
803 if (res) {
804 ERROR("powerctl: cannot expand '%s'\n", args[1]);
805 return -EINVAL;
806 }
807
808 if (strncmp(command, "shutdown", 8) == 0) {
809 cmd = ANDROID_RB_POWEROFF;
810 len = 8;
811 } else if (strncmp(command, "reboot", 6) == 0) {
812 cmd = ANDROID_RB_RESTART2;
813 len = 6;
814 } else {
815 ERROR("powerctl: unrecognized command '%s'\n", command);
816 return -EINVAL;
817 }
818
819 if (command[len] == ',') {
820 reboot_target = &command[len + 1];
821 } else if (command[len] == '\0') {
822 reboot_target = "";
823 } else {
824 ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
825 return -EINVAL;
826 }
827
828 return android_reboot(cmd, 0, reboot_target);
829 }
可以看到最后其调用的是android_reboot()函数,其实现如下:
107 int android_reboot(int cmd, int flags UNUSED, char *arg)
108 {
109 int ret;
110
111 sync();
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 = syscall(__NR_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 }
可以看到如果是系统关机会走ANDROID_RB_POWEROFF分支,而重启则会走ANDROID_RB_RESTART2分支,sync() 回写block设备的内容,这是阻塞型操作;remount_ro() 把block设备remount成ro,这里有个关键LOG:SysRq : Emergency Remount R/O,这是在logkit所能看到的最后一句LOG,因为remount成ro了,后面的LOG要通过last kmsg技术导出来。syscall(__NR_reboot....直接调用了linux的__NR_reboot系统调用,这点与android KK不同,这边直接用syscall功能,KK则通过汇编。先看看reboot()的实现代码:
[bionic/libc/bionic/reboot.cpp]
32 extern "C" int __reboot(int, int, int, void*);
33
34 int reboot(int mode) {
35 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
36 }
3 #include <private/bionic_asm.h>
4
5 ENTRY(__reboot)
6 mov ip, r7
7 ldr r7, =__NR_reboot //也用到了__NR_reboot系统调用
8 swi #0
9 mov r7, ip
10 cmn r0, #(MAX_ERRNO + 1)
11 bxls lr
12 neg r0, r0
13 b __set_errno_internal
14 END(__reboot)
[bionic/libc/kernel/uapi/asm-generic/unistd.h]
221 #define __NR_reboot 142
来看看kernel下的[kernel/include/uapi/asm-generic/unistd.h]
422 #define __NR_reboot 142
423 __SYSCALL(__NR_reboot, sys_reboot)
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
void __user *arg);
sys_reboot而最后的定义是在kernel/kernel/sys.c中
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg){
struct pid_namespace *pid_ns = task_active_pid_ns(current);
char buffer[256];
int ret = 0;
printk(KERN_EMERG "[shutdown_debug] enter reboot syscall.\n");
/* We only trust the superuser with rebooting the system. */
if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) {
printk(KERN_EMERG "[shutdown_debug] ns_capable return,pid_ns->user_ns=0x%x.\n",pid_ns->user_ns);
return -EPERM;
}
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
magic2 != LINUX_REBOOT_MAGIC2A &&
magic2 != LINUX_REBOOT_MAGIC2B &&
magic2 != LINUX_REBOOT_MAGIC2C)) {
printk(KERN_EMERG "[shutdown_debug] magic return.magic1=%d,magic2=%d\n",magic1,magic2);
return -EINVAL;
}
/*
* If pid namespaces are enabled and the current task is in a child
* pid_namespace, the command is handled by reboot_pid_ns() which will
* call do_exit().
*/
ret = reboot_pid_ns(pid_ns, cmd);
if (ret) {
printk(KERN_EMERG "[shutdown_debug] reboot_pid_ns return,ret=%d.\n",ret);
return ret;
}
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&reboot_mutex);
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
ret = -EFAULT;
break;
}
buffer[sizeof(buffer) - 1] = '\0';
kernel_restart(buffer);
break;
#ifdef CONFIG_KEXEC
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
mutex_unlock(&reboot_mutex);
printk(KERN_EMERG "[shutdown_debug] exit reboot syscall.\n");
return ret;
}
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...) \
SYSCALL_METADATA(sname, x, __VA_ARGS__) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
__MAP(x,__SC_TEST,__VA_ARGS__); \
__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
return ret; \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
这个函数有很多分支,我们只关心kernel_power_off()和kernel_restart()两函数就行:
void kernel_power_off(void)
{
printk(KERN_EMERG "[shutdown_debug] enter kernel_power_off.\n");
kernel_shutdown_prepare(SYSTEM_POWER_OFF); //关闭外设
if (pm_power_off_prepare)
pm_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown(); //关闭syscore
printk(KERN_EMERG "Power down.\n");//关键打印
kmsg_dump(KMSG_DUMP_POWEROFF);
machine_power_off();
printk(KERN_EMERG "[shutdown_debug] exit kernel_power_off.\n");
}
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);//关闭外设
migrate_to_reboot_cpu();
syscore_shutdown();//关闭syscore
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");//关键打印
else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
kmsg_dump(KMSG_DUMP_RESTART);
preempt_disable();
machine_restart(cmd);
}
static void kernel_shutdown_prepare(enum system_states state)
{
printk(KERN_EMERG "[shutdown_debug] enter kernel_shutdown_prepare.\n");
blocking_notifier_call_chain(&reboot_notifier_list,
(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
system_state = state;
usermodehelper_disable();
device_shutdown();
printk(KERN_EMERG "[shutdown_debug] exit kernel_shutdown_prepare.\n");
}
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
usermodehelper_disable();
device_shutdown();
}
machine_power_off() machine_resestart()函数实现:
void machine_power_off(void)
{
smp_send_stop();
if (pm_power_off)
pm_power_off();//关机
}
void machine_restart(char *cmd)
{
smp_send_stop();
/* Flush the console to make sure all the relevant messages make it
* out to the console drivers */
arm_machine_flush_console();
arm_pm_restart(reboot_mode, cmd);//重启
/* Give a grace period for failure to restart of 1s */
mdelay(1000);
/* Whoops - the platform was unable to reboot. Tell the user! */
printk("Reboot failed -- System halted\n");
local_irq_disable();
while (1);
}
pm_power_offf() arm_pm_restart()都是一个函数指针,他们的复制,根据厂家的不同而不同,SPRD,mediatek,msm三家各有各的操作,这里是SPRD,其赋值位于kernel/drivers/platform/sprd/Pm-scx35.c:
void __init sc_pm_init(void)
{
init_reset_vector();
pm_power_off = sc8830_power_off;
arm_pm_restart = sc8830_machine_restart;
pr_info("power off %pf, restart %pf\n", pm_power_off, arm_pm_restart);
init_gr();
setup_autopd_mode();
pm_ana_ldo_config();
init_led();
/* disable all sleep mode */
sci_glb_clr(REG_AP_AHB_MCU_PAUSE, BIT_MCU_DEEP_SLEEP_EN | BIT_MCU_LIGHT_SLEEP_EN | \
BIT_MCU_SYS_SLEEP_EN | BIT_MCU_CORE_SLEEP);
set_reset_vector();
#ifdef CONFIG_DDR_VALIDITY_TEST
test_memory();
#endif
#ifndef CONFIG_SPRD_PM_DEBUG
pm_debug_init();
#endif
/* enable arm clock auto gating*/
//sci_glb_set(REG_AHB_AHB_CTL1, BIT_ARM_AUTO_GATE_EN);
#ifdef CONFIG_CPU_IDLE
sc_cpuidle_init();
#endif
/*
wake_lock_init(&pm_debug_lock, WAKE_LOCK_SUSPEND, "pm_not_ready");
wake_lock(&pm_debug_lock);
*/
#if defined(CONFIG_SPRD_DEBUG)
sprd_debug_init();
#endif
}
其实现如下:
static void sc8830_power_off(void)
{
u32 reg_val;
/*turn off all modules's ldo*/
#ifdef CONFIG_SPRD_EXT_IC_POWER
sprd_extic_otg_power(0);
#endif
sci_adi_raw_write(ANA_REG_GLB_LDO_PD_CTRL, 0x1fff);
#if defined(CONFIG_ARCH_SCX15) || defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
sci_adi_raw_write(ANA_REG_GLB_PWR_WR_PROT_VALUE,BITS_PWR_WR_PROT_VALUE(0x6e7f));
do{
reg_val = (sci_adi_read(ANA_REG_GLB_PWR_WR_PROT_VALUE) & BIT_PWR_WR_PROT);
}while(reg_val == 0);
sci_adi_raw_write(ANA_REG_GLB_LDO_PD_CTRL,0xfff);
sci_adi_raw_write(ANA_REG_GLB_LDO_DCDC_PD,0x7fff);
#endif
#if defined(CONFIG_ADIE_SC2713S) || defined(CONFIG_ADIE_SC2713)
/*turn off system core's ldo*/
sci_adi_raw_write(ANA_REG_GLB_LDO_DCDC_PD_RTCCLR, 0x0);
sci_adi_raw_write(ANA_REG_GLB_LDO_DCDC_PD_RTCSET, 0X7fff);
#endif
}
static void sc8830_machine_restart(char mode, const char *cmd)
{
local_irq_disable();
local_fiq_disable();
arch_reset(mode, cmd);
mdelay(1000);
printk("reboot failed!\n");
while (1);
}