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 implements
LocalPowerManager, 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