android待机流程分析
2016-10-20 14:53
996 查看
以下是amlogic 905x android6.0的待机日志
android上层通过设置环境变量去关机
直接触发init.rc去执行
do_powerctl根据cmd标记flags
用android_reboot(cmd, 0, reboot_target);执行命令
其中
关闭多核
系统没有wake_lock时,以下timer会检测执行回调:
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;
struct timespec ts_entry, ts_exit;
}
static DECLARE_WORK(suspend_work, suspend);
上层修改的对应的设备节点之后
正常时是
执行以下代码:
重点执行这个func
于是我们就看到了以上打印
表示进下如下流程:
修改标记位,执行工作队列回调
接着走
执行注册在
之后释放锁
假待机: [ 79.159234@0] request_suspend_state: sleep (0->3) at 78988163869 (2015-01-01 00:01:24.258131660 UTC) [ 79.162712@0] request_suspend_state,164,old_sleep=0,new_state=3 [ 79.168682@0] early_suspend: call handlers [ 79.201103@0] avmute set to 2 [ 79.301870@0] hdmitx: system: HDMITX: early suspend [ 79.301915@0] hdmitx: system: unmux DDC for gpio read edid [ 79.308968@0] [ 79.308968@0] vdac_enable: on:0,module_sel:8 [ 79.354569@0] fb: osd_suspended [ 79.354611@0] sysled: early suspend ok [ 79.355889@0] gxbb_pm: meson_system_early_suspend [ 79.360544@0] early_suspend: sync [ 80.080436@0] PM: suspend entry 2015-01-01 00:01:25.179274911 UTC [ 80.080994@0] PM: Syncing filesystems ... done. [ 80.110489@0] Freezing user space processes ... (elapsed 0.269 seconds) done. [ 80.380308@0] Freezing remaining freezable tasks ... (elapsed 0.003 seconds) done. [ 80.392719@0] RTL871X: suspend start [ 80.424913@0] RTL871X: nolinked power save leave [ 80.436464@0] RTL871X: rtw_cmd_thread(wlan0) stop_req:1, break [ 80.445590@0] RTL871X: rtw_dev_unload: driver not in IPS [ 80.476912@0] RTL871X: rtw_dev_unload: driver not in IPS [ 80.478154@0] RTL871X: rtw suspend success in 80 ms [ 80.614705@0] aml_snd_card: enter aml_suspend_pre [ 80.614889@0] aml_snd_card: no audio pin_ctrl to suspend [ 80.630767@0] aml_T9015_audio_suspend! [ 80.630944@0] aml_snd_card: enter aml_suspend_post [ 80.634393@0] meson_uart c11084c0.serial: pull up rts [ 80.639082@0] amvecm: suspend module [ 80.642597@0] DI: di: di_suspend [ 80.646704@0] sysled: module suspend ok [ 80.650166@0] PM: suspend of devices complete after 259.894 msecs [ 80.655553@0] gxbb_pm: enter meson_pm_prepare! [ 80.665042@0] PM: late suspend of devices complete after 5.337 msecs [ 80.682488@0] PM: noirq suspend of devices complete after 16.474 msecs [ 80.683457@0] Disabling non-boot CPUs ... [ 80.687612@0] gxbb_pm: enter meson_pm_suspend! [ 80.687612@0] gxbb_pm: late_suspend: call handlers [ 80.687612@0] gxbb_pm: late_suspend: sync bl30 get wakeup sources! process command 00000006 bl30 enter suspend! cpu clk suspend rate 100000000 suspend_counter: 1 Enter ddr suspend first time suspend ddr suspend time: 1886us store restore gp0 pll process command 00000001 CEC cfg:0x002f set vddee to 0x035cmv 089 kern log_addr:0x04 rx stat:00, tx stat:00 ping_cec_ll_tx:TX_ERROR Set cec log_addr:0x04, ADDR0:14
真待机: [ 68.214993@1] BT_RADIO going: off [ 68.215020@1] BCM_BT: going OFF [ 68.442588@0] BT_RADIO going: on [ 68.442752@0] BCM_BT: going ON [ 68.687745@1] aml_spdif_dai: aml_hw_iec958_init,runtime->rate=48000, same source mode(1) [ 68.690825@1] aml_spdif_dai: share the same clock [ 68.694954@1] aml_spdif_dai: iec958 mode PCM16 [ 68.699346@1] aml_audio_hw: IEC958 16bit [ 68.703504@1] hdmitx: audio: aout notify rate 48000 [ 68.708042@1] hdmitx: audio: aout notify size 16 [ 68.712906@1] hdmitx: audio: no update [ 68.716294@1] aml_snd_m8_card aml_m8_snd.46: i2s/958 same source [ 68.751379@1] aml_snd_m8_card aml_m8_snd.46: I2S playback enable [ 68.751759@1] aml_snd_m8_card aml_m8_snd.46: IEC958 playback enable [ 69.368257@0] meson_uart c11084c0.serial: ttyS1 use xtal(8M) 24000000 change 1500000 to 1500000 [ 69.373019@0] meson_uart c11084c0.serial: ttyS1 use xtal(8M) 24000000 change 1500000 to 1500000 [ 69.380607@0] meson_uart c11084c0.serial: ttyS1 use xtal(8M) 24000000 change 1500000 to 115200 [ 69.910159@0] meson_uart c11084c0.serial: ttyS1 use xtal(8M) 24000000 change 115200 to 1500000 [ 69.914035@0] meson_uart c11084c0.serial: ttyS1 use xtal(8M) 24000000 change 1500000 to 1500000 [ 70.874014@0] SysRq : Emergency Remount R/O [ 70.880471@1] EXT4-fs (mmcblk0p14): re-mounted. Opts: (null) [ 70.883091@1] EXT4-fs (mmcblk0p3): re-mounted. Opts: (null) [ 70.889695@1] EXT4-fs (mmcblk0p8): re-mounted. Opts: (null) [ 70.891972@1] EXT4-fs (zram0): re-mounted. Opts: (null) [ 70.904583@1] Emergency Remount complete [ 70.974799@1] avmute set to 2 [ 71.768553@0] aml_snd_m8_card aml_m8_snd.46: I2S playback disable [ 71.769016@0] aml_snd_m8_card aml_m8_snd.46: IEC958 playback disable [ 71.775430@0] aml_spdif_dai: share the same clock [ 71.779982@0] aml_audio_hw: IEC958 16bit [ 71.784033@0] hdmitx: audio: aout notify rate 48000 [ 71.788698@0] hdmitx: audio: aout notify size 16 [ 71.793337@0] hdmitx: audio: no update [ 72.101818@0] aml_snd_card: no audio pin_ctrl to shutdown [ 72.102215@0] sysled: module shutdown ok [ 72.105939@0] reboot: Power down INFO: PSCI Affinity Map: INFO: AffInst: Level 0, MPID 0x0, State ON INFO: AffInst: Level 0, MPID 0x1, State ON INFO: AffInst: Level 0, MPID 0x2, State OFF INFO: AffInst: Level 0, MPID 0x3, State OFF bl31 reboot reason: 0x108 bl31 reboot reason: 0x108 system cmd 0. bl30 get wakeup sources! process command 00000006 bl30 enter suspend! cpu clk suspend rate 1000000000 suspend_counter: 1 Enter ddr suspend first time suspend ddr suspend time: 1886us store restore gp0 pll process command 00000001 CEC cfg:0x002f set vddee to 0x035cmv 089 kern log_addr:0x04 rx stat:00, tx stat:00 ping_cec_ll_tx:TX_ERROR Set cec log_addr:0x04, ADDR0:14
android上层通过设置环境变量去关机
public static void lowLevelShutdown() { SystemProperties.set("sys.powerctl", "shutdown"); }
直接触发init.rc去执行
on property:sys.powerctl=* powerctl ${sys.powerctl}
./code/system/core/init/keywords.h:80: KEYWORD(powerctl, COMMAND, 1, do_powerctl) int do_powerctl(int nargs, char **args);
./code/system/core/init/builtins.cpp:581:int do_powerctl(int nargs, char **args)
int do_powerctl(int nargs, char **args) { char command[PROP_VALUE_MAX]; int res; int len = 0; int cmd = 0; const char *reboot_target; res = expand_props(command, args[1], sizeof(command)); if (res) { ERROR("powerctl: cannot expand '%s'\n", args[1]); return -EINVAL; } if (strncmp(command, "shutdown", 8) == 0) { cmd = ANDROID_RB_POWEROFF; len = 8; } else if (strncmp(command, "reboot", 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6; } else { ERROR("powerctl: unrecognized command '%s'\n", command); return -EINVAL; } if (command[len] == ',') { reboot_target = &command[len + 1]; } else if (command[len] == '\0') { reboot_target = ""; } else { ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]); return -EINVAL; } return android_reboot(cmd, 0, reboot_target); }
do_powerctl根据cmd标记flags
if (strncmp(command, "shutdown", 8) == 0) { cmd = ANDROID_RB_POWEROFF; len = 8; } else if (strncmp(command, "reboot", 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6;
用android_reboot(cmd, 0, reboot_target);执行命令
其中
#define ANDROID_RB_RESTART 0xDEAD0001 #define ANDROID_RB_POWEROFF 0xDEAD0002 #define ANDROID_RB_RESTART2 0xDEAD0003
int android_reboot(int cmd, int flags UNUSED, const 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 = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); break; default: ret = -1; } return ret; }
./bionic/libc/bionic/reboot.cpp:35 extern "C" int __reboot(int, int, int, void*); int reboot(int mode) { return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL); }
./bionic/libc/arch-arm64/syscalls/__reboot.S /* Generated by gensyscalls.py. Do not edit. */ #include <private/bionic_asm.h> ENTRY(__reboot) mov x8, __NR_reboot svc #0 cmn x0, #(MAX_ERRNO + 1) cneg x0, x0, hi b.hi __set_errno_internal ret END(__reboot) .hidden __reboot
=》最后会进入Kernel 如 ./prebuilts/ndk/8/platforms/android-9/arch-arm/usr/include/sys/reboot.h:42:#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF 则进入内核的kernel/reboot.c SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) { case LINUX_REBOOT_CMD_POWER_OFF: kernel_power_off(); do_exit(0); break;
void kernel_power_off(void) { kernel_shutdown_prepare(SYSTEM_POWER_OFF); if (pm_power_off_prepare) pm_power_off_prepare(); migrate_to_reboot_cpu(); syscore_shutdown(); pr_emerg("Power down\n"); kmsg_dump(KMSG_DUMP_POWEROFF); machine_power_off(); } EXPORT_SYMBOL_GPL(kernel_power_off);
Process.c (arch\arm64\kernel):void machine_power_off(void) void machine_power_off(void) { local_irq_disable(); machine_shutdown(); if (pm_power_off) 关电源 pm_power_off(); }
关闭多核
void machine_shutdown(void) { #ifdef CONFIG_SMP smp_send_stop(); #endif } void smp_send_stop(void) { unsigned long timeout; if (num_online_cpus() > 1) { cpumask_t mask; cpumask_copy(&mask, cpu_online_mask); cpu_clear(smp_processor_id(), mask); smp_cross_call(&mask, IPI_CPU_STOP); } /* Wait up to one second for other CPUs to stop */ timeout = USEC_PER_SEC; while (num_online_cpus() > 1 && timeout--) udelay(1); if (num_online_cpus() > 1) pr_warning("SMP: failed to stop secondary CPUs\n"); }
函数指针pm_power_off是与平台相关的指针, 只是一个函数指针,而且做了全局操作,整个kernel都可以调用它,amlogic平台是如下方法设置的 ./common/drivers/amlogic/reset/gxbb_poweroff.c:152: pm_power_off = do_aml_poweroff; static void do_aml_poweroff(void) { /* TODO: Add poweroff capability */ __invoke_psci_fn_smc(0x82000042, 1, 0, 0); __invoke_psci_fn_smc(psci_function_id_poweroff, 0, 0, 0); } 即最后设置寄存器: static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) { register long x0 asm("x0") = function_id; register long x1 asm("x1") = arg0; register long x2 asm("x2") = arg1; register long x3 asm("x3") = arg2; asm volatile( __asmeq("%0", "x0") __asmeq("%1", "x1") __asmeq("%2", "x2") __asmeq("%3", "x3") "smc #0\n" : "+r" (x0) : "r" (x1), "r" (x2), "r" (x3)); return function_id; }
系统没有wake_lock时,以下timer会检测执行回调:
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;
struct timespec ts_entry, ts_exit;
if (has_wake_lock(WAKE_LOCK_SUSPEND)) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: abort suspend\n"); return; } entry_event_num = current_event_num; if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: sys_sync..."); sys_sync(); if (debug_mask & DEBUG_SUSPEND) pr_info("done.\n"); if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: enter suspend\n"); getnstimeofday(&ts_entry); ret = pm_suspend(requested_suspend_state); getnstimeofday(&ts_exit); if (debug_mask & DEBUG_EXIT_SUSPEND) { struct rtc_time tm; rtc_time_to_tm(ts_exit.tv_sec, &tm); pr_info("suspend: exit suspend, ret = %d (%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec); } if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) { ++suspend_short_count; if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) { suspend_backoff(); suspend_short_count = 0; } } else { suspend_short_count = 0; } if (current_event_num == entry_event_num) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: pm_suspend returned with no event\n"); } wake_lock_timeout(&unknown_wakeup, 5 * HZ);
}
static DECLARE_WORK(suspend_work, suspend);
static void expire_wake_locks(unsigned long data) { long has_lock; unsigned long irqflags; if (debug_mask & DEBUG_EXPIRE) pr_info("expire_wake_locks: start\n"); spin_lock_irqsave(&list_lock, irqflags); if (debug_mask & DEBUG_SUSPEND) print_active_locks(WAKE_LOCK_SUSPEND); has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND); if (debug_mask & DEBUG_EXPIRE) pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock); if (has_lock == 0) queue_work(suspend_work_queue, &suspend_work); spin_unlock_irqrestore(&list_lock, irqflags); } static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0); 该timer会在多个地方用到,在激活锁的函数中注册用于超时锁到期后检测系统的有效锁状态,如果系统不存在有效锁了则启动suspend进程回调pm_suspend。
上层修改的对应的设备节点之后
正常时是
root@p212:/sys/power # cat wake_unlock KeyEvents PowerManagerService.WakeLocks root@p212:/sys/power # cat wake_lock PowerManagerService.Display root@p212:/sys/power # cat state mem disk root@p212:/sys/power #
const char * const OLD_PATHS[] = { "/sys/android_power/acquire_partial_wake_lock", "/sys/android_power/release_wake_lock", }; const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock", };
执行以下代码:
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { suspend_state_t state; int error; error = pm_autosleep_lock(); if (error) return error; if (pm_autosleep_state() > PM_SUSPEND_ON) { error = -EBUSY; goto out; } state = decode_state(buf, n); if (state < PM_SUSPEND_MAX) { #ifdef CONFIG_EARLYSUSPEND if (state == PM_SUSPEND_ON || state == PM_SUSPEND_MEM) { error = 0; request_suspend_state(state); } #else error = pm_suspend(state); #endif } else if (state == PM_SUSPEND_MAX) error = hibernate(); else error = -EINVAL; out: pm_autosleep_unlock(); return error ? error : n; }
重点执行这个func
request_suspend_state
void request_suspend_state(suspend_state_t new_state) { unsigned long irqflags; int old_sleep; spin_lock_irqsave(&state_lock, irqflags); old_sleep = state & SUSPEND_REQUESTED; if (debug_mask & DEBUG_USER_STATE) { struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("request_suspend_state: %s (%d->%d) at %lld " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", new_state != PM_SUSPEND_ON ? "sleep" : "wakeup", requested_suspend_state, new_state, ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); } pr_info("%s,%d,old_sleep=%d,new_state=%d\n", __func__, __LINE__, old_sleep, new_state); if (!old_sleep && new_state != PM_SUSPEND_ON) { state |= SUSPEND_REQUESTED; queue_work(suspend_work_queue, &early_suspend_work); } else if (old_sleep && new_state == PM_SUSPEND_ON) { state &= ~SUSPEND_REQUESTED; wake_lock(&main_wake_lock); queue_work(suspend_work_queue, &late_resume_work); } requested_suspend_state = new_state; spin_unlock_irqrestore(&state_lock, irqflags); }
于是我们就看到了以上打印
pr_info("request_suspend_state: %s (%d->%d) at %lld " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", new_state != PM_SUSPEND_ON ? "sleep" : "wakeup", requested_suspend_state, new_state, ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec)
pr_info("%s,%d,old_sleep=%d,new_state=%d\n", __func__, __LINE__, old_sleep, new_state);
[ 735.994473@0] request_suspend_state: sleep (0->3) at 735823580141 (2015-01-01 00:34:28.725320516 UTC) [ 735.998034@0] request_suspend_state,164,old_sleep=0,new_state=3
表示进下如下流程:
if (!old_sleep && new_state != PM_SUSPEND_ON) { state |= SUSPEND_REQUESTED; queue_work(suspend_work_queue, &early_suspend_work); }
修改标记位,执行工作队列回调
queue_work(suspend_work_queue, &early_suspend_work);
static void early_suspend(struct work_struct *work) { struct early_suspend *pos; unsigned long irqflags; int abort = 0; mutex_lock(&early_suspend_lock); spin_lock_irqsave(&state_lock, irqflags); if (state == SUSPEND_REQUESTED) state |= SUSPENDED; else abort = 1; spin_unlock_irqrestore(&state_lock, irqflags); if (abort) { if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: abort, state %d\n", state); mutex_unlock(&early_suspend_lock); goto abort; } if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: call handlers\n"); list_for_each_entry(pos, &early_suspend_handlers, link) { if (pos->suspend != NULL) pos->suspend(pos); } mutex_unlock(&early_suspend_lock); if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: sync\n"); sys_sync(); abort: spin_lock_irqsave(&state_lock, irqflags); if (state == SUSPEND_REQUESTED_AND_SUSPENDED) wake_unlock(&main_wake_lock); spin_unlock_irqrestore(&state_lock, irqflags); }
接着走
if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: call handlers\n"); list_for_each_entry(pos, &early_suspend_handlers, link) { if (pos->suspend != NULL) pos->suspend(pos); }
执行注册在
early_suspend_handlers的所有回调函数
之后释放锁
if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: sync\n"); sys_sync();
相关文章推荐
- Android待机流程分析
- Android待机流程分析---锁屏、解锁模块
- Android待机流程分析
- Android待机流程分析---锁屏、解锁模块
- android 真待机流程分析
- Android待机流程分析---锁屏、解锁模块
- Android待机流程分析
- Android 待机功能流程分析
- Android待机流程分析---锁屏、解锁模块 .
- Android待机锁屏流程分析
- Android待机流程分析
- Android待机流程分析
- Android待机锁屏流程分析
- Android事件处理分析+Android事件处理 +Android输入事件流程
- Android GSM驱动模块(rild)详细分析(三)response流程
- Android APN开发流程分析(一)
- Android SurfaceFlinger process 流程分析
- Android Recoveryの流程分析
- android中通过拨号键打开contacts相关界面的流程分析
- Android 上层界面到内核代码的完整的流程分析,以alarm为例子