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以及内核层的唤醒睡眠机制,限于个人能力以及时间关系,不做更深入研究。文中有所失误也在所难免。
至此,所有分析结束。(在此文的分析过程中,参考了大量的优秀书籍及网络资料,不一一列出,但衷心感谢)
- Android电源管理机制剖析
- Android电源管理机制分析(zz)
- Android电源管理机制的实现
- Windows 8系统电源管理机制的改进
- cocos2d-x内存管理机制剖析
- android电源
- android电源
- 《python源码剖析》笔记 pythonm内存管理机制
- WEB状态管理机制剖析(cookie、session)
- android应用程序管理机制
- Android窗口管理机制
- android内存管理机制
- android 低内存管理机制
- Android中的内存管理机制
- Android内存管理机制详解
- Android内存管理机制详解
- android窗口管理机制
- Android内存管理机制详解
- 关于安装lamp环境之后出现的问题的排查
- Oracle 查询计划分析
- 让Maven正确处理javac警告
- 学会安排事情的优先级
- android中的spinner显示为图片列表
- Android电源管理机制剖析
- 逃离社交网络--- 我们得谈谈
- linux下一个网卡配置多个IP 详细出处参考:http://www.jb51.net/LINUXjishu/10935.html
- Android开发笔记之《Activity与Intent》
- 【jiasuba】chrome浏览器经常卡住,无法滚动网页解决方法
- Java 文件分块上传服务器端源代码
- VS2010下编译配置qwt
- Android 开发中使用 SQLite 数据库
- hdu3732 Ahui Writes Word (多重背包)