Speaking of PowerManagerService second WakeLock

WakeLock is a locking mechanism, as long as the process holds the lock, CPU has been at work, the system will not enter the sleep state.

For information on using comments in WakeLock fact PowerManager class we have been given, look Description:

    /**
     * This class gives you control of the power state of the device.
     *
     * <p>
     * <b>Device battery life will be significantly affected by the use of this API.</b>
     * Do not acquire {@link WakeLock}s unless you really need them, use the minimum levels
     * possible, and be sure to release them as soon as possible.
     * </p><p>
     * The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}.
     * This will create a {@link PowerManager.WakeLock} object.  You can then use methods
     * on the wake lock object to control the power state of the device.
     * </p><p>
     * In practice it's quite simple:
     * {@samplecode
     * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
     * PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
     * wl.acquire();
     *   ..screen will stay on during this section..
     * wl.release();
     * }
     * </p><p>
     * The following wake lock levels are defined, with varying effects on system power.
     * <i>These levels are mutually exclusive - you may only specify one of them.</i>

That realization is the code:

     PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
     PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
     wl.acquire();
     //screen will stay on during this section..
     wl.release();

We look newWakeLock method:

    public WakeLock newWakeLock(int levelAndFlags, String tag) {
        validateWakeLockParameters(levelAndFlags, tag);
        // 创建一个WakeLock并返回
        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
    }

    /** @hide */
    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:
            case DOZE_WAKE_LOCK:
            case DRAW_WAKE_LOCK:
                break;
            default:
                throw new IllegalArgumentException("Must specify a valid wake lock level.");
        }
        // tag不为空,否则会抛异常
        if (tag == null) {
            throw new IllegalArgumentException("The tag must not be null.");
        }
    }

WakeLock view of creation:

        WakeLock(int flags, String tag, String packageName) {
            // flag参数
            mFlags = flags;
            // tag不为空
            mTag = tag;
            mPackageName = packageName;
            // 创建一个Binder对象
            mToken = new Binder();
            mTraceName = "WakeLock (" + mTag + ")";
        }

1.wakelock level (wake lock level)

PARTIAL_WAKE_LOCK: to ensure that the CPU is running, allows the screen and keyboard backlight off;

SCREEN_DIM_WAKE_LOCK (abandoned): ensure screen opens (but may darken), allows the keyboard backlight off; Power button if pressed, or will enter a sleep state;

SCREEN_BRIGHT_WAKE_LOCK (abandoned): to ensure that the screen is on at full brightness, allows the keyboard backlight off; Power button if pressed, or will enter a sleep state;

FULL_WAKE_LOCK (abandoned): to ensure that the whole brightness of the screen and keyboard backlight; Power button if pressed, or will enter a sleep state;

PROXIMITY_SCREEN_OFF_WAKE_LOCK: When the sensor is activated, turning off the screen; shortly after the object is removed, the screen is opened again;

DOZE_WAKE_LOCK (@hide): screen into a low power state, allowing the CPU to suspend;

DRAW_WAKE_LOCK (@hide): keeping the device sufficiently to allow drawing awake;

2.wakelock flag (wake lock flag)

ACQUIRE_CAUSES_WAKEUP: lock screen after the acquisition;

ON_AFTER_RELEASE: When the lock is released, then the system delays for a blank;

UNIMPORTANT_FOR_LOGGING: The lock is not important to record the event, if later acquired an important wake-lock, it is treated as wake lock to be recorded;

3.acquire (Application Lock)

When you create wakelock, you need to apply for wakelock to ensure normal operation of the screen. View source code implementation:

        public void acquire() {
            // 加上同步锁,mToken
            synchronized (mToken) {
                // 调用acquireLocked函数
                acquireLocked();
            }
        }

        // 含参的acquire方法
        public void acquire(long timeout) {
            synchronized (mToken) {
                acquireLocked();
                mHandler.postDelayed(mReleaser, timeout);
            }
        }

We can see whether or not the reference method with the Senate will acquire to call acquireLocked method, look:

        private void acquireLocked() {
            mInternalCount++;
            mExternalCount++;
            // 唤醒锁非计数引入或计数为1
            if (!mRefCounted || mInternalCount == 1) {
                // 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);
                Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
                try {
                    // 调用PowerManagerService中的acquireWakeLock
                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                            mHistoryTag);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                mHeld = true;
            }
        }

Then look to achieve acquireWakeLock method PowerManagerService:

        @Override // Binder call
        public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
                WorkSource ws, String historyTag) {
            if (lock == null) {
                throw new IllegalArgumentException("lock must not be null");
            }
            if (packageName == null) {
                throw new IllegalArgumentException("packageName must not be null");
            }
            PowerManager.validateWakeLockParameters(flags, tag);

            // 检查 WAKE_LOCK 权限
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
            if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
                mContext.enforceCallingOrSelfPermission(
                        android.Manifest.permission.DEVICE_POWER, null);
            }
            if (ws != null && !ws.isEmpty()) {
                // 如果ws不为空,需要检查UPDATE_DEVICE_STATS 权限
                mContext.enforceCallingOrSelfPermission(
                        android.Manifest.permission.UPDATE_DEVICE_STATS, null);
            } else {
                ws = null;
            }

            final int uid = Binder.getCallingUid();
            final int pid = Binder.getCallingPid();
            final long ident = Binder.clearCallingIdentity();
            try {
                // 调用acquireWakeLockInternal函数
                acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

4.release (lock release)

After acquire the application lock, the lock process has been held in a bright screen, and other state, when the end of these states, we need to release the lock and could not have been held. Then go to call the release method, look at the source code to achieve:

    public void release() {
        release(0);
    }

    public void release(int flags) {
        // 同步锁,mToken
        synchronized (mToken) {
            if (mInternalCount > 0) {
                // internal count must only be decreased if it is > 0 or state of
                // the WakeLock object is broken.
                mInternalCount--;
            }
            if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
                mExternalCount--;
            }
            // 唤醒锁非引用计数或内部计数为0
            if (!mRefCounted || mInternalCount == 0) {
                mHandler.removeCallbacks(mReleaser);
                if (mHeld) {
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                    try {
                        // 调用PowerManagerService的releaseWakeLock函数
                        mService.releaseWakeLock(mToken, flags);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                    mHeld = false;
                }
            }
            // 唤醒锁引用计数且计数<0,抛WakeLock under-locked异常
            if (mRefCounted && mExternalCount < 0) {
                throw new RuntimeException("WakeLock under-locked " + mTag);
            }
        }
    }

5. Count / lock mode does not count

In the above talk acquire and release methods when it comes to have a word count. By default, Wake lock is the reference count, if the wake-lock is a reference count, each call to acquire must be balanced by an equal number of calls for release. That application once wakeLock, release the corresponding time required;

If the lock is not wake count, then a release of the call can lock solution out wakeLock, regardless acquire call several times.

Source is controlled by mRefCounted this boolean value: true if the reference count wakeup lock; lock to false indicating that no reference wake. It can be assigned to mRefCounted by setReferenceCounted method.

        public void setReferenceCounted(boolean value) {
            synchronized (mToken) {
                mRefCounted = value;
            }
        }

        // 默认为true,即引用计数
        private boolean mRefCounted = true;

PS: Source is based on the platform Android 10

Published 18 original articles · won praise 5 · views 20000 +

Guess you like

Origin blog.csdn.net/zplxl99/article/details/103021323