Android电源管理机制剖析

本文深入剖析了Android的电源管理系统,从电源管理相关文件、总体流程到系统机制,详细探讨了框架层和内核层的实现。重点分析了PowerManagerService在应用层与内核层间的交互,以及唤醒和睡眠的控制流程。通过本文,读者可以理解Android如何通过Wake Lock和定时器管理电源状态,以及在内核层如何通过wakelock队列控制系统的功耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        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)
  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值