1. 程式人生 > >Android電源管理機制剖析

Android電源管理機制剖析

        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_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) = '\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_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\n", "disk");
#else
	if (s != buf)
		/* convert the last space to a newline */
		*(s-1) = '\n';
#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', 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\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_TRACE
int 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_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[] = {