Android电源管理机制剖析

2019-07-13 22:06发布

        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 mPokeLocks = new HashMap(); // 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' ", 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 #include #include #include #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 ", 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_DEBUG int 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]); else s += sprintf(s, "%s ", pm_tests[level]); } if (s != buf) /* convert the last space to a newline */ *(s-1) = ' '; 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); 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_SUSPEND int 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_HIBERNATION s += sprintf(s, "%s ", "disk"); #else if (s != buf) /* convert the last space to a newline */ *(s-1) = ' '; #endif return (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_EARLYSUSPEND suspend_state_t state = PM_SUSPEND_ON; #else suspend_state_t state = PM_SUSPEND_STANDBY; #endif const char * const *s; #endif char *p; int len; int error = -EINVAL; p = memchr(buf, ' ', 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_SUSPEND for (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_EARLYSUSPEND if (state == PM_SUSPEND_ON || valid_state(state)) { error = 0; request_suspend_state(state); } #else error = enter_state(state); #endif #endif Exit: return error ? error : n; } power_attr(state); #ifdef CONFIG_PM_SLEEP static 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 ", 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_TRACE int pm_trace_enabled; static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d ", pm_trace_enabled); } static ssize_t pm_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_t pm_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_WAKELOCK power_attr(wake_lock); power_attr(wake_unlock); #endif static 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 #endif NULL, }; static struct attribute_group attr_group = { .attrs = g, }; #ifdef CONFIG_PM_RUNTIME struct 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; } #else static inline int pm_start_workqueue(void) { return 0; } #endif static 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_WAKELOCK power_attr(wake_lock); power_attr(wake_unlock); #endif static 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 #endif NULL, }; 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 (de