2011-01-04 14:16 Android电源管理系统调研报告

来源:互联网 发布:移动网络怎样优化 编辑:程序博客网 时间:2024/05/17 04:28

 

android电源管理

Android 的电源管理也是很重要的一部分。比如在待机的时候关掉不用的设备,timeout之后的屏幕和键盘背光的关闭,用户操作的时候该打开多少设备等等,这些都直接关系到产品的待机时间,以及用户体验。

      framework层主要有这两个文件:     

        frameworks\base\core\java\android\os\PowerManager.java

        frameworks\base\services\java\com\android\server\PowerManagerService.java

        其中PowerManager.java是提供给应用层调用的,最终的核心还是在PowerManagerService.java。这个类的作用就是提供PowerManager的功能,以及整个电源管理状态机的运行。里面函数和类比较多,就从对外和对内分两块来说。

        先说对外,PowerManagerService如何来进行电源管理,那就要有外部事件的时候去通知它,这个主要是在frameworks\base \services\java\com\android\server\WindowManagerService.java里面。 WindowManagerService会把用户的点击屏幕,按键等作为user activity事件来调用userActivity函数,PowerManagerService就会在userActivity里面判断事件类型作出反映,是点亮屏幕提供操作,还是完全不理会,或者只亮一下就关掉。供WindowManagerService调用的方法还有gotoSleep和其他一些获取电源状态的函数比如screenIsOn等等。

        在说对内,作为对外接口的userActivity方法主要是通过setPowerState来完成功能。把要设置的电源状态比如开关屏幕背光什么的作为参数调用setPowerState,setPowerState先判断下所要的状态能不能完成,比如要点亮屏幕的话但是现在屏幕被lock了那就不能亮了,否则就可以调用Power.setScreenState(true)来透过jni跑到driver里面去点亮屏幕了。

        而电源的状态循环则主要是通过Handler来实现的。PowerManagerService在init里面会启动一个HandlerThread一个后台消息循环来提供任务的延迟发送,就可以使用Handler来在定制推迟某一任务的执行时间,从而实现状态机的循环。比如timeout,一段时间之后无操作要让屏幕变暗,然后关闭,反映在代码里如下:

        userActivity里面在调用setPowerState之后会用setTimeoutLocked来设置timeout。然后在 setTimeoutLocked里面会根据当前的状态来计算下一个状态以及时间,判断完再调用 mHandler.postAtTime(mTimeoutTask, when)来post一个TimeoutTask。这样在when毫秒后就会执行TimeoutTask。在TimeoutTask里面则根据设定的状态来调用setPowerState来改变电源状态,然后再设定新的状态,比如现在是把屏幕从亮改暗了,那就再用 setTimeoutLocked(now, SCREEN_OFF)来等下把屏幕完全关掉。如果这次已经是把屏幕关了,那这轮的timeout状态循环就算是结束了。

        如果要定制的话,比如需求是在timeout屏幕关掉之后还要再关掉一些外围设备等等,那就在TimeoutTask里面把屏幕关掉之后再加上关闭其他设备的代码就好了。即使新的状态需求完全和原来的不一样,用Handler应该也不难。逻辑理清了把代码摆在合适的地方就好了。


   总体上来说Android的电源管理还是比较简单的, 主要就是通过锁和定时器来切换系统的状态,使系统的功耗降至最低,整个系统的电源管理架构图如下: (注该图来自Steve Guo)

 

Android power management block diagram 

接下来我们从Java应用层面, Android framework层面, Linux内核层面分别进行详细的讨论:

应用层的使用:

Android提供了现成android.os.PowerManager类,该类用于控制设备的电源状态的切换.

该类对外有三个接口函数:

         void goToSleep(long time); //强制设备进入Sleep状态

         Note:

尝试在应用层调用该函数,却不能成功,出现的错误好象是权限不够但在Framework下面的Service里调用是可以的.

         newWakeLock(int flags, String tag);//取得相应层次的锁

flags参数说明:

PARTIAL_WAKE_LOCK: Screen off, keyboard light off

SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off

SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off

FULL_WAKE_LOCK: screen bright, keyboard bright

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

ON_AFTER_RELEASE: 在释放锁时reset activity timer

Note:

如果申请了partial wakelock,那么即使按Power,系统也不会进Sleep,Music播放时

如果申请了其它的wakelocks,Power,系统还是会进Sleep

         void userActivity(long when, boolean noChangeLights);//User activity事件发生,设备会被切换到Full on的状态,同时Reset Screen off timer.

Sample code:

         PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wl = pm.newWakeLock (PowerManager.SCREEN_DIM_WAKE_LOCK, “My Tag”);

         wl.acquire();

         …….

         wl.release();

Note:

1. 在使用以上函数的应用程序中,必须在其Manifest.xml文件中加入下面的权限:

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

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

2. 所有的锁必须成对的使用,如果申请了而没有及时释放会造成系统故障.如申请了partial wakelock,而没有及时释放,那系统就永远进不了Sleep模式.


Android Framework层面:

其主要代码文件如下:

frameworks\base\core\java\android\os\PowerManager.java

frameworks\base\services\java\com\android\server\PowerManagerService.java

frameworks\base\core\java\android\os\Power.java

frameworks\base\core\jni\android_os_power.cpp

hardware\libhardware\power\power.c

其中PowerManagerService.java是核心, Power.java提供底层的函数接口,与JNI层进行交互, JNI层的代码主要在文件android_os_Power.cpp,Linux kernel交互是通过Power.c来实现的, AndriodKernel的交互主要是通过sys文件的方式来实现的,具体请参考Kernel层的介绍.

 

这一层的功能相对比较复杂,比如系统状态的切换,背光的调节及开关,Wake Lock的申请和释放等等,但这一层跟硬件平台无关,而且由Google负责维护,问题相对会少一些,有兴趣的朋友可以自己查看相关的代码.


Kernel层:

其主要代码在下列位置:

drivers/android/power.c

其对Kernel提供的接口函数有

EXPORT_SYMBOL(android_init_suspend_lock); //初始化Suspend lock,在使用前必须做初始化

EXPORT_SYMBOL(android_uninit_suspend_lock); //释放suspend lock相关的资源

EXPORT_SYMBOL(android_lock_suspend); //申请lock,必须调用相应的unlock来释放它

EXPORT_SYMBOL(android_lock_suspend_auto_expire);//申请partial wakelock, 定时时间到后会自动释放

EXPORT_SYMBOL(android_unlock_suspend); //释放lock

EXPORT_SYMBOL(android_power_wakeup); //唤醒系统到on

EXPORT_SYMBOL(android_register_early_suspend); //注册early suspend的驱动

EXPORT_SYMBOL(android_unregister_early_suspend); //取消已经注册的early suspend的驱动

 

提供给Android Framework层的proc文件如下:

"/sys/android_power/acquire_partial_wake_lock" //申请partial wake lock

"/sys/android_power/acquire_full_wake_lock" //申请full wake lock

"/sys/android_power/release_wake_lock" //释放相应的wake lock

"/sys/android_power/request_state" //请求改变系统状态,进standby和回到wakeup两种状态

"/sys/android_power/state" //指示当前系统的状态

 

Android的电源管理主要是通过Wake lock来实现的,在最底层主要是通过如下三个队列来实现其管理:

static LIST_HEAD(g_inactive_locks);

static LIST_HEAD(g_active_partial_wake_locks);

static LIST_HEAD(g_active_full_wake_locks);

所有初始化后的lock都会被插入到g_inactive_locks的队列中,而当前活动的partial wake lock都会被插入到g_active_partial_wake_locks队列中, 活动的full wake lock被插入到g_active_full_wake_locks队列中, 所有的partial wake lock 和full wake lock在过期后或unlock后都会被移到inactive的队列,等待下次的调用.

在Kernel层使用wake lock步骤如下:

1.        调用函数android_init_suspend_lock初始化一个wake lock

2.        调用相关申请lock的函数android_lock_suspend 或 android_lock_suspend_auto_expire请求lock,这里只能申请partial wake lock, 如果要申请Full wake lock,则需要调用函数android_lock_partial_suspend_auto_expire(该函数没有EXPORT出来),这个命名有点奇怪,不要跟前面的android_lock_suspend_auto_expire搞混了.

3.        如果是auto expire的wake lock则可以忽略,不然则必须及时的把相关的wake lock释放掉,否则会造成系统长期运行在高功耗的状态.

4.        在驱动卸载或不再使用Wake lock时请记住及时的调用android_uninit_suspend_lock释放资源.

 

系统的状态:

         USER_AWAKE, //Full on status

         USER_NOTIFICATION, //Early suspended driver but CPU keep on

         USER_SLEEP // CPU enter sleep mode

其状态切换示意图如下:

 

system state machine系统正常开机后进入到AWAKE状态, Backlight会从最亮慢慢调节到用户设定的亮度,系统screen off timer(settings->sound & display-> Display settings -> Screen timeout)开始计时,在计时时间到之前,如果有任何的activity事件发生,如Touch click, keyboard pressed等事件, 则将Reset screen off timer, 系统保持在AWAKE状态. 如果有应用程序在这段时间内申请了Full wake lock,那么系统也将保持在AWAKE状态, 除非用户按下power key. 在AWAKE状态下如果电池电量低或者是用AC供电screen off timer时间到并且选中Keep screen on while pluged in选项,backlight会被强制调节到DIM的状态.

如果Screen off timer时间到并且没有Full wake lock或者用户按了power key,那么系统状态将被切换到NOTIFICATION,并且调用所有已经注册的g_early_suspend_handlers函数, 通常会把LCD和Backlight驱动注册成early suspend类型,如有需要也可以把别的驱动注册成early suspend, 这样就会在第一阶段被关闭. 接下来系统会判断是否有partial wake lock acquired, 如果有则等待其释放, 在等待的过程中如果有user activity事件发生,系统则马上回到AWAKE状态;如果没有partial wake lock acquired, 则系统会马上调用函数pm_suspend关闭其它相关的驱动, 让CPU进入休眠状态.

系统在Sleep状态时如果检测到任何一个Wakeup source, 则CPU会从Sleep状态被唤醒,并且调用相关的驱动的resume函数,接下来马上调用前期注册的early suspend驱动的resume函数,最后系统状态回到AWAKE状态.这里有个问题就是所有注册过early suspend的函数在进Suspend的第一阶段被调用可以理解,但是在resume的时候, Linux会先调用所有驱动的resume函数,而此时再调用前期注册的early suspend驱动的resume函数有什么意义呢?个人觉得android的这个early suspend和late resume函数应该结合Linux下面的suspend和resume一起使用,而不是单独的使用一个队列来进行管理.

Android电源管理系统调研报告1

 

 

如今手持设备中出现的一对不可调和的矛盾就是越来越大的能量消耗与电池容量瓶颈之间的矛盾,就算没有这个瓶颈,相对更持久的续航能力也是众向所归。Android系统一般应用于高端智能设备,能源消耗尤其突出,因此对Android的电源管理系统的调研有很必要。

Android系统是基于标准Linux内核之上的,在Linux内核在原有的power manager系统之上增加了相应了文件,为Android系统的power manager提供底层服务支持。因此,调研工作在两个层面展开:Linux内核层、Android系统层。

 

 

Linux内核层:
针对Android系统而增添的power manager文件有如下五个:

/Linux-/kernel/power/

|-consoleearlysuspend.c

|-earlysuspend.c

|-fbearlysuspend.c

|-userwakelock.c

|-wakelock.c

这五个文件配合Linux层的power manager柜架和与功耗相关的设备驱动,向Android层提供了power manager的底层支持。与功耗相关的设备主要包括LCD屏和键盘及其它设备的LED灯。因些,在这类设备的驱动中应该增加相应的power manager功能。

在该调研报告中,仅简单地罗出列出各文件中定义的功能函数以及向上提供的接口,其具体的功能调用及整个power manager柜架地实现在后期的调研报告中阐述。

 

1)、consoleearlysuspend.c

       功能函数:

static void console_early_suspend(struct early_suspend *h);

static void console_late_resume(struct early_suspend *h);

static int __init console_early_suspend_init(void);

static void  __exit console_early_suspend_exit(void);

 

数据结构:

static struct early_suspend console_early_suspend_desc = {

       .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,

       .suspend = console_early_suspend,

       .resume = console_late_resume,

};

 

2、earlysuspend.c

功能函数:

void register_early_suspend(struct early_suspend *handler);

void unregister_early_suspend(struct early_suspend *handler);

static void early_suspend(struct work_struct *work);

static void late_resume(struct work_struct *work);

void request_suspend_state(suspend_state_t new_state);

suspend_state_t get_suspend_state(void);

 

 

供驱动使用的函数接口:

EXPORT_SYMBOL(register_early_suspend);

EXPORT_SYMBOL(unregister_early_suspend);

 

在earlysuspend.h文件中定义了注册接口函数:

#ifdef CONFIG_HAS_EARLYSUSPEND

void register_early_suspend(struct early_suspend *handler);

void unregister_early_suspend(struct early_suspend *handler);

 

3、fbearlysuspend.c

       功能函数:

static void stop_drawing_early_suspend(struct early_suspend *h);

static void start_drawing_late_resume(struct early_suspend *h);

static ssize_t wait_for_fb_sleep_show(struct kobject *kobj,

                                  struct kobj_attribute *attr, char *buf);

static ssize_t wait_for_fb_wake_show(struct kobject *kobj,

                                 struct kobj_attribute *attr, char *buf);

static int __init android_power_init(void);

static void  __exit android_power_exit(void)

 

主要的数据结构:

static struct early_suspend stop_drawing_early_suspend_desc = {

       .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,

       .suspend = stop_drawing_early_suspend,

       .resume = start_drawing_late_resume,

};

 

 

在以上面的几个函数中,都调用了__wake_up:

在sched.c中定义了这个函数

/**

 * __wake_up - wake up threads blocked on a waitqueue.

 * @q: the waitqueue

 * @mode: which threads

 * @nr_exclusive: how many wake-one or wake-many threads to wake up

 * @key: is directly passed to the wakeup function

 */

void __wake_up(wait_queue_head_t *q, unsigned int mode,

                     int nr_exclusive, void *key)

{

       unsigned long flags;

       spin_lock_irqsave(&q->lock, flags);

       __wake_up_common(q, mode, nr_exclusive, 0, key);

       spin_unlock_irqrestore(&q->lock, flags);

}

 

4、userwakelock.c

static struct user_wake_lock *lookup_wake_lock_name(const char *buf, int allocate, long *timeoutptr);

ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);

ssize_t ssixe_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,

       const char *buf, size_t n);

ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);

ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,       const char *buf, size_t n);

 

5、wakelock.c

提供了接口函数有:

EXPORT_SYMBOL(wake_lock_init);

EXPORT_SYMBOL(wake_lock_destroy);

EXPORT_SYMBOL(wake_lock);

EXPORT_SYMBOL(wake_lock_timeout);

EXPORT_SYMBOL(wake_unlock);

EXPORT_SYMBOL(wake_lock_active);

 

以上函数仅提供了一个android power manager实现的底层柜架,要使其很好的work起来,需要相关设备driver的支持和与Android层power manager系统很好的配合。


Android系统层

Android层的电源管理主要在framework层实现,其中battery的管理包括充放电状态、电量显示等,但这部分暂不在调研范围之间。该部分调研的重点在于LCD以及相关设备LED状态的切换。

相关文件包括:

/frameworks/base/services/java/com/android/server/PowerManagerService.java

/platform/frameworks/base/core/java/android/os/PowerManager.java

/platform/frameworks/base/core/java/android/os/Power.java

/frameworks/base/core/jni/android_os_Power.cpp

/hardware/libhardware_legacy/power/power.c

 

引用一张比较全面的power manager框架图,我们可以看到power manager的核心代码在PowerManagerService.java中,该文件通过利用PowerManager.java提供的类,android_os_Power.cpp提供的一些本地方法以及power.c对底层的调用,完成了android系统power manager的各自服务。该文件的分析见后续的调研报告。

 

2011-01-04 14:17

Android电源管理系统调研报告-(2)

1)、PowerManager.java

该文件定义了一个PowerManager类供其它文件使用,该类嵌套了一个nest class:

public class WakeLock,该nest class有如下方法:

public void setReferenceCounted(boolean value)

public void acquire()

public void acquire(long timeout)

public void release()

public void release(int flags)

public boolean isHeld()

public String toString()

@Override

        protected void finalize() throws Throwable

 

该nest class的构造方法为:

 WakeLock(int flags, String tag)

其中有一个关键的参数flags,它有如下几种情况:

       PARTIAL_WAKE_LOCK: Screen off, keyboard light off

SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off

SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off

FULL_WAKE_LOCK: screen bright, keyboard bright

上面4种是互斥的,即只能指定其中之一,但可以与下面两种flag不是互斥的:

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

ON_AFTER_RELEASE: 在释放锁时reset activity timer

 

 

除了这个内部类,powermanager类定义了如下方法:

public WakeLock newWakeLock(int flags, String tag)

              //该方法return一个nest class的一个对象。而我们看到,nest class实际上完成了WakeLock的申请与释放

public void userActivity(long when, boolean noChangeLights)

public void goToSleep(long time)

public void setBacklightBrightness(int brightness)

public int getSupportedWakeLockFlags()

public boolean isScreenOn()

 

该类的构造方法有两个:

private PowerManager()     

public PowerManager(IPowerManager service, Handler handler)

2、Power.java

PowerManagerSerivive.java中调用了一些本地方法,该文件作为这些方法的java层与jni的中间层,声明了本地接口。

public static native void acquireWakeLock(int lock, String id);

    public static native void releaseWakeLock(String id);

    public static native int setScreenState(boolean on);

    public static native int setLastUserActivityTimeout(long ms);

    @Deprecated

    public static native void shutdown();

    public static void reboot(String reason) throws IOException

 

3、andriod_ow_Power.cpp

该文件编写了本地实现方法,从本地方法列表可以知道该本地方法与power.c是密切相关的:

static JNINativeMethod method_table[] = {

    { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },

    { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },

    { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },

    { "setScreenState", "(Z)I", (void*)setScreenState },

    { "shutdown", "()V", (void*)android_os_Power_shutdown },

    { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },

};

 

4、power.c

该文件作为Android系统的最底层,与Linux内核的power manager交互。

static int64_t systemTime();

static int open_file_descriptors(const char * const paths[]);

static inline void initialize_fds(void);

int acquire_wake_lock(int lock, const char* id);

int set_last_user_activity_timeout(int64_t delay);

int set_screen_state(int on);

 

2011-01-04 14:18

Android电源管理系统调研报告-(3)

一、powermanagerservice.java1、nest class

1)、private class UnsynchronizedWakeLock

从类名可以看出这个类实现的是异步获取唤醒锁。当PowerManager.WakeLock与 synchronizing on mLocks之间发生死锁的时候,这个类可以重新实现PowerManager.WakeLock。由于它没有外部同步块,所以只有当拥有锁的时候才调用这个类。

该类实现的方法有:

public void acquire()

public void release()

public boolean isHeld()

public String toString()

构造方法:

UnsynchronizedWakeLock(int flags, String tag, boolean refCounted)

 

2)、private final class BatteryReceiver extends BroadcastReceiver

这个类是个广播接收,至于广播的使用,这里不作深入的探讨。该类重载了接收的方法。当然,接收的过程是有约束的,即同步mLocks。

@Override

        public void onReceive(Context context, Intent intent)

            synchronized (mLocks) 

即使当keyguard is on

                     synchronized (mLocks) {

                         forceUserActivityLocked();

 

3)、private final class BootCompletedReceiver extends BroadcastReceiver

        @Override

        public void onReceive(Context context, Intent intent) {

            bootCompleted();

         }   

该广播能接收到启动完成后的消息,而后调用bootCompleted()。

 

4)、private final class DockReceiver extends BroadcastReceiver

 

5)、private class SettingsObserver implements Observer

6)、private class WakeLock implements IBinder.DeathRecipient

方法public void binderDied()会调用releaseWakeLockLocked

synchronized (mLocks) {

                releaseWakeLockLocked(this.binder, 0, true);

 

7)、private class PokeLock implements IBinder.DeathRecipient

方法public void binderDied() 调用

            setPokeLock(0,this.binder, this.tag);

 

8)、private class TimeoutTask implements Runnable

该类实现了Runnable接口,有一个run方法。

run方法实现的是Timeout后进行的动作,setTimeoutLocked(now,SCREEN_DIM);?setTimeoutLocked(now,SCREEN_OFF);

 

9)、class BrightnessState

该类定义的方法有

BrightnessState(int m)

public void dump(PrintWriter pw, String prefix)

boolean setTargetLocked(int target, int stepsToTarget, int initialValue,int nominalCurrentValue)

 

delta = (targetValue -(nominalCurrentValue >= 0 ?nominalCurrentValue : curValue))/ stepsToTarget;

 

boolean stepLocked()

 

10)、private class LightAnimator implements Runnable

该类实现了Runnable接口,有一个run方法

run方法实现的是亮度变化的控制:

ScreenBrightness

KeyboardBrightness

ButtonBrightness

这三个设备亮度分步控制。

if (mKeyboardBrightness.stepLocked()) {

                    more = true;

                }

                if (mButtonBrightness.stepLocked()) {

                    more = true;

                }

                if (more) {

                     mHandler.postAtTime(mLightAnimator, now+(1000/60));

 

11)、private class GservicesChangedReceiver extends BroadcastReceiver

该类继承了广播接口的类,方法onReceive调用了updateGservicesValues()。

该类当接收到google service改变的广播时,就受调用updateGservicesValues()。

 

12)、private class LockList extends ArrayList<WakeLock>

方法:

void addLock(WakeLock wl)

WakeLock removeLock(IBinder binder)

int getIndex(IBinder binder)

int gatherState()

int reactivateScreenLocksLocked()

 

该类实践上是建立了一了锁队列/锁列表,该队列可以通过addLock新建一个锁,也可以通过removeLock从队列中摘除一个锁,可以通过getIndex查询指定锁在队列中的索引号

 

定义了一个该类的实例

private final LockList mLocks = new LockList();

整个service中方法的调用都同步这个对象mLocks

synchronized (mLocks)

 

 

2、相关的service:BatteryService

mBatteryService.isPowered()

mBatteryService.getBatteryLevel()

BatteryStatsService.getService()

GservicesHardwareserviceActivityService

 

3、参数

    //flags for setPowerState

    private static final intSCREEN_ON_BIT          = 0x00000001;

    private static final intSCREEN_BRIGHT_BIT      = 0x00000002;

    private static final intBUTTON_BRIGHT_BIT      = 0x00000004;

    private static final intKEYBOARD_BRIGHT_BIT    = 0x00000008;

    private static final intBATTERY_LOW_BIT        = 0x00000010;

 

    //SCREEN_OFF == everything off

    private static final intSCREEN_OFF         = 0x00000000;

 

    //SCREEN_DIM == screen on, screen backlight dim

    private static final intSCREEN_DIM         = SCREEN_ON_BIT;

 

    //SCREEN_BRIGHT == screen on, screen backlight bright

    private static final intSCREEN_BRIGHT      = SCREEN_ON_BIT |SCREEN_BRIGHT_BIT;

 

    //SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright

    private static final intSCREEN_BUTTON_BRIGHT  = SCREEN_BRIGHT |BUTTON_BRIGHT_BIT;

 

    //SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlightsbright

    private static final intALL_BRIGHT         = SCREEN_BUTTON_BRIGHT| KEYBOARD_BRIGHT_BIT;

 


 

4、提供的相关服务

提供的这些服务之间并不是独立的,而是相互交织在一起,共同完成电源管理的:

1)、光感传感器

LIGHT_SENSOR

 

定义了光感传感器变化明暗变化的延时:

// How long to wait to debounce light sensor changes.

     private static final int LIGHT_SENSOR_DELAY = 2000;

 

相关的参数有:

private Sensor mLightSensor;

    private boolean mLightSensorEnabled;

    private float mLightSensorValue = -1;

    private int mHighestLightSensorValue = -1;

    private float mLightSensorPendingValue = -1;

    private int mLightSensorBrightness = -1;

    private int mLightSensorWarmupTime;

         private static final boolean mDebugLightSensor = (false || mSpew);

 

相关的方法:

private void enableLightSensor(boolean enable)

    private int setScreenStateLocked

    private int getPreferredBrightness()

    private Runnable mAutoBrightnessTask = new Runnable()

    private void lightSensorChangedLocked(int value)

    public void setKeyboardVisibility(boolean visible)

    private void setScreenBrightnessMode(int mode)

    private void enableLightSensor(boolean enable)

         SensorEventListener mLightListener = new SensorEventListener()

 

                        // force recompute of backlight values

                        if (mLightSensorValue >= 0) {

                             int value = (int)mLightSensorValue;

                             mLightSensorValue = -1;

                             lightSensorChangedLocked(value);

 

 

 

2)、接近/距离传感器

PROXIMITY_SENSOR

 

定义了接近传感器变化明暗变化的延时:

// For debouncing the proximity sensor.

     private static final int PROXIMITY_SENSOR_DELAY = 1000;

 

定义了接近传感器触发的最大距离:

// trigger proximity if distance is less than 5 cm

     private static final float PROXIMITY_THRESHOLD = 5.0f;

 

在powermanager类中定义的与接近传感器相关的参数有:

private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;

     public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF

 

相关参数:

    private int mProximityWakeLockCount = 0;

    private boolean mProximitySensorEnabled = false;

    private boolean mProximitySensorActive = false;

    private int mProximityPendingValue = -1; // -1 == nothing, 0 == inactive, 1 == active

    private long mLastProximityEventTime;

 

    private UnsynchronizedWakeLock mProximityPartialLock;

         private Sensor mProximitySensor;

 

相关方法:

    SensorEventListener mProximityListener = new SensorEventListener()

         private Runnable mProximityTask = new Runnable()

 

                            //当拨出电话或接通电话时会调用该方法

    private void enableProximityLockLocked()

                            ......

                            //传感器的注册,三个参数分别是接收信号Listener的实例、传感器类型的列表、接收频度;

                     mSensorManager.registerListener(mProximityListener, mProximitySensor,

                         SensorManager.SENSOR_DELAY_NORMAL);

 

                            //当挂断电话时会调用该方法

    private void disableProximityLockLocked()

                            ......

                            //缷载传感器

              mSensorManager.unregisterListener(mProximityListener);

 

    private void proximityChangedLocked(boolean active){

                            ......

                            //小于触发距离触发接近传感器之后的动作_灭屏。如打电话时屏幕LCD灯的熄灭

                             if (active) {

             goToSleepLocked(SystemClock.uptimeMillis(),

                     WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);

             mProximitySensorActive = true;

                            ......

     SensorEventListener mProximityListener = new SensorEventListener()

 

3)、提供明亮度动态变化:

animation for brightness changes:

 

定义了可以明暗动态变化设备的宏,可以看出,不外乎这三个部分:屏幕灯、触摸按键灯和键盘灯

    static final boolean ANIMATE_SCREEN_LIGHTS = true;

    static final boolean ANIMATE_BUTTON_LIGHTS = false;//如果有该部分的灯并需要亮度调节,找开这个宏

    static final boolean ANIMATE_KEYBOARD_LIGHTS = false;//如果有该部分的灯并需要亮度调节,找开这个宏

 

    

明暗变化的级别,分普通级别的较慢级别:

    static final int ANIM_STEPS = 60/4;

    // Slower animation for autobrightness changes

    static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;

 

 

相关类:

101010private class LightAnimator implements Runnable

 

相关方法:

private void updateLightsLocked(int newState, int forceState)

private void lightSensorChangedLocked(int value)

public void setBacklightBrightness(int brightness)

 

 

4)、允许用户用软件自动调节亮度

mUseSoftwareAutoBrightness

在initThread中初始化了这个变量

mUseSoftwareAutoBrightness =resources.getBoolean(com.android.internal.R.bool.config_automatic_brightness_available);

当这个变量获取到非零值

        if (mUseSoftwareAutoBrightness) {

             mAutoBrightnessLevels = resources.getIntArray(

                     com.android.internal.R.array.config_autoBrightnessLevels);

 

自动调节亮度的功能与LIGHT_SENSOR相关,当外界光线强时,屏幕会相应提升亮度。

 

 

Linux下USB suspend/resume源码分析

Author:aaron

 

本文主要从自己开发的一个USB驱动的例子来深入讲解linux内核是如何支持USB设备的休眠和唤醒的,

最近我在为我们公司的一个模块写linux下的驱动, 其中之一就是要支持USB的休眠唤醒问题, 实际上linux内核对USB的这个功能的支持还是比较新的, 也就是最近几年的事.

 

一  打开/关闭USB suspend/resuem功能

要让linux支持usb suspend/resuem, 当然先要把内核中这个功能的代码编译进去咯, 即要在make menuconfig时打开对这项功能的支持.

第一个打开的项是CONFIG_PM, 即整个系统的电源管理, USB suspend/resuem只是整个电源管理的一个自系统. 只有打开了这个功能才能让USB的这个特性能用.

第二个要打开的当让是USB自己的开关了CONFIG_USB_SUSPEND. 即打开了这个功能后我们只要在我们自己的驱动里简单调用下USB core提供的函数接口就能使我们的设备休眠了.

 

二 源码分析

在2.6.19之前的代码中不支持USB自动休眠的功能, 它只能是在host休眠情况下才会让USB设备也休眠. 所以如果我们要让自己的设备在不使用的情况下就休眠就得自己添加相应的代码, 幸运的是我们不需要添加复杂的代码就能达到这个目的, 因为USB core里提供了几个接口可以直接让我们的驱动调用以把我们的设备置入休眠状态.

下面我们以2.6.16的代码为例来分析下USB设备是如何进入休眠的.

Drivers/usr/core/hub.c:

int usb_suspend_device(struct usb_device *udev)

{

#ifdef      CONFIG_USB_SUSPEND

       if (udev->state == USB_STATE_NOTATTACHED)

              return -ENODEV;

       return __usb_suspend_device(udev, udev->portnum);

#else

       /* NOTE:  udev->state unchanged, it's not lying ... */

       udev->dev.power.power_state = PMSG_SUSPEND;

       return 0;

#endif

}

没错, 在我们的驱动里只要在适当的地方调用这个函数就可以使我们的设备休眠了. 但是需要注意的是,  内核没有EXPORT这个函数, 因此如果我们的驱动要编译成模块的话, 我们只有修改内核以EXPORT这个函数了.

实际上真正干正事的函数是__usb_suspend_device

Drivers/usr/core/hub.c:

static int __usb_suspend_device (struct usb_device *udev, int port1)

{

       int   status = 0;

 

       /* caller owns the udev device lock */

       if (port1 < 0)

              return port1;

    /*如果设备已休眠或还没attach上则直接返回*/

       if (udev->state == USB_STATE_SUSPENDED

                     || udev->state == USB_STATE_NOTATTACHED) {

              return 0;

       }

 

       /* all interfaces must already be suspended */

    /*要休眠设备, 首先必须要设备下的每个interface都可以休眠才行*/

       if (udev->actconfig) {

              int   i;

 

              for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {

                     struct usb_interface       *intf;

 

                     intf = udev->actconfig->interface[i];

                     if (is_active(intf)) {   /*如果某个interface处于活动状态则不能休眠*/

                            dev_dbg(&intf->dev, "nyet suspended/n");

                            return -EBUSY;

                     }

              }

       }

 

       /* we only change a device's upstream USB link.

        * root hubs have no upstream USB link.

        */

    /*干正事的一个函数*/

       if (udev->parent)

              status = hub_port_suspend(hdev_to_hub(udev->parent), port1,

                            udev); 

 

       if (status == 0)

              udev->dev.power.power_state = PMSG_SUSPEND;   /*保存设备状态*/

       return status;

}

第一个参数是要休眠的USB设备, 第二个参数是该USB设备所连接到的hub的某个端口.

从这个函数我们可以大概猜测到, 要一个设备休眠原理就是要把这个设备attach到的那个端口休眠掉.

没错USB spec规定了只要把设备所attach上的那个端口disable掉, 那么这条路径上就没有任何传输了, 在过了一段时间后设备端应该会产生一个suspend的中断, 以让设备进入休眠状态.

Drivers/usr/core/hub.c:

static int hub_port_suspend(struct usb_hub *hub, int port1,

              struct usb_device *udev)

{

       int   status;

 

       // dev_dbg(hub->intfdev, "suspend port %d/n", port1);

 

       /* enable remote wakeup when appropriate; this lets the device

        * wake up the upstream hub (including maybe the root hub).

        *

        * NOTE:  OTG devices may issue remote wakeup (or SRP) even when

        * we don't explicitly enable it here.

        */

/*如果设备支持远程唤醒功能, 则打开此功能*/

       if (device_may_wakeup(&udev->dev)) {

              status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

                            USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,

                            USB_DEVICE_REMOTE_WAKEUP, 0,

                            NULL, 0,

                            USB_CTRL_SET_TIMEOUT);

              if (status)

                     dev_dbg(&udev->dev,

                            "won't remote wakeup, status %d/n",

                            status);

       }

 

       /* see 7.1.7.6 */

   /*^_^看usb spec 7.1.7.6吧, 这个命令就是把hub的这个port disable掉, 这样就达到休眠的目的了*/

       status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);

       if (status) {

              dev_dbg(hub->intfdev,

                     "can't suspend port %d, status %d/n",

                     port1, status);

              /* paranoia:  "should not happen" */

              (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

                            USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,

                            USB_DEVICE_REMOTE_WAKEUP, 0,

                            NULL, 0,

                            USB_CTRL_SET_TIMEOUT);

       } else {

              /* device has up to 10 msec to fully suspend */

              dev_dbg(&udev->dev, "usb suspend/n");

              usb_set_device_state(udev, USB_STATE_SUSPENDED);  /*设置设备状态*/

              msleep(10);

       }

       return status;

}

OK, 很简单把usb设备attach上的那个port disable掉, 就可以达到休眠的目的了(当然实际上它只是把这个port所在的那条链路上的传输停掉, 至于设备是否真会休眠要考设备本省的, 正常情况下, 设备硬件会检测总线上是否有传输, 如没有则把设备转入suspend状态).

OK, 理解了USB设备如何休眠, 那么对于USB设备如何唤醒就很清楚了, 就是重新enable那个port就行了. 这里就不在分析了.

因此假如说我们的设备要在打开之后禁止休眠, 在关闭之后才允许休眠, 该怎么做呢? 呵呵,只要在驱动的open函数里resume设备, 在close函数里suspend设备就行了.

至于2.6.19以后的版本, 加入了自动休眠的功能, 具体实现原理可以参考由fudan_abc写的<<linux那些事儿之HUB>>