android 2.3 电源管理

1.     介绍.... 4

2.     前言.... 4

3.     应用程序开发相关.... 4

3.1.      Api的使用... 4

3.2.      注意事项... 5

4.     驱动程序开发相关.... 5

5.     FrameWork相关.... 6

5.1.      Linux内核的电源管理... 6

5.2.      Android对linux内核的修改... 6

5.3.      Android Power Management.. 7

6.     情景分析.... 10

7.     LightsService. 10

8.     WatchDog.. 10

9.     优缺点.... 11

10.      PowerManagerService阅读笔记.... 12

11.     如何充分利用xx pmu的功能.... 13


1.       介绍

       这是一篇关于Android电源管理的文章, 适合应用程序开发人员和驱动开发人员和FrameWork开发人员阅读。

2.       前言

     Android系统出于节电的需要, 一般应用在用户一段时间无操作的情况下屏幕变暗, 然后进后休眠状态, 此时cpu处于挂起状态, 屏幕处于关闭状态。 用户只能在”设置->声音和显示”中设置所有应用默认的屏幕亮度和系统无操作多久进入睡眠的时间。

     当然这种管理模式并不适合于所有的应用, 比如当看电影的时候总不希望系统隔一段时间就进入睡眠吧。所以Android系统为这种有特殊需求的应用提供了可以不遵守规矩的Api, 通过使用这种Api可以打破默认情况下的电源管理模式。

3.       应用程序开发相关

3.1.      Api的使用

    只需要熟悉android.os.PowerManager和android.os.PowerManager.WakeLock这两个类的Api就足够了, 当需要用到这些Api时, 需要在Manifest.xml添加如下权限:

     <uses-permission android:name="android.permission.WAKE_LOCK" />

     <uses-permission android:name="android.permission.DEVICE_POWER" />

     很重要的一个概念就是WakeLock, 系统中定义了六种WakeLock, 常用的有4个:

 

cpu

Screen

keyboard light

PARTIAL_WAKE_LOCK

on

off

off

SCREEN_DIM_WAKE_LOCK

on

dim

off

SCREEN_BRIGHT_WAKE_LOCK

on

on

off

FULL_WAKE_LOCK

on

on

on

    对WakeLock有两种操作:获取和释放。获取后当系统需要睡眠时就会进入所获取的WakeLock代表的状态。 实例代码如下:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();

   ……
   ..cpu on, screen dim, keyboard light off
wl.release();

    如上面代码所示, 如果系统在获取锁后一段时间无操作就会进入SCREEN_DIM_WAKE_LOCK锁所对应的状态。

    另外还有两个比较特殊的锁:

l          ACQUIRE_CAUSES_WAKEUP:一旦有请求锁时强制打开Screen和keyboard light 

l          ON_AFTER_RELEASE:当lock被释放后,通过reset user activity timer使屏幕多亮一会儿

 

关于api更加详细的内容请参考官方文档。

 

3.24.  注意事项

l        使用WakeLock会增加系统功耗,所以原则上是只有必要的时候才用

l         所有的锁必须成对的使用, 如申请了PARTIAL_WAKE_LOCK, 而没有及时释放,那系统就永远进不了Sleep模式, 这会严重影响手持设备的待机时间。

4.       驱动程序开发相关

    值得注意的是, 写Android的linux驱动时也要记得系统随时都可能suspend。有些驱动需要关心early suspend和later resume, 比如early suspend时framebuffer驱动的dma应该可以休息了。 有些驱动则需要在某个过程中系统不能睡眠, 比如usb gadget driver向pc传文件的过程中系统就不能睡眠, 睡了就传不完了, 这就需要在这个过程前后获得而后释放锁。 有些驱动向某个设备发送命令过程中如果发生suspend, 等到唤醒的时候再接着发可能外设早已timeout, 这时也需要锁。

     驱动相关的wakelock接口如下, 在inclulde/linux/wakelock.h中定义:

void wake_lock_init(struct wake_lock *lock, int type, const char *name);

void wake_lock_destroy(struct wake_lock *lock);

void wake_lock(struct wake_lock *lock);

void wake_lock_timeout(struct wake_lock *lock, long timeout);

void wake_unlock(struct wake_lock *lock);

int wake_lock_active(struct wake_lock *lock);

long has_wake_lock(int type);

     示例代码如下:

#include <linux/earlysuspend.h>

#include <linux/module.h>

 

struct wake_lock my_wake_lock;

 

static int __init my_init(void)

{

wake_lock_init(&my_wake_lock, WAKE_LOCK_SUSPEND, "mylock");

 

wake_lock(&my_wake_lock);

      //we do not want to suspend here!

wake_unlock(&my_wake_lock);

 

       return 0;

}

 

static void  __exit my_exit(void)

{

wake_lock_destroy(&my_wake_lock)

}

 

module_init(my_init);

module_exit(my_exit);

 

 

     early suspend和later resume是Android对linux内核的扩展机制, 当系统持有wakelock时,如果一段时间无用户操作, 就会进入early suspend状态, 所有驱动注册的early suspend回调函数会被调用。当用户开始操作设备时,所有驱动注册的later resume函数会被调用。 当系统中无wakelock时, 驱动注册的early suspend会先于suspend函数调用, 唤醒时later resume会再resume函数后调用。 early suspend机制给系统提供了一种折中的省电模式,让系统在不能睡眠的情况下各个驱动模块也能有机会调整工作模式。 驱动注册early suspend和later resume回调的代码如下:

#include <linux/earlysuspend.h>

#include <linux/module.h>

 

static my_early_suspend(struct early_suspend *h)

{

 

}

static void my_late_resume(struct early_suspend *h)

{

 

}

 

static struct early_suspend my_early_suspend_desc = {

    .suspend = my_early_suspend,

    .resume = my_late_resume,

};

 

static int __init my_init(void)

{

       register_early_suspend(&my_early_suspend_desc);

       return 0;

}

 

static void  __exit my_exit(void)

{

    unregister_early_suspend(&my_ early_suspend_desc);

}

 

module_init(my_init);

module_exit(my_exit);

 

另外,请慎重在驱动的suspend和resume函数中和内核线程(workqueue或tasklet)中操作wakelock。

5.       FrameWork相关

5.1.      Linux内核的电源管理

    Linux内核的电源管理有两个阶段suspend和resume, 分别在设备睡眠和唤醒的时候进行,需要关心电源管理的驱动程序可以注册suspend和resume函数在睡眠和唤醒时执行。Linux内核提供给应用层的接口是/sys/power/state, 有如下命令:

l        echo mem>/sys/power/state:睡眠,状态保存进ram

l        echo on>/sys/power/state:唤醒

l        echo standby>/sys/power/state

l        echo disk>/sys/power/state:睡眠, 状态保存进disk

还有一些其他命令请查阅网上资料, 有的命令不一定支持。

5.2.      Android对linux内核的修改

    Android linux内核的电源管理系统是基于Linux内核的电源管理系统的扩展,添加了锁的概念, 多出了两个阶段early suspend和later resume,在有锁的情况下进入的睡眠是partial lock状态, 只会执行注册的early suspend函数, 唤醒时只会执行注册的later resume函数。只有在无锁时进入睡眠才会真正suspend,注册的early suspend函数会在suspend函数前执行,注册的later resume函数会在resume函数后执行 。 关心电源管理的android驱动程序可以注册early suspend和later resume和suspend和resume函数在相应阶段执行。 Android linux内核提供给应用层得接口如下:

l        /sys/power/state:只支持mem(睡眠)和on(唤醒)两个参数 

l        /sys/power/power_lock: 写入锁的名字即获得锁

l        /sys/power/power_unlock:写入锁的名字即解锁

    状态转换图如下:


图1

    值得注意的是, 其实并不能把Android linux内核的电源管理和Android电源管理分开, Android linux内核的电源管理完全是根据上层需要对linux内核做的修改, 单独并不能工作。 请看情景分析 , later resume过程是在Android FrameWork层收到电源键按下的事件后“echo on>/sys/power/state“进行的。

    TODO:分析Android Linux内核的电源管理系统源码

    

 

5.3.      Android Power Management

    Android系统的电源管理是基于Android linux内核的电源管理系统, 在锁的基础上又添加了SCREEN_DIM_WAKE_LOCK,SCREEN_BRIGHT_WAKE_LOCK和SCREEN_FULL_WAKE_LOCK。为了尽可能节电, 系统中有一个定时器,每当定时器溢出时就会根据当前持有锁得情况进行判断进入相应的状态。 定时器溢出时间在settings里面可以设置。

    电源管理模块的结构图如下。


       WatchDog负责监测PowerManagerService, 防止PowerManagerService出现死锁。

    PowerManagerService通过LightsService操作屏幕和键盘背光。

        下图是状态转换图, 比较复杂所以没有画出状态转换条件。


图2

    与图1对应的是Suspend和PARTIAL_WAKE_LOCK状态,而另外三个状态都是处于图1中的awake状态之中。 下图把他们统一看做SCREEN_LOCK状态,简化后的状态图如下, 这回从Android api的角度来分析状态的转换的条件。


图3

    从suspend到SCREEN_LOCK的转换是到FULL_SCREEN_WAKE_LOCK, 从PARTIAL_WAKE_LOCK到SCREEN_LOCK的转换则分三种情况:

l        userActivity:到FULL_SCREEN_WAKE_LOCK状态

l        获得FULL_SCREEN_WAKE_LOCK 进入FULL_SCREEN_WAKE_LOCK状态

l        获得DIM_SCREEN_WAKE_LOCK: 进入DIM_SCREEN_WAKE_LOCK状态

l        获得BRIGHT_SCREEN_WAKE_LOCK: 进入BRIGHT_SCREEN_WAKE_LOCK状态

    当然SCREEN_DIM_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK和SCREEN_FULL_WAKE_LOCK之间也是会相互转换的。

   

6.       情景分析

    系统开机后一段时间无用户输入进入睡眠, 过一段时间用户按下电源键将设备唤醒。

过程如下:

l        PowerManagerService定时器溢出

l        由于无锁, 会利用LightsService关闭屏幕背光和键盘背光

l        echo mem>/sys/power/state进入内核态

l        调用所有驱动注册的early suspend函数

l        由于无锁, 会调用所有驱动注册的suspend函数真正进入睡眠

l        按下电源键设备被唤醒, 所有驱动的resume函数被调用

l        WindowManagerService收到/event/input0的按键事件, 调用PowerManagerService.userActivity函数, 随后PowerManagerService会利用LightsService打开屏幕和键盘背光, 并且“echo on>/sys/power/state“进入内核态。

l        内核调用所有驱动的later resume函数,至此唤醒过程结束。

 

注:在linux最小系统调试电源管理时, echo mem >/sys/power/state进入睡眠, 按电源键唤醒后再echo mem >/sys/power/state将无法进入睡眠。 需手动echo on>/sys/power/state来完成唤醒过程才能再次echo mem >/sys/power/state。

7.       LightsService

     http://wenku.baidu.com/view/1d5b627202768e9951e73852.html

8.       WatchDog

     http://www.limodev.cn/blog/archives/1566

9.       优缺点

优点:节电

缺点:每一个开发者(无论应用和驱动)都需要关心电源管理, 一个程序锁使用不当会影  响整个系统。

   

    Android 对linux内核PowerManager部分的修改没有被linux内核所接收引发了一场大讨论,至于当中缘由和是非,有兴趣请看下面的文章和讨论。

l         http://lwn.net/Articles/388131/

l         http://lwn.net/Articles/318611/

l         \\srv-srd\SHARES\FW\协同开发\Android预研\经验分享\framework\张岱岩\Android2.2电源管理\ suspend_blockers.pdf

 

下面是自己对一些有见解的讨论的摘录

1.all that suspend blockers do is to tell the system that while suspend is blocked, don't run your normal heuristics.

When suspend is not blocked, the system can run the heuristics to decide if it should suspend or not.

suspend blockers may allow yo to set the system heuristics to be more aggressive, but if you have any apps on the system that do not invoke suspend blockers, you run the risk of suspending too aggressively when those apps are running.

And if an app claims that you should not suspend (by setting a suspend block), then the system will never go to sleep.

this is very similar to cooperative multitasking, when all apps are well written it can work _very_ well (and can be far more efficient than premptive multitasking), but it only takes one badly written app to cripple the system.

There's a reason that there are basically no commonly used cooperative multitasking systems, in the real world they just aren't reliable enough. The only place you can really use them is in embedded situations where you control everything that's running on the system. That no longer includes phones as people can download apps to run on them.

2. Android's implementation of suspend blockers allows it to suspend the system aggressively without worrying about interrupting anything important (such as a download). And for many apps it achieves this without any risk that the app will block suspend no matter how buggy it is, because only some apps have access to the suspend blocker API.

Before an app is installed the user is shown a list of access rights the app is requesting. One access right an app can require is to "prevent the phone from sleeping". As many apps don't need this functionality they don't ask for access to the suspend blocker API, and so can't flatten your battery no matter how buggy they are.

Apps that do require access to the suspend blocker API would need to to exhibit buggy behavior *while holding a lock* in order to drain your battery. Android can also show you which apps are using the most power if you are concerned about your battery life.

3. My understanding is that in the Android phone world what happens is this:

• User A downloads "cow bouncer" and is impressed that now their phone constantly has bouncing cows. However an hour later their phone bleeps to warn the battery is low. The "low battery" screen shows a "Why so soon?" button or link, which implicates "cow bouncer" as the reason. User A chooses to uninstall the "cow bouncer" app because it's a waste of battery life.

• User B downloads "John the ripper Android edition" and sets it to work cracking password hashes. An hour later the phone bleeps due to exhausted battery. User B plugs it into the wall, he doesn't ask why because hey, he was running a password cracker on his phone, stands to reason it will exhaust the battery.

By obligating ordinary developers to ask for this functionality if they need it and then auditing how it is used, Android make them responsible to their users - if you need to block suspend for long periods, you will need to educate your users about why that is, and persuade them that the app functionality is worth the reduced battery life, otherwise they're going to throw your app away and probably warn off other potential customers

10.   PowerManagerService阅读笔记

获得或释放锁时更新mWakeLockState

用户输入或timeout时更新mUserState

setPowerState时根据mWakeLockState|mUserState更新状态

用户输入通过PowerManagerService.userActivity和gotoSleep系列函数注入, 包括电源键

需要注意的是, InputManager和PowerManagerService的接口层com_android_service_PowerManagerService的状态需要通过nativeSetPowerState正确维护

11.  如何充分利用xxpmu的功能

Android的省电模式只有suspend和early suspend。 early suspend是假睡眠, cpu仍然工作, 并没有通过pmu。 xxpmu有4中状态, runtime, 待机, 关机和掉电, 关机状态下系统可以被唤醒, 当电池耗光时进入掉电状态。 其中省电模式有待机和关机。

待机时状态保存在ram, 关机时状态保存在flash, 都可以被唤醒, 关机状态更省电但恢复时间更长。

       根据xx spec,我们只需要在系统进入待机状态之前设置RTC即可, 如果进入待机一段时间内没有本唤醒, RTC会发出RTC_close_D信号使GL5201进入关机状态。

       接下来的问题是, 我们将设置RTC的代码放在哪里?

       下图使android linux内核电源管理的状态转换图, FrameWork部分没有权利直接让系统睡眠, 而是通过sys文件系统向内核发送请求, 内核再根据锁的情况来决定要不要睡眠。 所以只需要修改内核代码, 在睡眠前设置RTC即可。

       Android电源管理也是分平台相关部分和平台无关部分, 平台无关部分代码位于kernel/power目录下。 平台相关代码一般放在arch/pm.c(当然文件名不必须是pm.c)文件中。 在pm.c的工作就是实现并在启动时调用suspend_set_ops函数向内核注册一个platform_suspend_ops结构体,platform_suspend_ops结构体里是一些回调函数, 在这些函数里来设置pmu的寄存器。 platform_suspend_ops结构体如下:

struct platform_suspend_ops {

       int (*valid)(suspend_state_t state);

       int (*begin)(suspend_state_t state);

       int (*prepare)(void);

       int (*prepare_late)(void);

       int (*enter)(suspend_state_t state);

       void (*wake)(void);

       void (*finish)(void);

       void (*end)(void);

       void (*recover)(void);

};

       这里只有enter函数是必须的, 其它都可以根据实际情况选择性的实现。 我们可以这样实现platform_suspend_ops的enter函数:

int platform_enter(suspend_state_t state)

{

set_rtc();

platform_suspend();

clear_rtc();

}

 

       RTC的超时时间(也就是待机状态向关机状态转换的时间)可以(不必须)由用户设置, 可以通过添加sysfs接口的方式将用户的设置传到内核空间,这样就需要改动Settings程序代码, 在用户设置时和系统启动时调用sysfs接口设置超时时间。

       关于Android linux内核休眠机制的分析请参考《Android linux 内核休眠与唤醒》(http://www.360doc.com/content/10/0722/08/496343_40576726.shtml

       关于嵌入式系统的电源管理方式, 请参考《嵌入式系统动态电源管理技术》(http://blog.csdn.net/colorant/article/details/2827812

      

12.   调试过程中产生的问题

l         一段时间无用户操作, 系统不会进入suspend模式。 但在命令行里echo mem>/sys/power/state可以进入suspend模式。

原因:没有将wakelock编译进内核,导致hardware/libhardware_legacy/power/power.c初始化失败(因为找不到/sys/power/wake_lock和/sys/power/wake_unlock),acquire_wake_lock, set_screen_state等函数全部直接返回error。

l         调试过程中出现了一系列问题, 比如唤醒后马上又进入睡眠, 都是由于唤醒时没有向上报power的input event导致的, 没input event上报导致系统没持有任何wakelock, 而且later resume过程也无法执行到。 EventHub中有一段注释:

// Poll for events.  Mind the wake lock dance!

        // We hold a wake lock at all times except during poll().  This works due to some

        // subtle choreography.  When a device driver has pending (unread) events, it acquires

        // a kernel wake lock.  However, once the last pending event has been read, the device

        // driver will release the kernel wake lock.  To prevent the system from going to sleep

        // when this happens, the EventHub holds onto its own user wake lock while the client

        // is processing events.  Thus the system can only sleep if there are no events

        // pending or currently being processed.

        release_wake_lock(WAKE_LOCK_ID);

 

        int pollResult = poll(mFDs, mFDCount, -1);

 

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

l         在驱动suspend函数中申请锁会导致睡眠失败, 系统resume。

l         wakeup wakelock, 也就是唤醒后的第一个锁, 必须是向input子系统发送power事件时获得的锁,  在其它驱动resume函数中申请锁, 如果此锁成为wakeup wakelock,会导致唤醒失败, 系统重新进入睡眠。

l         内核线程在默认情况下是不被冷冻的, 也就是在打印的freezing tasks和restart tasks之间仍然活跃, 而被冷冻的用户进程则在restart tasks之后才开始调度。 所以在内核线程要慎重申请wakelock, 必要时需要在驱动suspend时挂起内核线程, resume时再恢复。

l         如下内核oop:

[  220.980000] CPU 0 Unable to handle kernel paging request at virtual address 0063002e, epc == 801d2df8, ra == 801d4f0c

[  220.980000] Oops[#1]:

[  220.980000] Cpu 0

[  220.980000] $ 0   : 00000000 00000001 00000000 00000000

[  220.980000] $ 4   : 0063002e ffffffff 0063002e 00000000

[  220.980000] $ 8   : 00000022 00000003 00000001 00000002

[  220.980000] $12   : 00000005 fffffffe 00000002 c4653601

[  220.980000] $16   : 80710190 80711000 ffffffff 860fbd94

[  220.980000] $20   : 8071018f 8035f44c 00000e71 80360000

[  220.980000] $24   : 00000000 00000002                  

[  220.980000] $28   : 860fa000 860fbce8 8035f494 801d4f0c

[  220.980000] Hi    : 00000005

[  220.980000] Lo    : 5ae82600

[  220.980000] epc   : 801d2df8 strnlen+0x8/0x4c

[  220.980000]     Not tainted

[  220.980000] ra    : 801d4f0c string.clone.1+0x48/0x10c

[  220.980000] Status: 31009c02    KERNEL EXL

[  220.980000] Cause : 00800008

[  220.980000] BadVA : 0063002e

[  220.980000] PrId  : 00019750 (MIPS 74Kc)

[  220.980000] Modules linked in: gl5201_camera ov2643 sndrv atc260x_audio aotg_monitor g_switch mmc_block atv5201_mmc mmc_core galcore atc260x_pm atc260x_hwmon atc260x_switch_ldo atc260x_dcdc atc260x_ldo atc260x_power atc260x_gpio atc260x_rtc atc260x_onoff atc260x_tp atc260x_core asoc_spi blk2drv blk1drv atv5201_matrixkey atv5201_vout atv5201_fb atv5201_de atv5201_tvout atv5201_lcd atv5201_display atv5201_backlight [last unloaded: aotg_udc]

[  220.980000] Process UEventObserver (pid: 431, threadinfo=860fa000, task=860ef468, tls=40869f00)

[  220.980000] Stack : 803d5ada 803d5ada 80711000 860fbdc8 0063002e 00000000 803d5ab7 803d5ab7

[  220.980000]         80711000 801d6574 803d5ab6 00000000 86227740 86227a00 ffffffff ffffffff

[  220.980000]         ffffffff ffffffff ff0a0004 ffffffff 00000001 80710190 86227b00 86227b00

[  220.980000]         ffffffff 00000000 006f0074 ffffffff 00002719 ffffffff 0000000a 800f8d54

[  220.980000]         80444230 8403ed00 8642c018 86227740 860fbd90 80129ef8 c46535ff 80073460

[  220.980000]         ...

[  220.980000] Call Trace:

[  220.980000] [<801d2df8>] strnlen+0x8/0x4c

[  220.980000] [<801d4f0c>] string.clone.1+0x48/0x10c

[  220.980000] [<801d6574>] vsnprintf+0x270/0x498

[  220.980000] [<800f8d54>] seq_printf+0x44/0x8c

[  220.980000] [<80073460>] print_lock_stat+0x14c/0x364

[  220.980000] [<800736e0>] wakelock_stats_show+0x68/0x138

[  220.980000] [<800f9100>] seq_read+0x1e0/0x4d0

[  220.980000] [<8012a740>] proc_reg_read+0x98/0x108

[  220.980000] [<800d704c>] vfs_read+0xb8/0x148

[  220.980000] [<800d7128>] sys_read+0x4c/0xa4

[  220.980000] [<80012aa4>] stack_done+0x20/0x3c

[  220.980000]

[  220.980000]

[  220.980000] Code: 00000000  10a00010  00001021 <80820000> 1040000b  00852821  08074b86  00801021  80430000

[  220.980000] Disabling lock debugging due to kernel taint

[  221.748000] gl5201_matixkey_drv: key 139 :pressed

[  221.764000] Fatal exception: panic in 5 seconds

[  221.788000] BUG: scheduling while atomic: UEventObserver/431/0x00000002

[  221.808000] Modules linked in: gl5201_camera ov2643 sndrv atc260x_audio aotg_monitor g_switch mmc_block atv5201_mmc mmc_core galcore atc260x_pm atc260x_hwmon atc260x_switch_ldo atc260x_dcdc atc260x_ldo atc260x_power atc260x_gpio atc260x_rtc atc260x_onoff atc260x_tp atc260x_core asoc_spi blk2drv blk1drv atv5201_matrixkey atv5201_vout atv5201_fb atv5201_de atv5201_tvout atv5201_lcd atv5201_display atv5201_backlight [last unloaded: aotg_udc]

[  221.980000] Call Trace:

[  221.988000] [<8031dcac>] dump_stack+0x8/0x34

[  222.000000] [<8031e388>] schedule+0x4b0/0x754

[  222.028000] [<8031efac>] schedule_timeout+0x188/0x340

[  222.044000] [<80044490>] msleep+0x24/0x34

[  222.068000] [<8000fcdc>] die+0x138/0x150

[  222.080000] [<800163b4>] do_page_fault+0x2a4/0x320

[  222.108000] [<80009444>] ret_from_exception+0x0/0x10

[  222.124000] [<801d2df8>] strnlen+0x8/0x4c

[  222.148000] [<801d4f0c>] string.clone.1+0x48/0x10c

[  222.164000] [<801d6574>] vsnprintf+0x270/0x498

[  222.188000] [<800f8d54>] seq_printf+0x44/0x8c

[  222.200000] [<80073460>] print_lock_stat+0x14c/0x364

[  222.228000] [<800736e0>] wakelock_stats_show+0x68/0x138

[  222.244000] [<800f9100>] seq_read+0x1e0/0x4d0

[  222.268000] [<8012a740>] proc_reg_read+0x98/0x108

[  222.284000] [<800d704c>] vfs_read+0xb8/0x148

[  222.308000] [<800d7128>] sys_read+0x4c/0xa4

[  222.320000] [<80012aa4>] stack_done+0x20/0x3c

[  222.348000]

[  222.356000] gl5201_matixkey_drv: [in asoc_keymx_report_released]key 139 :release

[  226.792000] Kernel panic - not syncing: Fatal exception

[  226.820000] Rebooting in 5 seconds..

很可能是驱动对wake_lock api的错误使用导致:

 

Wake lock在使用前要调用wake_lock_init。

Wake lock释放前要调用Wake_lock_destroy。

 

wake lock错误使用的例子:

(1)     wakelock作为函数局部变量, 函数退出前没调用wake_lock_destroy

 

如果某某驱动在释放wakelock的内存前没调Wake_lock_destroy, kernel的wakelock管理系统仍然会持有指向已经释放的wakelock的指针, 从而导致类似这种错误。

用户态操作wakelock通过/systemfs接口, 内存由kernel的wakelock管理系统分配, 不存在此类担心。

 

所以用到wakelock驱动, 还应确定对wakelock的使用是否正确。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值