Android电源管理机制剖析

来源:互联网 发布:2016能看片的软件 编辑:程序博客网 时间:2024/04/30 20:17

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

        一,电源管理相关文件

          1,框架层文件

               /frameworks/base/services/java/com/android/server/PowerManagerService.java
               /frameworks/base/services/jni/com_android_server_PowerManagerService.cpp
               /frameworks/base/services/java/com/android/server/LightsService.java
               /frameworks/base/services/jni/com_android_server_LightsService.cpp
               /frameworks/base/services/java/com/android/server/BatteryService.java
               /frameworks/base/services/jni/com_android_server_BatteryService.cpp
               /frameworks/base/core/java/android/os/Power.java
               /frameworks/base/core/jni/android_os_Power.cpp
               /frameworks/base/core/java/android/os/PowerManager.java
               /frameworks/base/services/powermanager/IPowerManager.cpp
               /frameworks/base/core/java/android/os/IPowerManager.aidl
               /frameworks/base/core/java/android/os/LocalPowerManager.java
               /frameworks/base/services/jni/com_android_server_InputManager.cpp
               /hardware/libhardware_legacy/power/power.c      

         2,驱动层文件:

               kernel/kernel/power/main.c
               kernel/power/earlysuspend.c
               kernel/kernel/power/suspend.c
               kernel/kernel/power/wakelock.c
               kernel/kernel/power/userwakelock.c

       二,电源管理系统总体流程

         下图从应用层-- >框架层-- >抽象层-- >内核层 简单描述了电源管理系统的睡眠与唤醒代码流程。

          下图PowerManagerService的处理过程,该服务是整个电源管理系统的核心服务。

      三,电源管理系统机制分析

        接下来我们将以上图的框架结构为主线,将进行详细地从最上层到最底层的跟踪。本文的主旨主要就是读者从Android最上层(Java写的应用程序)一步一步的往下跟进,经过Java、C++和C语言写的Framework层、JNI层、HAL层最后到达android的最底层(Kernel层)。通过本文的阅读,您将对android的整体有更加深入、宏观的理解和把握。


        1,框架层分析

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

        Android 的电源管理机制只要是通过锁和定时器来切换系统的状态,是系统的功耗降至最低。在应用层:android 提供了android.os.PowerManager类供应程序使用,用于控制设备的电源状态切换。在框架层 :是再java中通过JNI 访问C++函数->HAL层->sysfs文件系统->调用内核提供的支持来实现。

        整个状态切换流程是:系统正常开机后进入到awake状态,backlight会从最亮慢慢调节到用户设定的亮度,系统screenoff timer(settings->sound and display-> display settings ->screen timeout)开始计时,在计时时间到之前,如果有任何的activity事件发生,如touchclick,keyboard pressed等事件,则将resetscreen off timer, 系统保持在awake状态.如果有应用程序在这段时间内申请了fullwake lock,那么系统也将保持在awake状态,除非用户按下powerkey.。在awake状态下如果电池电量低或者是用AC供电screenoff timer时间到并且选中Keepscreen on while pluged in选项,backlight会被强制调节到DIM的状态。如果screenoff timer时间到并且没有fullwake lock或者用户按了powerkey,那么系统状态将被切换到notification,并且调用所有已经注册的g_early_suspend_handlers函数,通常会把LCD和Backlight驱动注册成earlysuspend类型,如有需要也可以把别的驱动注册成earlysuspend,这样就会在第一阶段被关闭.接下来系统会判断是否有partialwake lock acquired, 如果有则等待其释放,在等待的过程中如果有useractivity事件发生,系统则马上回到awake状态;如果没有partialwake lock acquired, 则系统会马上调用函数pm_suspend关闭其它相关的驱动,让CPU进入休眠状态.系统在Sleep状态时如果检测到任何一个wakeupsource,则CPU会从sleep状态被唤醒,并且调用相关的驱动的resume函数,接下来马上调用前期注册的earlysuspend驱动的resume函数,最后系统状态回到awake状态.

        上图中,我们可以看到power manager的核心代码在PowerManagerService.java中,该文件通过利用PowerManager.java提供的类,android_os_Power.cpp提供的一些本地方法以及power.c对底层的调用,完成了android系统power manager的各自服务。

        在应用程序框架层中,PowerManager类是面向上层应用程序的接口类,提供了Wake Lock机制(同时也是睡眠唤醒子系统)的基本接口(唤醒锁的获取和释放)。上层应用程序通过调用这些接口,实现对系统电源状态的监控。PowerManager类通过IBinder这种Android中特有的通信模式,与PowerManagerService 类进行通信。PowerManagerService 是PowerManager 类中定义的接口的具体实现,并进一步调用Power 类来与下一层进行通信。PowerManagerService 类是WakeLock 机制在应用程序框架层的核心,他们对应用程调用PowerManager类接口时所传递的参数进行初步的分析和对应的设置,并管理一个唤醒锁队列,然后配合其他模块(例如WatchDog、BatteryService、ShutdownThread 等)的状态信息,做出决策,调用Power类的对应接口,最终通过JNI 接口,调用到硬件抽象层中的函数,对sysfs的用户接口进行操作,从而触发内核态实现的用。

        在分析框架层相关文件之前,我们必须先清楚应用层相关文件之间的相互调用关系。

        PowerManagerService.java ---- >PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor{}

        PowerManager.java---- >PowerManager{}---- >PowerManager(IPowerManagerservice, Handler handler){}

        LocalPowerManager.java---- >interface LocalPowerManager{}

        IPowerManager.aidl---- >interface IPowerManager{}

        IPowerManager.cpp---- >class BpPowerManager : public BpInterface<IPowerManager>

 

        首先分析:PowerManager.java这个类是框架层留给应用层的接口,PowerManager.java 电源管理工具类,其为一个公共类提供了较多的公共接口。获取对象方法:PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);应用层可以通过pm对象进行相关的管理操作。根据上面分析的相互调用关系可知,获取PowerManager在getSystemService(Context.POWER_SERVICE)获取对象的时候是通过构造函数PowerManager(IPowerManagerservice, Handler handler){}来创建的,而此处IPowerManager 则是创建PowerManager实例的核心,而IPowerManager则是由PowerManagerService实现,所以PowerManager大部分方法实质还是有PowerManagerService来实现的,清楚了这点后面的分析要简单很多。下面看下PowerManager.java的源码:

public class PowerManager{    private static final String TAG = "PowerManager";    private static final int WAKE_BIT_CPU_STRONG = 1;    private static final int WAKE_BIT_CPU_WEAK = 2;    private static final int WAKE_BIT_SCREEN_DIM = 4;    private static final int WAKE_BIT_SCREEN_BRIGHT = 8;    private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;    private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;        private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG                                        | WAKE_BIT_CPU_WEAK                                        | WAKE_BIT_SCREEN_DIM                                        | WAKE_BIT_SCREEN_BRIGHT                                        | WAKE_BIT_KEYBOARD_BRIGHT                                        | WAKE_BIT_PROXIMITY_SCREEN_OFF;    public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT                                             | WAKE_BIT_KEYBOARD_BRIGHT;    @Deprecated    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;    public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;    public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;    public static final int ON_AFTER_RELEASE = 0x20000000;    public class WakeLock    {        static final int RELEASE_WAKE_LOCK = 1;        Runnable mReleaser = new Runnable() {            public void run() {                release();            }        };        int mFlags;        String mTag;        IBinder mToken;        int mCount = 0;        boolean mRefCounted = true;        boolean mHeld = false;        WorkSource mWorkSource;        WakeLock(int flags, String tag)        {            switch (flags & LOCK_MASK) {            case PARTIAL_WAKE_LOCK:            case SCREEN_DIM_WAKE_LOCK:            case SCREEN_BRIGHT_WAKE_LOCK:            case FULL_WAKE_LOCK:            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:                break;            default:                throw new IllegalArgumentException();            }            mFlags = flags;            mTag = tag;            mToken = new Binder();        }        public void setReferenceCounted(boolean value)        {            mRefCounted = value;        }        public void acquire()        {            synchronized (mToken) {                acquireLocked();            }        }        public void acquire(long timeout) {            synchronized (mToken) {                acquireLocked();                mHandler.postDelayed(mReleaser, timeout);            }        }                private void acquireLocked() {            if (!mRefCounted || mCount++ == 0) {                mHandler.removeCallbacks(mReleaser);                try {                    mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);                } catch (RemoteException e) {                }                mHeld = true;            }        }        public void release() {            release(0);        }        public void release(int flags) {            synchronized (mToken) {                if (!mRefCounted || --mCount == 0) {                    mHandler.removeCallbacks(mReleaser);                    try {                        mService.releaseWakeLock(mToken, flags);                    } catch (RemoteException e) {                    }                    mHeld = false;                }                if (mCount < 0) {                    throw new RuntimeException("WakeLock under-locked " + mTag);                }            }        }        public boolean isHeld()        {            synchronized (mToken) {                return mHeld;            }        }        public void setWorkSource(WorkSource ws) {            synchronized (mToken) {                if (ws != null && ws.size() == 0) {                    ws = null;                }                boolean changed = true;                if (ws == null) {                    mWorkSource = null;                } else if (mWorkSource == null) {                    changed = mWorkSource != null;                    mWorkSource = new WorkSource(ws);                } else {                    changed = mWorkSource.diff(ws);                    if (changed) {                        mWorkSource.set(ws);                    }                }                if (changed && mHeld) {                    try {                        mService.updateWakeLockWorkSource(mToken, mWorkSource);                    } catch (RemoteException e) {                    }                }            }        }        public String toString() {            synchronized (mToken) {                return "WakeLock{"                    + Integer.toHexString(System.identityHashCode(this))                    + " held=" + mHeld + ", refCount=" + mCount + "}";            }        }        @Override        protected void finalize() throws Throwable        {            synchronized (mToken) {                if (mHeld) {                    Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);                    try {                        mService.releaseWakeLock(mToken, 0);                    } catch (RemoteException e) {                    }                }            }        }    }    /**     * Get a wake lock at the level of the flags parameter.  Call     * {@link WakeLock#acquire() acquire()} on the object to acquire the     * wake lock, and {@link WakeLock#release release()} when you are done.     *     * {@samplecode     *PowerManager pm = (PowerManager)mContext.getSystemService(     *                                          Context.POWER_SERVICE);     *PowerManager.WakeLock wl = pm.newWakeLock(     *                                      PowerManager.SCREEN_DIM_WAKE_LOCK     *                                      | PowerManager.ON_AFTER_RELEASE,     *                                      TAG);     *wl.acquire();     * // ...     *wl.release();     * }     * @see WakeLock#acquire()     * @see WakeLock#release()     */    public WakeLock newWakeLock(int flags, String tag)    {        if (tag == null) {            throw new NullPointerException("tag is null in PowerManager.newWakeLock");        }        return new WakeLock(flags, tag);    }    public void userActivity(long when, boolean noChangeLights)    {        try {            mService.userActivity(when, noChangeLights);        } catch (RemoteException e) {        }    }    public void goToSleep(long time)     {        try {            mService.goToSleep(time);        } catch (RemoteException e) {        }    }    public void setBacklightBrightness(int brightness)    {        try {            mService.setBacklightBrightness(brightness);        } catch (RemoteException e) {        }    }    public int getSupportedWakeLockFlags()    {        try {            return mService.getSupportedWakeLockFlags();        } catch (RemoteException e) {            return 0;        }    }    public boolean isScreenOn()    {        try {            return mService.isScreenOn();        } catch (RemoteException e) {            return false;        }    }    public void reboot(String reason)    {        try {            mService.reboot(reason);        } catch (RemoteException e) {        }    }    private PowerManager()    {    }    public PowerManager(IPowerManager service, Handler handler)    {        mService = service;        mHandler = handler;    }        IPowerManager mService;    Handler mHandler;}


        该部分代码中声明的内容并不多,成员变量中只有一些关于WakeLock唤醒锁的标志位,此处相关设置不做详细分析,具体参数与对应的工作状态间API。该内中声明了几个重要的成员方法。内部类WakeLock是整个唤醒锁的核心。并提供了acquire()和release()操作。成员方法WakeLock newWakeLock(int flags, String tag)是创建唤醒锁的核心方法,返回一个唤醒锁对象。接下来几个方法均有PowerManagerService.java去实现:userActivity(long when, boolean noChangeLights)用来响应用户操作事件,包括用户点击后唤醒屏幕等;goToSleep(long time) 强制进入睡眠状态,为用户按下Power键后的操作,在com_android_server_InputManager.cpp中调用,其详细操作见PMS中的实现;setBacklightBrightness(int brightness)设置背光操作;isScreenOn()判断当前屏幕点亮状态的接口,比较实用。

        上述简单的介绍了PowerManager.java,接下来着重分析PowerManagerService.java,该类负责电源管理方面的工作,作为系统基础服务之一,简称PMS。PMS与系统其它服务均有交互,且与HAL层有着紧密的联系,所以PMS的整个系统更加复杂。

        从PowerManagerService extends IPowerManager.Stub implementsLocalPowerManager, Watchdog.Monitor{}可以看出,PowerManagerService实现的接口以及继承的类关系。

        第一个实现的IPowerManager.Stub,即一个Binder的基础实现,该实现完成了PMS的Binder通信,即客户端与服务端的通信,见AIDL实现机制。此处为IPowerManager.aidl。

interface IPowerManager{    void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);    void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);    void goToSleep(long time);    void goToSleepWithReason(long time, int reason);    void releaseWakeLock(IBinder lock, int flags);    void userActivity(long when, boolean noChangeLights);    void userActivityWithForce(long when, boolean noChangeLights, boolean force);    void clearUserActivityTimeout(long now, long timeout);    void setPokeLock(int pokey, IBinder lock, String tag);    int getSupportedWakeLockFlags();    void setStayOnSetting(int val);    void setMaximumScreenOffTimeount(int timeMs);    void preventScreenOn(boolean prevent);    boolean isScreenOn();    void reboot(String reason);    void crash(String message);    void setBacklightBrightness(int brightness);    void setAttentionLight(boolean on, int color);}

        该接口中声明了AIDL公开的方法,应用层使用PMS的方法与PowerManager不一样。

        IPowerManager mPowerManagerService;=IPowerManager.Stub.asInterface(ServiceManager.getService("power"));

        该方法获得PMS的本地代理,可调用PMS中在IPowerManager.aidl接口中公开的方法。

        第二个实现的接口为LocalPowerManager.java

public interface LocalPowerManager {    // Note: be sure to update BatteryStats if adding or modifying event constants.        public static final int OTHER_EVENT = 0;    public static final int BUTTON_EVENT = 1;    public static final int TOUCH_EVENT = 2;    public static final int POKE_LOCK_IGNORE_TOUCH_EVENTS = 0x1;    public static final int POKE_LOCK_SHORT_TIMEOUT = 0x2;    public static final int POKE_LOCK_MEDIUM_TIMEOUT = 0x4;    public static final int POKE_LOCK_TIMEOUT_MASK = 0x6;    void goToSleep(long time);        // notify power manager when keyboard is opened/closed    void setKeyboardVisibility(boolean visible);    // when the keyguard is up, it manages the power state, and userActivity doesn't do anything.    void enableUserActivity(boolean enabled);    // the same as the method on PowerManager    void userActivity(long time, boolean noChangeLights, int eventType);    boolean isScreenOn();    void setScreenBrightnessOverride(int brightness);    void setButtonBrightnessOverride(int brightness);}


         另外一个实现的是Watchdog,此处不做功能性的分析。

         PMS的创建在SystemServer中,有ServerThread线程创建,跟PMS有关的操作见下:

    PowerManagerService power = null;    power = new PowerManagerService();    ServiceManager.addService(Context.POWER_SERVICE, power);    power.init(context, lights, ActivityManagerService.self(), battery);    Watchdog.getInstance().init(context, battery, power, alarm,ActivityManagerService.self());    power.systemReady();

 

         接下来正式分析PMS系统。先看下其成员变量,重要变量已做注释。

    private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK                                        | PowerManager.SCREEN_DIM_WAKE_LOCK                                        | PowerManager.SCREEN_BRIGHT_WAKE_LOCK                                        | PowerManager.FULL_WAKE_LOCK                                        | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;    //                       time since last state:               time since last event:    // The short keylight delay comes from secure settings; this is the default.    private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec    private static final int MEDIUM_KEYLIGHT_DELAY = 15000;       // t+15 sec    private static final int LONG_KEYLIGHT_DELAY = 6000;        // t+6 sec    private static final int LONG_DIM_TIME = 7000;              // t+N-5 sec    // How long to wait to debounce light sensor changes in milliseconds    private static final int LIGHT_SENSOR_DELAY = 2000;//光线传感器时延    // light sensor events rate in microseconds    private static final int LIGHT_SENSOR_RATE = 1000000;//光线传感器频率    // For debouncing the proximity sensor in milliseconds    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;//距离传感器距离范围    // Cached secure settings; see updateSettingsValues()    private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;//键盘灯短暂时延    // Default timeout for screen off, if not found in settings database = 15 seconds.    private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15000;//默认屏幕超时时间,从Settings中获取    // flags for setPowerState    private static final int SCREEN_ON_BIT          = 0x00000001;    private static final int SCREEN_BRIGHT_BIT      = 0x00000002;    private static final int BUTTON_BRIGHT_BIT      = 0x00000004;    private static final int KEYBOARD_BRIGHT_BIT    = 0x00000008;    private static final int BATTERY_LOW_BIT        = 0x00000010;    // values for setPowerState    // SCREEN_OFF == everything off    private static final int SCREEN_OFF         = 0x00000000;//屏幕灭掉,进入睡眠状态    // SCREEN_DIM == screen on, screen backlight dim    private static final int SCREEN_DIM         = SCREEN_ON_BIT;//屏幕灭掉,依然在工作状态    // SCREEN_BRIGHT == screen on, screen backlight bright    private static final int SCREEN_BRIGHT      = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;//屏幕亮,处于工作状态    // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright    private static final int SCREEN_BUTTON_BRIGHT  = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;//屏幕亮,按键灯亮    // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright    private static final int ALL_BRIGHT         = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;//按键灯亮,键盘灯亮    // used for noChangeLights in setPowerState()    private static final int LIGHTS_MASK        = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;//屏幕亮,按键灯亮,键盘灯亮    boolean mAnimateScreenLights = true;    static final int ANIM_STEPS = 60/4;    // Slower animation for autobrightness changes    static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;    // These magic numbers are the initial state of the LEDs at boot.  Ideally    // we should read them from the driver, but our current hardware returns 0    // for the initial value.  Oops!    static final int INITIAL_SCREEN_BRIGHTNESS = 255;//屏幕初始状态 亮    static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF;//按键灯初始状态 灭    static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;//键盘灯初始状态 灭    private final int MY_UID;    private final int MY_PID;    private boolean mDoneBooting = false;    private boolean mBootCompleted = false;//开机完成标志位    private int mStayOnConditions = 0;    private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };    private final int[] mBroadcastWhy = new int[3];    private boolean mPreparingForScreenOn = false;    private boolean mSkippedScreenOn = false;    private boolean mInitialized = false;    private int mPartialCount = 0;    private int mPowerState;    // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,    // WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT or WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR    private int mScreenOffReason;    private int mUserState;    private boolean mKeyboardVisible = false;    private int mStartKeyThreshold = 0;    private boolean mUserActivityAllowed = true;    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 int mScreenOffTimeoutSetting;//屏幕超时设置    private int mMaximumScreenOffTimeout = Integer.MAX_VALUE;    private int mKeylightDelay;    private int mDimDelay;    private int mScreenOffDelay;    private int mWakeLockState;    private long mLastEventTime = 0;    private long mScreenOffTime;    private volatile WindowManagerPolicy mPolicy;    private final LockList mLocks = new LockList();    private Intent mScreenOffIntent;    private Intent mScreenOnIntent;    private LightsService mLightsService;//系统LightsService    private Context mContext;    private LightsService.Light mLcdLight;//屏    private LightsService.Light mButtonLight;//按键灯    private LightsService.Light mKeyboardLight;//键盘灯(若有实体输入法按键)    private LightsService.Light mAttentionLight;//通知等(若有信号灯)    private UnsynchronizedWakeLock mBroadcastWakeLock;//广播同步锁    private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;    private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;    private UnsynchronizedWakeLock mPreventScreenOnPartialLock;    private UnsynchronizedWakeLock mProximityPartialLock;    private HandlerThread mHandlerThread;    private HandlerThread mScreenOffThread;    private Handler mScreenOffHandler;    private Handler mHandler;        //计时器线程,主要完成管理屏幕超时操作,如当有用户点击屏幕时    //该计时器重新开始计时,直到无任何操作,且到屏幕时延最大时间,将屏幕灭掉    private final TimeoutTask mTimeoutTask = new TimeoutTask();    private final BrightnessState mScreenBrightness            = new BrightnessState(SCREEN_BRIGHT_BIT);//亮度管理    private boolean mStillNeedSleepNotification;    private boolean mIsPowered = false;    private IActivityManager mActivityService;    private IBatteryStats mBatteryStats;    private BatteryService mBatteryService;//电池服务    private SensorManager mSensorManager;//Sensor管理器    private Sensor mProximitySensor;//距离传感器    private Sensor mLightSensor;//光线传感器    private Sensor mLightSensorKB;//光线传感器    private boolean mLightSensorEnabled;//光线传感器是否可用    private float mLightSensorValue = -1;    private boolean mProxIgnoredBecauseScreenTurnedOff = false;    private int mHighestLightSensorValue = -1;    private boolean mLightSensorPendingDecrease = false;    private boolean mLightSensorPendingIncrease = false;    private float mLightSensorPendingValue = -1;    private int mLightSensorScreenBrightness = -1;    private int mLightSensorButtonBrightness = -1;    private int mLightSensorKeyboardBrightness = -1;    private boolean mDimScreen = true;    private boolean mIsDocked = false;    private long mNextTimeout;    private volatile int mPokey = 0;    private volatile boolean mPokeAwakeOnSet = false;    private volatile boolean mInitComplete = false;    private final HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();    // mLastScreenOnTime is the time the screen was last turned on    private long mLastScreenOnTime;    private boolean mPreventScreenOn;    private int mScreenBrightnessOverride = -1;    private int mButtonBrightnessOverride = -1;    private int mScreenBrightnessDim;    private boolean mUseSoftwareAutoBrightness;    private boolean mAutoBrightessEnabled;    private int[] mAutoBrightnessLevels;    private int[] mLcdBacklightValues;    private int[] mButtonBacklightValues;    private int[] mKeyboardBacklightValues;    private int mLightSensorWarmupTime;    boolean mUnplugTurnsOnScreen;    private int mWarningSpewThrottleCount;    private long mWarningSpewThrottleTime;    private int mAnimationSetting = ANIM_SETTING_OFF;    // Must match with the ISurfaceComposer constants in C++.    private static final int ANIM_SETTING_ON = 0x01;    private static final int ANIM_SETTING_OFF = 0x10;    // Used when logging number and duration of touch-down cycles    private long mTotalTouchDownTime;    private long mLastTouchDown;    private int mTouchCycles;    // could be either static or controllable at runtime    private static final boolean mSpew = false;    private static final boolean mDebugProximitySensor = (false || mSpew);    private static final boolean mDebugLightSensor = (false || mSpew);        private native void nativeInit();    private native void nativeSetPowerState(boolean screenOn, boolean screenBright);    private native void nativeStartSurfaceFlingerAnimation(int mode);


         本地方法的实现是在com_android_server_PowerManagerService.cpp中。

         首先看其构造方法:

    PowerManagerService() {        // Hack to get our uid...  should have a func for this.        long token = Binder.clearCallingIdentity();        MY_UID = Process.myUid();//获取本进程的UID以及PID        MY_PID = Process.myPid();        Binder.restoreCallingIdentity(token);//设置超时时间为1周。Power类封装了同Linux交互的接口。        // XXX remove this when the kernel doesn't timeout wake locks        Power.setLastUserActivityTimeout(7*24*3600*1000); // one week//初始化两个状态变量        // assume nothing is on yet        mUserState = mPowerState = 0;//将自己添加到看门狗Watchdog的监控管理队列中        // Add ourself to the Watchdog monitors.        Watchdog.getInstance().addMonitor(this);    }


          构造方法比较简单,接着分析init()函数,还函数完成了一些重要的初始化操作。

//电源管理的初始化操作函数,完成一些赋值操作,线程管理等    void init(Context context, LightsService lights, IActivityManager activity,            BatteryService battery) {        mLightsService = lights;        mContext = context;        mActivityService = activity;        mBatteryStats = BatteryStatsService.getService();        mBatteryService = battery;        mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);        mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);        mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);        mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);        nativeInit();//本地JNI方法        synchronized (mLocks) {            updateNativePowerStateLocked();        }        mInitComplete = false;//初始化未完成标志        //灭屏操作线程        //该操作的作用,手机一开机,屏幕亮度并不是立即就达到用户设置的亮度值        //而是有一个缓慢的变化过程,经过一段渐变之后才达到用户设置的亮度值,该现象在此处完成        mScreenOffThread = new HandlerThread("PowerManagerService.mScreenOffThread") {            @Override            protected void onLooperPrepared() {                mScreenOffHandler = new Handler();                synchronized (mScreenOffThread) {                    mInitComplete = true;                    mScreenOffThread.notifyAll();                }            }        };        mScreenOffThread.start();        synchronized (mScreenOffThread) {            while (!mInitComplete) {                try {                    mScreenOffThread.wait();                } catch (InterruptedException e) {                    // Ignore                }            }        }                mInitComplete = false;        //Handler 线程,初始化其他的一些线程,此处调用initInThread()函数        mHandlerThread = new HandlerThread("PowerManagerService") {            @Override            protected void onLooperPrepared() {                super.onLooperPrepared();                initInThread();            }        };        mHandlerThread.start();//此处为典型的线程A创建线程B,然后线程A等待线程B创建完成        synchronized (mHandlerThread) {            while (!mInitComplete) {                try {                    mHandlerThread.wait();                } catch (InterruptedException e) {                    // Ignore                }            }        }                nativeInit();        //当用户有任何操作可强制唤醒睡眠状态        synchronized (mLocks) {            updateNativePowerStateLocked();            // We make sure to start out with the screen on due to user activity.            // (They did just boot their device, after all.)            forceUserActivityLocked();            mInitialized = true;        }    }


          关键部分已经添加注释,接下来另外一个初始化操作函数是initInThread(),被init()调用。

//线程初始化操作,被init()调用    void initInThread() {        mHandler = new Handler();        mBroadcastWakeLock = new UnsynchronizedWakeLock(                                PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);        mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(                                PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);        mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(                                PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);        mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(                                PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);        mProximityPartialLock = new UnsynchronizedWakeLock(                                PowerManager.PARTIAL_WAKE_LOCK, "Proximity Partial", false);        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);        mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);        mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);        Resources resources = mContext.getResources();        mAnimateScreenLights = resources.getBoolean(                com.android.internal.R.bool.config_animateScreenLights);        mUnplugTurnsOnScreen = resources.getBoolean(                com.android.internal.R.bool.config_unplugTurnsOnScreen);        mScreenBrightnessDim = resources.getInteger(                com.android.internal.R.integer.config_screenBrightnessDim);        // read settings for auto-brightness        mUseSoftwareAutoBrightness = resources.getBoolean(                com.android.internal.R.bool.config_automatic_brightness_available);        if (mUseSoftwareAutoBrightness) {            mAutoBrightnessLevels = resources.getIntArray(                    com.android.internal.R.array.config_autoBrightnessLevels);            mLcdBacklightValues = resources.getIntArray(                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);            mButtonBacklightValues = resources.getIntArray(                    com.android.internal.R.array.config_autoBrightnessButtonBacklightValues);            mKeyboardBacklightValues = resources.getIntArray(                    com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues);            mLightSensorWarmupTime = resources.getInteger(                    com.android.internal.R.integer.config_lightSensorWarmupTime);        }       ContentResolver resolver = mContext.getContentResolver();        Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,                "(" + Settings.System.NAME + "=?) or ("                        + Settings.System.NAME + "=?) or ("                        + Settings.System.NAME + "=?) or ("                        + Settings.System.NAME + "=?) or ("                        + Settings.System.NAME + "=?) or ("                        + Settings.System.NAME + "=?)",                new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN,                        SCREEN_BRIGHTNESS_MODE, WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE},                null);        mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);        SettingsObserver settingsObserver = new SettingsObserver();        mSettings.addObserver(settingsObserver);        // pretend that the settings changed so we will get their initial state        settingsObserver.update(mSettings, null);        // register for the battery changed notifications        IntentFilter filter = new IntentFilter();        filter.addAction(Intent.ACTION_BATTERY_CHANGED);        mContext.registerReceiver(new BatteryReceiver(), filter);        filter = new IntentFilter();        filter.addAction(Intent.ACTION_BOOT_COMPLETED);        mContext.registerReceiver(new BootCompletedReceiver(), filter);        filter = new IntentFilter();        filter.addAction(Intent.ACTION_DOCK_EVENT);        mContext.registerReceiver(new DockReceiver(), filter);        // Listen for secure settings changes        mContext.getContentResolver().registerContentObserver(            Settings.Secure.CONTENT_URI, true,            new ContentObserver(new Handler()) {                public void onChange(boolean selfChange) {                    updateSettingsValues();                }            });        updateSettingsValues();        synchronized (mHandlerThread) {            mInitComplete = true;            mHandlerThread.notifyAll();        }    }


          至此,PMS的初始化创建已经完成。接下来分下几个重要的函数。

    void systemReady() {    //创建一个SensorManager 用于和系统的传感器系统交互,该部分多为native方法        mSensorManager = new SensorManager(mHandlerThread.getLooper());        mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);        // don't bother with the light sensor if auto brightness is handled in hardware        if (mUseSoftwareAutoBrightness) {            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);        }        mLightSensorKB = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);        if(mSensorManager != null && mLightSensorKB != null){            mSensorManager.registerListener(mLightListenerKB, mLightSensorKB,                    LIGHT_SENSOR_RATE);        }        // wait until sensors are enabled before turning on screen.        // some devices will not activate the light sensor properly on boot        // unless we do this.        if (mUseSoftwareAutoBrightness) {            // turn the screen on            setPowerState(SCREEN_BRIGHT);        } else {//不考虑软件自动亮度调节,所以执行此处            // turn everything on            setPowerState(ALL_BRIGHT);//设置手机电源状态为ALL_BRIGHT,即屏幕按键灯都打开        }        synchronized (mLocks) {            Slog.d(TAG, "system ready!");            mDoneBooting = true;//根据情况启动LightSensor            enableLightSensorLocked(mUseSoftwareAutoBrightness && mAutoBrightessEnabled);            long identity = Binder.clearCallingIdentity();            try {//通知BatteryStatsService 他将统计相关的电量使用情况                mBatteryStats.noteScreenBrightness(getPreferredBrightness());                mBatteryStats.noteScreenOn();            } catch (RemoteException e) {                // Nothing interesting to do.            } finally {                Binder.restoreCallingIdentity(identity);            }        }    }


          systemReady()完成的主要操作:传感器操作;电源状态设置;BatteryStatsService管理。

          bootCompleted()开机完成之后调用的函数。

    void bootCompleted() {        Slog.d(TAG, "bootCompleted");        synchronized (mLocks) {            mBootCompleted = true;            //此时将重新计算屏幕的超时时间            userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);            //根据当前的手机状态判断是否进入睡眠状态(如插上USB充电状态等)            updateWakeLockLocked();            mLocks.notifyAll();        }    }


        内部类WakeLock是android提供给应用程序获取电力资源的的唯一方法,只要还有地方使用WakeLock,系统就不会进入休眠状态。PMS中实现了PowerManager.java中夫人相应定义和方法。该类是电源管理系统唤醒与睡眠机制的核心。此处不再做详细分析。后续会专题研究。

        根据前面的分析,PMS有事需要进行点亮屏幕,打开按键灯等操作,为此android提供了Power类以及LightService满足PMS的要求。这两个类比较简单,但是背后的Kernel层相对复杂些。这些Light点亮操作均为LightService通过JNI读写文件节点,通过设置1或0来操作。此处不再详细研究。

        PMS中的userActivity()分析。关于userActivity()的作用。比如打开手机,并解锁进入桌面,如果在规定的时间内不操作手机,那么屏幕将变暗,最后关闭。如果在此过程中,触碰屏幕,屏幕又会重新亮起,这个触动屏幕的操作将导致userActivity()最终被调用。

//触动屏幕时,该函数将被调用,由PhoneWindowManager.java 等调用    private void userActivity(long time, long timeoutOverride, boolean noChangeLights,            int eventType, boolean force) {//mPokey和输入事件处理策略有关,如果此处的条件满足则表示忽略TOUCH_EVENTS        if (((mPokey & POKE_LOCK_IGNORE_TOUCH_EVENTS) != 0) && (eventType == TOUCH_EVENT)) {            if (false) {                Slog.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));            }            return;        }        synchronized (mLocks) {            if (mSpew) {                Slog.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time                        + " mUserActivityAllowed=" + mUserActivityAllowed                        + " mUserState=0x" + Integer.toHexString(mUserState)                        + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)                        + " mProximitySensorActive=" + mProximitySensorActive                        + " timeoutOverride=" + timeoutOverride                        + " force=" + force);            }            // ignore user activity if we are in the process of turning off the screen            if (isScreenTurningOffLocked()) {                Slog.d(TAG, "ignoring user activity while turning off screen");                return;            }            // Disable proximity sensor if if user presses power key while we are in the            // "waiting for proximity sensor to go negative" state.            if (mProximitySensorActive && mProximityWakeLockCount == 0) {                mProximitySensorActive = false;//控制接近传感器            }            if (mLastEventTime <= time || force) {                mLastEventTime = time;                if ((mUserActivityAllowed ) || force) {                    // Only turn on button backlights if a button was pressed                    // and auto brightness is disabled                    if (eventType == BUTTON_EVENT && !mUseSoftwareAutoBrightness) {                        mUserState =  SCREEN_BRIGHT; //设置用户事件导致的mUserState                    } else {                        // don't clear button/keyboard backlights when the screen is touched.                        mUserState |= SCREEN_BRIGHT;                    }                    int uid = Binder.getCallingUid();                    long ident = Binder.clearCallingIdentity();                    try {                      //通知BatteryStatsService进行电量统计                        mBatteryStats.noteUserActivity(uid, eventType);                    } catch (RemoteException e) {                        // Ignore                    } finally {                        Binder.restoreCallingIdentity(ident);                    }//重新计算WakeLock状态                    mWakeLockState = mLocks.reactivateScreenLocksLocked();                    setPowerState(mUserState | mWakeLockState, noChangeLights,                            WindowManagerPolicy.OFF_BECAUSE_OF_USER);                    if(mProximitySensorActive){                    //重新开始屏幕计时                    setTimeoutLocked(time, timeoutOverride, SCREEN_OFF);                    }                    else                    {                    //重新开始屏幕计时                        setTimeoutLocked(time,timeoutOverride,SCREEN_BRIGHT);                     }                }            }        }        if (mPolicy != null) {        //mPolicy指向PhoneWindowManager,用于和WindowManagerService交互            mPolicy.userActivity();        }    }


        该函数重点在于重置计时器超时函数setTimeoutLocked(),并由setPowerState()真正去设置屏幕状态,同时屏幕状态切换由TimeoutTask完成,此处不再详细研究。

        另外PMS系统中,与其交互的两个重要Service:BatteryService和BatteryStatsService。BatteryService提供接口用于获取电池信息,充电状态等。BatteryStatsService主要用于用电统计,通过它可知谁是系统中的耗电大户。

        至此,PMS分析结束。

       接下来,简单介绍下框架层其他几个相关类。

       首先,Power.java和andriod_os_Power.cpp

       PowerManagerSerivive.java中调用了一些本地方法,该文件作为这些方法的java层与jni的中间层,声明了本地接口。该本分实现是在Power.java中。
                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

        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);

        框架层,与电源管理相关的类还有一些,介于篇幅,不再一一分析了。

 

       2,内核层分析

        接下来简单看下内核层的相关文件,文件列表上述已经列出。

        其主要代码在下列位置:
       drivers/android/power.c
       其对Kernel 提供的接口函数有
              EXPORT_SYMBOL(android_init_suspend_lock); //初始化Suspendlock,在使用前必须做初始化
              EXPORT_SYMBOL(android_uninit_suspend_lock); //释放suspendlock 相关的资源
              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); //注册earlysuspend 的驱动
              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 wakelock
              "/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 wakelock 和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

       接着分析下,Kernel的wake lock唤醒操作。

       框架层acquireWakeLock()-- >android_os_Power.cpp-- >acquireWakeLock()-- >power.c-- >acquire_wake_lock()。

      

int acquire_wake_lock(int lock, const char* id){initialize_fds();// LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);if (g_error) return g_error;int fd;if (lock == PARTIAL_WAKE_LOCK) {fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];}else {return EINVAL;}return write(fd, id, strlen(id));}

 

       到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层framework层、JNI层、HAL层都已经介绍了就剩下Kernel层了。下面就应该是和kernel层进行交互了。但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信,在这个函数的最后不是还有一个返回语句return write(fd, id, strlen(id)),该write方法为重点。此时我们先跳过power.c中的acquire_wake_lock(),先分析/kernel/kernel/power/main.c中的相关方法,然后再回头分析power.c中的acquire_wake_lock()中的write(fd, id, strlen(id))。这样整个流程就能顺利连接起来。

       /kernel/kernel/power/main.c

#include <linux/kobject.h>#include <linux/string.h>#include <linux/resume-trace.h>#include <linux/workqueue.h>#include "power.h"DEFINE_MUTEX(pm_mutex);#ifdef CONFIG_PM_SLEEP/* Routines for PM-transition notifications */static BLOCKING_NOTIFIER_HEAD(pm_chain_head);int register_pm_notifier(struct notifier_block *nb){return blocking_notifier_chain_register(&pm_chain_head, nb);}EXPORT_SYMBOL_GPL(register_pm_notifier);int unregister_pm_notifier(struct notifier_block *nb){return blocking_notifier_chain_unregister(&pm_chain_head, nb);}EXPORT_SYMBOL_GPL(unregister_pm_notifier);int pm_notifier_call_chain(unsigned long val){return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)== NOTIFY_BAD) ? -EINVAL : 0;}/* If set, devices may be suspended and resumed asynchronously. */int pm_async_enabled = 1;static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,     char *buf){return sprintf(buf, "%d\n", pm_async_enabled);}static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,      const char *buf, size_t n){unsigned long val;if (strict_strtoul(buf, 10, &val))return -EINVAL;if (val > 1)return -EINVAL;pm_async_enabled = val;return n;}power_attr(pm_async);#ifdef CONFIG_PM_DEBUGint pm_test_level = TEST_NONE;static const char * const pm_tests[__TEST_AFTER_LAST] = {[TEST_NONE] = "none",[TEST_CORE] = "core",[TEST_CPUS] = "processors",[TEST_PLATFORM] = "platform",[TEST_DEVICES] = "devices",[TEST_FREEZER] = "freezer",};static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf){char *s = buf;int level;for (level = TEST_FIRST; level <= TEST_MAX; level++)if (pm_tests[level]) {if (level == pm_test_level)s += sprintf(s, "[%s] ", pm_tests[level]);elses += sprintf(s, "%s ", pm_tests[level]);}if (s != buf)/* convert the last space to a newline */*(s-1) = '\n';return (s - buf);}static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n){const char * const *s;int level;char *p;int len;int error = -EINVAL;p = memchr(buf, '\n', n);len = p ? p - buf : n;mutex_lock(&pm_mutex);level = TEST_FIRST;for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {pm_test_level = level;error = 0;break;}mutex_unlock(&pm_mutex);return error ? error : n;}power_attr(pm_test);#endif /* CONFIG_PM_DEBUG */#endif /* CONFIG_PM_SLEEP */struct kobject *power_kobj;static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,  char *buf){char *s = buf;#ifdef CONFIG_SUSPENDint i;for (i = 0; i < PM_SUSPEND_MAX; i++) {if (pm_states[i] && valid_state(i))s += sprintf(s,"%s ", pm_states[i]);}#endif#ifdef CONFIG_HIBERNATIONs += sprintf(s, "%s\n", "disk");#elseif (s != buf)/* convert the last space to a newline */*(s-1) = '\n';#endifreturn (s - buf);}static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,   const char *buf, size_t n){#ifdef CONFIG_SUSPEND#ifdef CONFIG_EARLYSUSPENDsuspend_state_t state = PM_SUSPEND_ON;#elsesuspend_state_t state = PM_SUSPEND_STANDBY;#endifconst char * const *s;#endifchar *p;int len;int error = -EINVAL;p = memchr(buf, '\n', n);len = p ? p - buf : n;/* First, check if we are requested to hibernate */if (len == 4 && !strncmp(buf, "disk", len)) {error = hibernate();  goto Exit;}#ifdef CONFIG_SUSPENDfor (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {if (*s && len == strlen(*s) && !strncmp(buf, *s, len))break;}if (state < PM_SUSPEND_MAX && *s)#ifdef CONFIG_EARLYSUSPENDif (state == PM_SUSPEND_ON || valid_state(state)) {error = 0;request_suspend_state(state);}#elseerror = enter_state(state);#endif#endif Exit:return error ? error : n;}power_attr(state);#ifdef CONFIG_PM_SLEEPstatic ssize_t wakeup_count_show(struct kobject *kobj,struct kobj_attribute *attr,char *buf){unsigned int val;return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;}static ssize_t wakeup_count_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n){unsigned int val;if (sscanf(buf, "%u", &val) == 1) {if (pm_save_wakeup_count(val))return n;}return -EINVAL;}power_attr(wakeup_count);#endif /* CONFIG_PM_SLEEP */#ifdef CONFIG_PM_TRACEint pm_trace_enabled;static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,     char *buf){return sprintf(buf, "%d\n", pm_trace_enabled);}static ssize_tpm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,       const char *buf, size_t n){int val;if (sscanf(buf, "%d", &val) == 1) {pm_trace_enabled = !!val;return n;}return -EINVAL;}power_attr(pm_trace);static ssize_t pm_trace_dev_match_show(struct kobject *kobj,       struct kobj_attribute *attr,       char *buf){return show_trace_dev_match(buf, PAGE_SIZE);}static ssize_tpm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n){return -EINVAL;}power_attr(pm_trace_dev_match);#endif /* CONFIG_PM_TRACE */#ifdef CONFIG_USER_WAKELOCKpower_attr(wake_lock);power_attr(wake_unlock);#endifstatic struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,&pm_trace_dev_match_attr.attr,#endif#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,&wakeup_count_attr.attr,#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif#ifdef CONFIG_USER_WAKELOCK&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#endifNULL,};static struct attribute_group attr_group = {.attrs = g,};#ifdef CONFIG_PM_RUNTIMEstruct workqueue_struct *pm_wq;EXPORT_SYMBOL_GPL(pm_wq);static int __init pm_start_workqueue(void){pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);return pm_wq ? 0 : -ENOMEM;}#elsestatic inline int pm_start_workqueue(void) { return 0; }#endifstatic int __init pm_init(void){int error = pm_start_workqueue();if (error)return error;hibernate_image_size_init();hibernate_reserved_size_init();power_kobj = kobject_create_and_add("power", NULL);if (!power_kobj)return -ENOMEM;return sysfs_create_group(power_kobj, &attr_group);}core_initcall(pm_init);


        这段代码虽然简短,但看起来是不是还是比较费劲,没关系,我们倒过来看就比较清楚了。上面代码中的最后一个函数pm_init(void)的返回值为 sysfs_create_group(power_kobj, &attr_group);的意思就是当我们在对sysfs/下相对的节点进行操作的时候会调用与attr_group 里的相关函数。还是上面一个文件main.c。

#ifdef CONFIG_USER_WAKELOCKpower_attr(wake_lock);power_attr(wake_unlock);#endifstatic struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,&pm_trace_dev_match_attr.attr,#endif#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,&wakeup_count_attr.attr,#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif#ifdef CONFIG_USER_WAKELOCK&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#endifNULL,};static struct attribute_group attr_group = {.attrs = g,};

       
        

        再往上面看其实就是指&wake_lock_attr.attr(对不同情况的操作会调用不同的attr_group)。power_attr(wake_lock)就是使具体的操作函数与其挂钩。我们现在来看一看这个挂钩过程是怎么实现的。

        power_attr(name)的定义是在/kernel/kernel/power/power.h

#define power_attr(_name) \static struct kobj_attribute _name##_attr = { \.attr = { \.name = __stringify(_name), \.mode = 0644, \}, \.show = _name##_show, \.store = _name##_store, \}


         在该函数中##的作用通俗点讲就是“连接”的意思。比如power_attr(wake_lock):

static struct kobj_attribute wake_lock_attr = { \.attr = { \.name = __stringify(wake_lock), \.mode = 0644, \}, \.show = wake_lock_show, \.store = wake_lock_store, \}

 

         函数wake_lock_store和wake_lock_show就定义在android/kernel/kernel/power/userwakelock.c中。因此当我们对/sys/power/wake_lock进行操作的时候就会调用到userwakelock.c中定义的wake_lock_store()函数。好了,我们该回到原来我们产生疑问的地方了,在 power.c中我们将重新研究一下这这段代码,这时我们还得关注其中的另一个函数initialize_fds()。

       

initialize_fds(void){// XXX: should be this://pthread_once(&g_initialized, open_file_descriptors);// XXX: not this:if (g_initialized == 0) {if(open_file_descriptors(NEW_PATHS) < 0) {open_file_descriptors(OLD_PATHS);on_state = "wake";off_state = "standby";}g_initialized = 1;}}


        其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS) ;而
        const char * const NEW_PATHS[] = {
                "/sys/power/wake_lock",
                "/sys/power/wake_unlock",
                "/sys/power/state"
        };

       总之经过着一些列的步骤后,最终我们将在 return write(fd, id, strlen(id))时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。

ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n){long timeout;struct user_wake_lock *l;mutex_lock(&tree_lock);l = lookup_wake_lock_name(buf, 1, &timeout);if (IS_ERR(l)) {n = PTR_ERR(l);goto bad_name;}if (debug_mask & DEBUG_ACCESS)pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);if (timeout)wake_lock_timeout(&l->wake_lock, timeout);elsewake_lock(&l->wake_lock);bad_name:mutex_unlock(&tree_lock);return n;}


          该函数执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。

         至此唤醒流程分析结束。

         最后看一下kernel的睡眠休眠流程。即按下Power键或者系统屏幕超时后的状态。

         按下Power键或者屏幕超时后系统会进入:PMS的goToSleep(long time)。goToSleepWithReason()会调用goToSleepLocked()方法,接着会调用setPowerState();而
setPowerState()方法里会调用setScreenStateLocked(),setScreenStateLocked()又会调用到Power类中的JNI接口setScreenState(),其具体实现是在android_os_Power.cpp文件中。  接着该函数中return set_screen_state()的实现是android/hardware/libhardware_legacy/power/power.c的set_screen_state(int on)    函数。

    

set_screen_state(int on){QEMU_FALLBACK(set_screen_state(on));LOGI("*** set_screen_state %d", on);initialize_fds();//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,// systemTime(), strerror(g_error));if (g_error) return g_error;char buf[32];int len;if(on)len = snprintf(buf, sizeof(buf), "%s", on_state);elselen = snprintf(buf, sizeof(buf), "%s", off_state);buf[sizeof(buf) - 1] = '\0';len = write(g_fds[REQUEST_STATE], buf, len);if(len < 0) {LOGE("Failed setting last user activity: g_error=%d\n", g_error);}return 0;}


          代码到这里跟前面唤醒部分很相似,如果接着往下分析的话,可以套用上面分析思路,最终len = write(g_fds[REQUEST_STATE], buf, len);语句调用的是android//kernel/kernel/power/main.c中的set_screen_state( );当我们在sys/power/state(android/hardware/libhardware_legacy/power/power.c)进行读写操作的时候,(linux/kernel/power/main.c)中的state_store()函数会被调用,在该函数中会分成两个分支:     

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n){#ifdef CONFIG_SUSPEND#ifdef CONFIG_EARLYSUSPENDsuspend_state_t state = PM_SUSPEND_ON;#elsesuspend_state_t state = PM_SUSPEND_STANDBY;#endifconst char * const *s;#endifchar *p;int len;int error = -EINVAL;p = memchr(buf, '\n', n);len = p ? p - buf : n;if (len == 4 && !strncmp(buf, "disk", len)) {error = hibernate();goto Exit;}#ifdef CONFIG_SUSPENDfor (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {if (*s && len == strlen(*s) && !strncmp(buf, *s, len))break;}if (state < PM_SUSPEND_MAX && *s)#ifdef CONFIG_EARLYSUSPENDif (state == PM_SUSPEND_ON || valid_state(state)) {error = 0;request_suspend_state(state);}#elseerror = enter_state(state);#endif#endifExit:return error ? error : n;}


        Android特有的earlysuspend: request_suspend_state(state)
        Linux标准的suspend: enter_state(state)
        注意:如果CONFIG_EARLYSUSPEND宏开的话,kernel会先走earlysuspend,反之则直接走suspend;从这里开始就要分两个分支了,如果支持earlysuspend的话就进入 request_suspend_state(state)函数,如果不支持的话就进入标准Linux的enter_state(state)函数。这两个函数分别在两个文件中kernel/kernel/power/earlysuspend.c和suspend.c。现在再回过头来看的话,感觉整个android中睡眠唤醒机制还是很清晰的。这两个函数体里又做了什么,在这里就不再做具体分析,大家可以自己对照代码或者上网查资料,因为本文的主旨是带读者从最上层应用层一直到最底层kernel层,把整个android的电源管理机制给走通。

       四,文章总结

       本文简单介绍了android电源管理的机制,分别从框架层和内核层研读了android源码电源管理的整体架构,并重点分析了框架层的PMS以及内核层的唤醒睡眠机制,限于个人能力以及时间关系,不做更深入研究。文中有所失误也在所难免。

       至此,所有分析结束。(在此文的分析过程中,参考了大量的优秀书籍及网络资料,不一一列出,但衷心感谢)

 

 

 

原创粉丝点击