Android WakeLock詳解,androidwakelock

來源:互聯網
上載者:User

Android WakeLock詳解,androidwakelock
目錄

  • 目錄
  • 前言
  • WakeLock使用
    • WakeLock levelAndFlags和使用情境
    • 參考情境
  • WakeLock源碼分析
  • 結束語

前言

不知道大家是否也想過,當你手機滅屏的時候,為什麼一條或者QQ資訊能夠點亮你的螢幕?
答案就是Android的WakeLock機制。這篇文章主要是介紹如何使用WakeLock,應該還達不到詳解的地步,各位同學感興趣的可以看一下WakeLock的基本使用方法。

WakeLock使用

我們先來看一下Android官方對PowerManager和WakeLock的註解:

  • PowerManager:This class gives you control of the power state of the device.
  • WakeLock:A wake lock is a mechanism to indicate that your application needs to have the device stay on.
WakeLock levelAndFlags和使用情境
Level 保持CPU 保持螢幕亮 保持鍵盤亮 使用情境
PARTIAL_WAKE_LOCK 長時間啟動並執行後台服務,例如Service等
SCREEN_DIM_WAKE_LOCK 低亮度 除非必須保持CPU運行直至運算完成,否則請使用FLAG_KEEP_SCREEN_ON方式
SCREEN_BRIGHT_WAKE_LOCK 高亮度 除非必須保持CPU運行直至運算完成,否則請使用FLAG_KEEP_SCREEN_ON方式
FULL_WAKE_LOCK 高亮度 除非必須保持CPU運行直至運算完成,否則請使用FLAG_KEEP_SCREEN_ON方式

除了這四個Level之外,PowerMager還提供了兩個Flag,可以配合Level使用。

FLAG 描述
ACQUIRE_CAUSES_WAKEUP 預設情況下wake locks並不是馬上開啟CPU、Screen或者Keyboard的illumination(對於Screen是Dim或Bright,Keyboard是Bright. wake locks只是在被開啟後(比如使用者的活動),讓裝置延續(儲存)你設定開啟的狀態. 但是如果加上ACQUIRE_CAUSES_WAKEUP就可以讓Screen或Keyboar的illumination沒開啟的情況,馬上開啟它們。 典型的應用就是在收到一個重要的notifications時,需要馬上點亮螢幕。
ON_AFTER_RELEASE 當wake lock被釋放的時候,當前調用wake lock的activity的計數器會被重設,所以螢幕會繼續亮一段時間

注意:
這兩個Flag和PARTIAL_WAKE_LOCK組合是沒有作用的。

參考情境

寫一個應用,可以完成如下情境:

具體代碼如下:

MainActivity.java

    private void testWakeLock() {        new Thread(new Runnable() {            private void printLog() {                for (int i = 0; i < 10; i ++) {                    Log.e("wangzhengyi", "hello log " + i);                    try {                        Thread.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }            @Override            public void run() {                Log.e("wangzhengyi", "ready to acquire wakelock!");                try {                    Thread.sleep(10000);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                TestWakeLock twl = new TestWakeLock(MainActivity.this);                twl.acquireWakeLock();                printLog();                twl.releaseWakeLock();            }        }).start();    }

TestWakeLock.java

import android.content.Context;import android.os.PowerManager;import android.os.PowerManager.WakeLock;import android.util.Log;public class TestWakeLock {    private WakeLock mWakeLock;    private Context mContext;    public TestWakeLock(Context context) {        this.mContext = context;    }    public void acquireWakeLock() {        if (mWakeLock == null) {            PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);            mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ZHENGYI.WZY");            if (mWakeLock != null) {                mWakeLock.acquire();                Log.e("wangzhengyi", "get powermanager wakelock!");            }        }    }    public void releaseWakeLock() {        if (mWakeLock != null) {            mWakeLock.release();            Log.e("wangzhengyi", "release powermanager wakelock!");        }    }}

AndroidManifest.xml

<uses-permission android:name="android.permission.WAKE_LOCK"/>
WakeLock源碼分析

不深入到WakeLock源碼,怎麼敢稱為詳解,對吧!!接下來,我們看一下WakeLock的源碼實現。

    public WakeLock newWakeLock(int levelAndFlags, String tag) {        validateWakeLockParameters(levelAndFlags, tag);        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());    }    public static void validateWakeLockParameters(int levelAndFlags, String tag) {        switch (levelAndFlags & WAKE_LOCK_LEVEL_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("Must specify a valid wake lock level.");        }        if (tag == null) {            throw new IllegalArgumentException("The tag must not be null.");        }    }

可以看到,newWakeLock方法首先檢測LevelAndFlags和Tag的合法性,代碼很簡單,大家可以自己看一下。其實就是:tag不可為空,Level必須用PowerManager提供的幾個Level。

接下來,我們就進入到WakeLock的建構函式了。WakeLock是PowerManager的內部類。這裡我刪除了WakeLock類中暫時我們用不到的方法。

    public final class WakeLock {        private final int mFlags;        private final String mTag;        private final String mPackageName;        private final IBinder mToken;        private int mCount;        private boolean mRefCounted = true;        private boolean mHeld;        private final Runnable mReleaser = new Runnable() {            public void run() {                release();            }        };        WakeLock(int flags, String tag, String packageName) {            mFlags = flags;            mTag = tag;            mPackageName = packageName;            mToken = new Binder();        }        /**         * Acquires the wake lock.         * <p>         * Ensures that the device is on at the level requested when the wake         * lock was created.         * </p>         */        public void acquire() {            synchronized (mToken) {                acquireLocked();            }        }        private void acquireLocked() {            if (!mRefCounted || mCount++ == 0) {                // Do this even if the wake lock is already thought to be held                // (mHeld == true)                // because non-reference counted wake locks are not always                // properly released.                // For example, the keyguard's wake lock might be forcibly                // released by the                // power manager without the keyguard knowing. A subsequent call                // to acquire                // should immediately acquire the wake lock once again despite                // never having                // been explicitly released by the keyguard.                mHandler.removeCallbacks(mReleaser);                try {                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);                } catch (RemoteException e) {                }                mHeld = true;            }        }        /**         * Releases the wake lock.         * <p>         * This method releases your claim to the CPU or screen being on. The         * screen may turn off shortly after you release the wake lock, or it         * may not if there are other wake locks still held.         * </p>         */        public void release() {            release(0);        }        /**         * Releases the wake lock with flags to modify the release behavior.         * <p>         * This method releases your claim to the CPU or screen being on. The         * screen may turn off shortly after you release the wake lock, or it         * may not if there are other wake locks still held.         * </p>         *         * @param flags         *            Combination of flag values to modify the release behavior.         *            Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is         *            supported.         *         *            {@hide}         */        public void release(int flags) {            synchronized (mToken) {                if (!mRefCounted || --mCount == 0) {                    mHandler.removeCallbacks(mReleaser);                    if (mHeld) {                        try {                            mService.releaseWakeLock(mToken, flags);                        } catch (RemoteException e) {                        }                        mHeld = false;                    }                }                if (mCount < 0) {                    throw new RuntimeException("WakeLock under-locked " + mTag);                }            }        }        /**         * Returns true if the wake lock has been acquired but not yet released.         *         * @return True if the wake lock is held.         */        public boolean isHeld() {            synchronized (mToken) {                return mHeld;            }        }    }

我們以acquire方法為例,通過對源碼的分析,我們發現擷取WakeLock的實現是通過mService進行的:

mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);

而mService是在PowerManager類裡執行個體化的:

final IPowerManager mService;

mService執行個體化類為/frameworks/base/services/java/com/android/server/power/PowerManagerService.java,而到這裡類裡,你最終發現acquireWakeLock是由JNI層的native方法實現的。

private static native void nativeAcquireSuspendBlocker(String name);

而這個方法的實現是在/frameworks/base/services/jni/com_android_server_power_PowerManagerService.cpp代碼中:

static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {    ScopedUtfChars name(env, nameStr);    acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());}

這個acquire_wake_lock是在/hardware/libhardware_legacy/power/power.c裡定義的

acquire_wake_lock(int lock, const char* id){    initialize_fds();//    ALOGI("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));}

可以看到,acquire wake lock真正的實現是在fd所指向的檔案中寫了一串字元即可。
fd所指向的檔案定義如下:

const char * const NEW_PATHS[] = {    "/sys/power/wake_lock",    "/sys/power/wake_unlock",};
結束語

好了,到此Android WakeLock分析結束,歡迎大家拍磚

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.