当前位置: 首页 > news >正文

待机异常篇

待机异常篇

待机异常篇待机异常
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_EARLYSUSPENDif (state == PM_SUSPEND_ON || valid_state(state)) {error = 0;request_suspend_state(state);}
#elseerror = pm_suspend(state);
#endif
  • static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
    {
    ....
    #ifdef CONFIG_EARLYSUSPENDif (state == PM_SUSPEND_ON || valid_state(state)) {error = 0;request_suspend_state(state);}
    #elseerror = pm_suspend(state);
    #endif
    • 
      

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

      因此,不同平台处理earlysuspend的方式也不同,如Intel平台是通过将所有/sys/power/early_suspend/xxdevic/early_suspend文件写1使其对应的设备进入earlysuspend(代码路径:hardware\libhardware\modules\power\),该操作发生在上图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;}
      • 1

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

      调试方法
      mBootCompleted在收到Intent.ACTION_BOOT_COMPLETED广播后置1,而Intent.ACTION_BOOT_COMPLETED广播是在进入到Launcher后发出的,frameworks\base\services\java\com\android\server\am\ActivityManagerService.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\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
      -                       "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
      +       ret = seq_printf(m, "%-35s%-15lu%-15lu%-15lu%-15lu%-15lld%-15lld%-15lld%-15lld%-15lld\n",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\t\tactive_count\tevent_count\twakeup_count\t"
      -               "expire_count\tactive_since\ttotal_time\tmax_time\t"
      -               "last_change\tprevent_suspend_time\n");
      +       seq_printf(m, "%-35s%-15s%-15s%-15s%-15s%-15s%-15s%-15s%-15s%-15s\n",
      +                       "name","active_count","event_count","wakeup_count","expire_count","active_since","total_time","max_time","last_chang
      • 1

      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\n”,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\n”,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_DEBUGif (desc->istate & IRQS_PENDING) {printk(KERN_DEBUG "Wakeup from IRQ %d %s\n",irq,desc->action && desc->action->name ?desc->action->name : "");}
      #endif /* CONFIG_PM_DEBUG */
      • 1

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

      printk("%s:irq = %d,name = %s\n",__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有几次进入待机状态。

    http://www.xdnf.cn/news/806203.html

    相关文章:

  • 4.4 Linux文件系统-挂载卸载和超级块
  • Linux虚拟机Apache服务器配置
  • 什么是3322域名?3322域名如何注册?
  • C++开发股票软件
  • 最详细的Cydia使用教程------完全版。新补充Cydia1.1.1离线安装(升级)方法。
  • android gallery滑动监听,利用RecyclerView和ViewPager实现GalleryView可无限左滑右滑
  • windows xp系统安装教程
  • 几个开源的视频编解码器介绍
  • [转]站长实用,42个著名搜索引擎免费登陆入口大全
  • N点虚拟主机管理系统如何使用?
  • 【直播回放】最强大的GNN直播回放来咯!
  • Spring Boot 集成支付宝支付,看这篇就够了
  • WAP网站设计六——WML Script标准函数库
  • IndexOutOf下标越界几种解决方案
  • 皮肤html代码大全,清新QQ空间免费皮肤代码大全(可用)
  • 镜头光晕 - Affinity Photo 教程
  • 流程图控件开源_软件自动化测试基本流程(附流程图)
  • VirtualBox上建立开发板、虚拟机和主机的连接
  • Element-UI:el-table样式修改
  • 宏基4750网卡驱动linux,宏碁4750g无线网卡驱动下载
  • SQL Server 2000企业版安装教程
  • WebEasyMail发布和邮箱申请
  • 网络摄像机—图像压缩方式—JPEG、MJPEG
  • WAP网页设计入门
  • USB大容量存储设备无法启动该怎么办?
  • E6全部刷机包
  • 上网本安装MeeGo 1.0初体验
  • VS各个版本之间2005、08、10、12...转换
  • 2025LitCTF re wp复现
  • Android 4.0 x86安装教程 附带联网参数详细设置