سؤال

In my background service I was acquiring partial wake lock using acquire() (without arguments) and was releasing it manually when I didn't need it anymore.

At that time, some Xperia users were complaining about problems with Xperia's Stamina mode. I found this article: Optimizing for Sony's Stamina Mode

  1. Don’t use wake locks Wake locks are in general quite bad for power consumption, as they keep the entire Android system awake. If wake locks are used, make sure that they are timed wake locks so that the taken wake lock does not exist for a too long time. Time your wake lock so that it is released after your task is complete. You can see it used in an example at Java Monday.

So I've started using timed wake locks (using acquire(timeout) instead of acquire()). The problem is with the release. I'm still releasing manually, since in most cases I will not need the lock anymore sooner than the timeout will expire.

The problem is that automatic release. I'll explain. Timed acquire is implemented this way (taken from android-19 sources):

public void acquire(long timeout) {
    synchronized (mToken) {
        acquireLocked();
        mHandler.postDelayed(mReleaser, timeout);
    }
}

mReleaser is initialized as following (from android-19 sources):

private final Runnable mReleaser = new Runnable() {
    public void run() {
        release();
    }
};

And release() throws RuntimeException if the lock is not held anymore:

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);
        }
    }
}

So the problem is that when I release it manually, it still tries to release it automatically after timeout expiration, and the wake lock gets under-locked.

The question is: how can I still use timed wake lock, while being able to release it manually before the timeout expiration?

هل كانت مفيدة؟

المحلول

As a solution (or work around - if someone knows better solution please comment) wake locks without reference counter:

mWakeLock.setReferenceCounted(false);

This prevents under-locking

نصائح أخرى

In the code you copied above the highlighted line removes the callback added by acquire when the reference count drops to zero so assuming you are acquiring and then releasing just once per acquire then you should should be okay. If you actually hit the timeout though how do you know to stop the manual release...

if (!mRefCounted || --mCount == 0) {
   mHandler.removeCallbacks(mReleaser);           /// This removes the callback
   if (mHeld) {
        try {
            mService.releaseWakeLock(mToken, flags);
        } catch (RemoteException e) {
        }
        mHeld = false;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top