zoukankan      html  css  js  c++  java
  • 待机异常篇

    待机异常篇

    待机异常篇待机异常
    1: 按Power key后,连early_suspend都没进。待机异常
    2: 能够进early_suspend。但进不了suspend待机异常
    3: 能够进suspend,但出现:PM: Some devices failed to suspend待机异常
    4: 能够进入到suspend_enter,suspend流程走完了。但非常快被唤醒待机异常
    5: 能够进入到suspend_enter,也不被唤醒,但电流非常大。CPU也较烫

    这里写图片描写叙述
    这里写图片描写叙述

    关于early_suspend:
    因为/sys/power/autosleep在处理suspend时,并没有像/sys/power/state那样。有对earlysuspend的兼容处理。如:
    Kernel/kernel/power/main.c

    static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
                   const char *buf, size_t n)
    {
    ....
    #ifdef CONFIG_EARLYSUSPEND
            if (state == PM_SUSPEND_ON || valid_state(state)) {
                error = 0;
                request_suspend_state(state);
            }
    #else
            error = pm_suspend(state);
    #endif

    进入request_suspend_state会先处理earlysuspend,然后再进入suspend。
    而autosleep在处理时,是直接进入pm_suspend,不会去处理earlysuspend。

    因此。不同平台处理earlysuspend的方式也不同,如Intel平台是通过将全部/sys/power/early_suspend/xxdevic/early_suspend文件写1使其相应的设备进入earlysuspend(代码路径:hardwarelibhardwaremodulespower),该操作发生在上图ANDROID待机流程的blankAllDisplays,在blankAllDisplays函数里,会先调用nativeSetInteractive进入early_suspend,再调用nativeSetAutoSuspend进入suspend。
    /sys/power/early_suspend/xxdevic/early_suspend 节点通过以下接口生成:
    device_create_file(&dev->pdev->dev, &dev_attr_early_suspend);
    register_early_suspend_device(&dev->pdev->dev);

    待机异常1 :按Power key后。连early_suspend都没进。

    问题分析
    这种情况发生在Android待机流程中的goToSleepInternal,因为不满足待机条件而无法进入待机。
    不能进入待机的条件:

    private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
    
            if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
                    || !mBootCompleted || !mSystemReady) {
                return false;
            }

    事件时间和电源状态一般不会是异常的因素。因此引起异常的主要是mBootCompleted 和mSystemReady 两个条件。

    调试方法
    mBootCompleted在收到Intent.ACTION_BOOT_COMPLETED广播后置1,而Intent.ACTION_BOOT_COMPLETED广播是在进入到Launcher后发出的。frameworksaseservicesjavacomandroidserveramActivityManagerService.java,因此当系统启动异常时进入不到Launcher。就无法待机;另一种情问,多Launcher选择界面时也因没进入Launcher而不发ACTION_BOOT_COMPLETED广播而造成待不了机。

    当ActivityManagerService跑起来就表示mSystemReady 为true,能够通过查看logcat,假设看到有“Activity Manager”的log表示已跑ActivityManagerService。假设看到“** Failure starting bootstrap service”,表示启动失败。

    待机异常2:能够进early_suspend。但进不了suspend

    问题分析
    进入suspend时,会调用pm_get_wakeup_count。假设系统存在wake_lock就会卡在这个函数里,如:
    pm_get_wakeup_count:
    prepare_to_wait(&wakeup_count_wait_queue, &wait,
    TASK_INTERRUPTIBLE);

    当wake_lock释放完成时才会唤醒该wait,例如以下inpr = 0:
    wakeup_source_deactivate:
    if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
    wake_up(&wakeup_count_wait_queue);

    调试方法
    在串口终端下,不要连接USB,连USB会产生wake_lock。cat /sys/power/wakeup_count,这时会去调用pm_get_wakeup_count。假设cat也卡住,说明存在suspend确实是卡在wake_lock上。


    Wake_lock有些是android进程加的和有些是kernel进程加的。能够通过命令cat /sys/kernel/debug/wakeup_sources 来查看全部的wake_lock。例如以下:

    active_since 所在列,假设有数值大于0,表示其所相应的行是当前活动的wake_lock。如上图,PowerManagerService.WakeLocks和dwc_wake_lock是活动的。
    原代码的打印有可能对不齐,以下的修改能够让其对齐:

    --- a/kernel/drivers/base/power/wakeup.c
    +++ b/kernel/drivers/base/power/wakeup.c
    @@ -842,8 +842,7 @@ static int print_wakeup_source_stats(struct seq_file *m,
    
    
    -       ret = seq_printf(m, "%-12s	%lu		%lu		%lu		%lu		"
    -                       "%lld		%lld		%lld		%lld		%lld
    ",
    +       ret = seq_printf(m, "%-35s%-15lu%-15lu%-15lu%-15lu%-15lld%-15lld%-15lld%-15lld%-15lld
    ",
                            ws->name, active_count, ws->event_count,
                            ws->wakeup_count, ws->expire_count,
                            ktime_to_ms(active_time), ktime_to_ms(total_time),
    @@ -863,9 +862,8 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
     {
    
    
    -       seq_puts(m, "name		active_count	event_count	wakeup_count	"
    -               "expire_count	active_since	total_time	max_time	"
    -               "last_change	prevent_suspend_time
    ");
    +       seq_printf(m, "%-35s%-15s%-15s%-15s%-15s%-15s%-15s%-15s%-15s%-15s
    ",
    +                       "name","active_count","event_count","wakeup_count","expire_count","active_since","total_time","max_time","last_chang

    android加的wake_lock能够通过命令cat /sys/power/wake_lock来查看。再在kernel/kernel/power/main.c 的wake_lock_store函数里加上打印: printk(“pid %d wirte %s to /sys/power/wake_lock ”,current->pid,buf);,将pid打印出来,然后cat /proc/进程ID/status 来查看详细进程(也能够 ps 进程ID号来查看)。

    待机异常3: 能够进suspend,但出现:PM: Some devices failed to suspend

    问题分析
    有些设备在待机时失败了。

    调试方法
    首先用命令cat /sys/kernel/debug/suspend_stats查看待机异常发生在哪个阶段。例如以下:
    success: 3
    fail: 1
    failed_freeze: 0
    failed_prepare: 0
    failed_suspend: 1
    failed_suspend_late: 0
    failed_suspend_noirq: 0
    failed_resume: 0
    failed_resume_early: 0
    failed_resume_noirq: 0
    failures:
    last_failed_dev:

    last_failed_errno: -16
    0
    last_failed_step: suspend

    failed_suspend 的记数大于0表示在device_suspend阶段异常。


    从log能够看到,假设是这种字段:
    active wakeup source: event3-556
    PM: Some devices failed to suspend
    则表示有些活动wakeup锁还没释放。

    在kernel/drivers/base/power/wakeup.c的wakeup_source_add函数里加入打印:
    printk(“%s:%s ”,FUNCTION,ws->name);
    dump_stack();
    跟踪出哪个驱动,然后在该驱动里跟踪wakeup锁。

    假设log是这种:
    PM: Device xxx failed to xxx: error x
    PM: Some devices failed to suspend
    则表示有设备在待机时失败,依据设备名找到相应驱动,然后跟踪该驱动suspend失败的原因。

    另外。将kernel/kernle/printk.c里的ignore_loglevel置1:
    Kernel/kernel/printk.c
    static bool __read_mostly ignore_loglevel=1;
    用命令echo 1 > /sys/power/pm_print_times 打开kernel/drivers/base/power/main.c里的initcall_debug_report打印。这样。在待机时就能够打印出哪些设备待机成功或失败。

    待机异常4: 能够进入到suspend_enter。suspend流程走完了,但非常快被唤醒

    问题分析
    Suspend流程走完后被唤醒,说明有唤醒源异常,造成异常唤醒。

    调试方法
    首先用命令cat /sys/kernel/debug/suspend_stats查看待机过程是否正常,假设正常,那么须要找出唤醒源。
    打开kernel/kernel/irq/pm.c的resume_irqs函数里的信息打印:

    #ifdef CONFIG_PM_DEBUG
            if (desc->istate & IRQS_PENDING) {
                printk(KERN_DEBUG "Wakeup from IRQ %d %s
    ",
                    irq,
                    desc->action && desc->action->name ?
                    desc->action->name : "");
            }
    #endif /* CONFIG_PM_DEBUG */

    从信息打印里能够看出是哪个中断号唤醒的,命令cat /proc/interrupts能够查看全部中断。另外,在kernel/kernel/irq/manage.c 的__setup_irq函数里加打印及dump_stack。跟踪哪个驱动注冊了该irq号:

    printk("%s:irq = %d,name = %s
    ",__FUNCTION__,irq,new->name ?
                new->name : "");
    dump_stack();

    待机异常5: 能够进入到suspend_enter,也不被唤醒,但电流非常大,CPU也较烫

    问题分析
    进入suspend_enter且不被唤醒。说明系统已进入待机,应该是SOC没进入待机状态造成

    调试方法
    能够在suspend_enter加SOC power state的寄存器的打印,或者跟vendor要soc待机的调试手段,比方 intel平台,能够通过查询cat /sys/kernel/debug/mid_pmu_states 查询cpu有几次进入待机状态。

  • 相关阅读:
    JDBC五数据源和数据池(web基础学习笔记十一)
    JDBC四(web基础学习笔记十)
    JDBC三(web基础学习笔记九)
    JDBC二查询(web基础学习笔记八)
    JDBC一(web基础学习笔记七)
    HTML二(基本标签)
    Java从零开始学八(循环结构)
    如何合理地估算线程池大小?(转载)
    Java 8 Documentation Download
    Redis集群
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7098060.html
Copyright © 2011-2022 走看看