diff options
9 files changed, 317 insertions, 61 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 19830c3990a1..5a293c52bdd4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31738,9 +31738,14 @@ package android.os { method public void release(); method public void release(int); method public void setReferenceCounted(boolean); + method public void setStateListener(@NonNull java.util.concurrent.Executor, @Nullable android.os.PowerManager.WakeLockStateListener); method public void setWorkSource(android.os.WorkSource); } + public static interface PowerManager.WakeLockStateListener { + method public void onStateChanged(boolean); + } + public class Process { ctor public Process(); method public static final long getElapsedCpuTime(); diff --git a/core/java/Android.bp b/core/java/Android.bp index 8234f03100ca..5649c5f1f7db 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -128,6 +128,7 @@ filegroup { "android/os/IThermalStatusListener.aidl", "android/os/IThermalService.aidl", "android/os/IPowerManager.aidl", + "android/os/IWakeLockCallback.aidl", ], } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index df5b7bc237df..4fe6524dee27 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -21,15 +21,16 @@ import android.os.BatterySaverPolicyConfig; import android.os.ParcelDuration; import android.os.PowerSaveState; import android.os.WorkSource; +import android.os.IWakeLockCallback; /** @hide */ interface IPowerManager { void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws, - String historyTag, int displayId); + String historyTag, int displayId, IWakeLockCallback callback); void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, - int uidtoblame, int displayId); + int uidtoblame, int displayId, IWakeLockCallback callback); @UnsupportedAppUsage void releaseWakeLock(IBinder lock, int flags); void updateWakeLockUids(IBinder lock, in int[] uids); @@ -40,6 +41,7 @@ interface IPowerManager boolean setPowerModeChecked(int mode, boolean enabled); void updateWakeLockWorkSource(IBinder lock, in WorkSource ws, String historyTag); + void updateWakeLockCallback(IBinder lock, IWakeLockCallback callback); boolean isWakeLockLevelSupported(int level); void userActivity(int displayId, long time, int event, int flags); diff --git a/core/java/android/os/IWakeLockCallback.aidl b/core/java/android/os/IWakeLockCallback.aidl new file mode 100644 index 000000000000..89615d22421e --- /dev/null +++ b/core/java/android/os/IWakeLockCallback.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** + * @hide + */ +oneway interface IWakeLockCallback { + oneway void onStateChanged(boolean enabled); +} diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 5bd8588d8970..315eef78724e 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2770,6 +2770,23 @@ public final class PowerManager { public static final int PRE_IDLE_TIMEOUT_MODE_SHORT = 2; /** + * A listener interface to get notified when the wakelock is enabled/disabled. + */ + public interface WakeLockStateListener { + /** + * Frameworks could disable the wakelock because either device's power allowlist has + * changed, or the app's wakelock has exceeded its quota, or the app goes into cached + * state. + * <p> + * This callback is called whenever the wakelock's state has changed. + * </p> + * + * @param enabled true is enabled, false is disabled. + */ + void onStateChanged(boolean enabled); + } + + /** * A wake lock is a mechanism to indicate that your application needs * to have the device stay on. * <p> @@ -2800,6 +2817,8 @@ public final class PowerManager { private String mHistoryTag; private final String mTraceName; private final int mDisplayId; + private WakeLockStateListener mListener; + private IWakeLockCallback mCallback; private final Runnable mReleaser = () -> release(RELEASE_FLAG_TIMEOUT); @@ -2890,7 +2909,7 @@ public final class PowerManager { Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0); try { mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, - mHistoryTag, mDisplayId); + mHistoryTag, mDisplayId, mCallback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3083,6 +3102,45 @@ public final class PowerManager { } }; } + + /** + * Set the listener to get notified when the wakelock is enabled/disabled. + * + * @param executor {@link Executor} to handle listener callback. + * @param listener listener to be added, set the listener to null to cancel a listener. + */ + public void setStateListener(@NonNull @CallbackExecutor Executor executor, + @Nullable WakeLockStateListener listener) { + Preconditions.checkNotNull(executor, "executor cannot be null"); + synchronized (mToken) { + if (listener != mListener) { + mListener = listener; + if (listener != null) { + mCallback = new IWakeLockCallback.Stub() { + public void onStateChanged(boolean enabled) { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + listener.onStateChanged(enabled); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + } else { + mCallback = null; + } + if (mHeld) { + try { + mService.updateWakeLockCallback(mToken, mCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + } } /** diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 73ec2cd66ac1..77d63100032c 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -33,6 +33,7 @@ import android.metrics.LogMaker; import android.net.Uri; import android.os.BatteryStats; import android.os.Handler; +import android.os.IWakeLockCallback; import android.os.Looper; import android.os.Message; import android.os.PowerManager; @@ -215,14 +216,15 @@ public class Notifier { * Called when a wake lock is acquired. */ public void onWakeLockAcquired(int flags, String tag, String packageName, - int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { + int ownerUid, int ownerPid, WorkSource workSource, String historyTag, + IWakeLockCallback callback) { if (DEBUG) { Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag + "\", packageName=" + packageName + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid + ", workSource=" + workSource); } - + notifyWakeLockListener(callback, true); final int monitorType = getBatteryStatsWakeLockMonitorType(flags); if (monitorType >= 0) { try { @@ -300,8 +302,9 @@ public class Notifier { */ public void onWakeLockChanging(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, - int newFlags, String newTag, String newPackageName, int newOwnerUid, - int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { + IWakeLockCallback callback, int newFlags, String newTag, String newPackageName, + int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag, + IWakeLockCallback newCallback) { final int monitorType = getBatteryStatsWakeLockMonitorType(flags); final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); @@ -323,10 +326,16 @@ public class Notifier { } catch (RemoteException ex) { // Ignore } + } else if (!PowerManagerService.isSameCallback(callback, newCallback)) { + onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag, + null /* Do not notify the old callback */); + onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, + newWorkSource, newHistoryTag, newCallback /* notify the new callback */); } else { - onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag); + onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag, + callback); onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, - newWorkSource, newHistoryTag); + newWorkSource, newHistoryTag, newCallback); } } @@ -334,14 +343,15 @@ public class Notifier { * Called when a wake lock is released. */ public void onWakeLockReleased(int flags, String tag, String packageName, - int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { + int ownerUid, int ownerPid, WorkSource workSource, String historyTag, + IWakeLockCallback callback) { if (DEBUG) { Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag + "\", packageName=" + packageName + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid + ", workSource=" + workSource); } - + notifyWakeLockListener(callback, false); final int monitorType = getBatteryStatsWakeLockMonitorType(flags); if (monitorType >= 0) { try { @@ -859,6 +869,18 @@ public class Notifier { return enabled && dndOff; } + private void notifyWakeLockListener(IWakeLockCallback callback, boolean isEnabled) { + if (callback != null) { + mHandler.post(() -> { + try { + callback.onStateChanged(isEnabled); + } catch (RemoteException e) { + throw new IllegalArgumentException("Wakelock.mCallback is already dead.", e); + } + }); + } + } + private final class NotifierHandler extends Handler { public NotifierHandler(Looper looper) { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index efcfbdd16e4e..38570727742d 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -66,6 +66,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.IPowerManager; +import android.os.IWakeLockCallback; import android.os.Looper; import android.os.Message; import android.os.ParcelDuration; @@ -1436,7 +1437,8 @@ public final class PowerManagerService extends SystemService } private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag, - String packageName, WorkSource ws, String historyTag, int uid, int pid) { + String packageName, WorkSource ws, String historyTag, int uid, int pid, + @Nullable IWakeLockCallback callback) { synchronized (mLock) { if (displayId != Display.INVALID_DISPLAY) { final DisplayInfo displayInfo = @@ -1460,11 +1462,12 @@ public final class PowerManagerService extends SystemService boolean notifyAcquire; if (index >= 0) { wakeLock = mWakeLocks.get(index); - if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) { + if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid, callback)) { // Update existing wake lock. This shouldn't happen but is harmless. notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName, - uid, pid, ws, historyTag); - wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid); + uid, pid, ws, historyTag, callback); + wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid, + callback); } notifyAcquire = false; } else { @@ -1476,12 +1479,7 @@ public final class PowerManagerService extends SystemService } state.mNumWakeLocks++; wakeLock = new WakeLock(lock, displayId, flags, tag, packageName, ws, historyTag, - uid, pid, state); - try { - lock.linkToDeath(wakeLock, 0); - } catch (RemoteException ex) { - throw new IllegalArgumentException("Wake lock is already dead."); - } + uid, pid, state, callback); mWakeLocks.add(wakeLock); setWakeLockDisabledStateLocked(wakeLock); notifyAcquire = true; @@ -1576,11 +1574,8 @@ public final class PowerManagerService extends SystemService mRequestWaitForNegativeProximity = true; } - try { - wakeLock.mLock.unlinkToDeath(wakeLock, 0); - } catch (NoSuchElementException e) { - Slog.wtf(TAG, "Failed to unlink wakelock", e); - } + wakeLock.unlinkToDeath(); + wakeLock.setDisabled(true); removeWakeLockLocked(wakeLock, index); } } @@ -1650,13 +1645,41 @@ public final class PowerManagerService extends SystemService if (!wakeLock.hasSameWorkSource(ws)) { notifyWakeLockChangingLocked(wakeLock, wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, - ws, historyTag); + ws, historyTag, null); wakeLock.mHistoryTag = historyTag; wakeLock.updateWorkSource(ws); } } } + private void updateWakeLockCallbackInternal(IBinder lock, IWakeLockCallback callback, + int callingUid) { + synchronized (mLock) { + int index = findWakeLockIndexLocked(lock); + if (index < 0) { + if (DEBUG_SPEW) { + Slog.d(TAG, "updateWakeLockCallbackInternal: lock=" + Objects.hashCode(lock) + + " [not found]"); + } + throw new IllegalArgumentException("Wake lock not active: " + lock + + " from uid " + callingUid); + } + + WakeLock wakeLock = mWakeLocks.get(index); + if (DEBUG_SPEW) { + Slog.d(TAG, "updateWakeLockCallbackInternal: lock=" + Objects.hashCode(lock) + + " [" + wakeLock.mTag + "]"); + } + + if (!isSameCallback(callback, wakeLock.mCallback)) { + notifyWakeLockChangingLocked(wakeLock, wakeLock.mFlags, wakeLock.mTag, + wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, + wakeLock.mWorkSource, wakeLock.mHistoryTag, callback); + wakeLock.mCallback = callback; + } + } + } + @GuardedBy("mLock") private int findWakeLockIndexLocked(IBinder lock) { final int count = mWakeLocks.size(); @@ -1684,7 +1707,7 @@ public final class PowerManagerService extends SystemService wakeLock.mNotifiedAcquired = true; mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, - wakeLock.mHistoryTag); + wakeLock.mHistoryTag, wakeLock.mCallback); restartNofifyLongTimerLocked(wakeLock); } } @@ -1726,11 +1749,13 @@ public final class PowerManagerService extends SystemService @GuardedBy("mLock") private void notifyWakeLockChangingLocked(WakeLock wakeLock, int flags, String tag, - String packageName, int uid, int pid, WorkSource ws, String historyTag) { + String packageName, int uid, int pid, WorkSource ws, String historyTag, + IWakeLockCallback callback) { if (mSystemReady && wakeLock.mNotifiedAcquired) { mNotifier.onWakeLockChanging(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, - wakeLock.mHistoryTag, flags, tag, packageName, uid, pid, ws, historyTag); + wakeLock.mHistoryTag, wakeLock.mCallback, flags, tag, packageName, uid, pid, ws, + historyTag, callback); notifyWakeLockLongFinishedLocked(wakeLock); // Changing the wake lock will count as releasing the old wake lock(s) and // acquiring the new ones... we do this because otherwise once a wakelock @@ -1747,7 +1772,7 @@ public final class PowerManagerService extends SystemService wakeLock.mAcquireTime = 0; mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, - wakeLock.mWorkSource, wakeLock.mHistoryTag); + wakeLock.mWorkSource, wakeLock.mHistoryTag, wakeLock.mCallback); notifyWakeLockLongFinishedLocked(wakeLock); } } @@ -4045,10 +4070,7 @@ public final class PowerManagerService extends SystemService } } } - if (wakeLock.mDisabled != disabled) { - wakeLock.mDisabled = disabled; - return true; - } + return wakeLock.setDisabled(disabled); } return false; } @@ -5041,10 +5063,11 @@ public final class PowerManagerService extends SystemService public boolean mNotifiedAcquired; public boolean mNotifiedLong; public boolean mDisabled; + public IWakeLockCallback mCallback; public WakeLock(IBinder lock, int displayId, int flags, String tag, String packageName, WorkSource workSource, String historyTag, int ownerUid, int ownerPid, - UidState uidState) { + UidState uidState, @Nullable IWakeLockCallback callback) { mLock = lock; mDisplayId = displayId; mFlags = flags; @@ -5055,15 +5078,43 @@ public final class PowerManagerService extends SystemService mOwnerUid = ownerUid; mOwnerPid = ownerPid; mUidState = uidState; + mCallback = callback; + linkToDeath(); } @Override public void binderDied() { + unlinkToDeath(); PowerManagerService.this.handleWakeLockDeath(this); } + private void linkToDeath() { + try { + mLock.linkToDeath(this, 0); + } catch (RemoteException e) { + throw new IllegalArgumentException("Wakelock.mLock is already dead."); + } + } + + @GuardedBy("mLock") + void unlinkToDeath() { + try { + mLock.unlinkToDeath(this, 0); + } catch (NoSuchElementException e) { + Slog.wtf(TAG, "Failed to unlink Wakelock.mLock", e); + } + } + + public boolean setDisabled(boolean disabled) { + if (mDisabled != disabled) { + mDisabled = disabled; + return true; + } else { + return false; + } + } public boolean hasSameProperties(int flags, String tag, WorkSource workSource, - int ownerUid, int ownerPid) { + int ownerUid, int ownerPid, IWakeLockCallback callback) { return mFlags == flags && mTag.equals(tag) && hasSameWorkSource(workSource) @@ -5072,7 +5123,8 @@ public final class PowerManagerService extends SystemService } public void updateProperties(int flags, String tag, String packageName, - WorkSource workSource, String historyTag, int ownerUid, int ownerPid) { + WorkSource workSource, String historyTag, int ownerUid, int ownerPid, + IWakeLockCallback callback) { if (!mPackageName.equals(packageName)) { throw new IllegalStateException("Existing wake lock package name changed: " + mPackageName + " to " + packageName); @@ -5089,6 +5141,7 @@ public final class PowerManagerService extends SystemService mTag = tag; updateWorkSource(workSource); mHistoryTag = historyTag; + mCallback = callback; } public boolean hasSameWorkSource(WorkSource workSource) { @@ -5307,11 +5360,12 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void acquireWakeLockWithUid(IBinder lock, int flags, String tag, - String packageName, int uid, int displayId) { + String packageName, int uid, int displayId, IWakeLockCallback callback) { if (uid < 0) { uid = Binder.getCallingUid(); } - acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid), null, displayId); + acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid), null, + displayId, callback); } @Override // Binder call @@ -5346,7 +5400,8 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, - WorkSource ws, String historyTag, int displayId) { + WorkSource ws, String historyTag, int displayId, + @Nullable IWakeLockCallback callback) { if (lock == null) { throw new IllegalArgumentException("lock must not be null"); } @@ -5386,7 +5441,7 @@ public final class PowerManagerService extends SystemService final long ident = Binder.clearCallingIdentity(); try { acquireWakeLockInternal(lock, displayId, flags, tag, packageName, ws, historyTag, - uid, pid); + uid, pid, callback); } finally { Binder.restoreCallingIdentity(ident); } @@ -5395,7 +5450,8 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void acquireWakeLockAsync(IBinder lock, int flags, String tag, String packageName, WorkSource ws, String historyTag) { - acquireWakeLock(lock, flags, tag, packageName, ws, historyTag, Display.INVALID_DISPLAY); + acquireWakeLock(lock, flags, tag, packageName, ws, historyTag, Display.INVALID_DISPLAY, + null); } @Override // Binder call @@ -5463,6 +5519,23 @@ public final class PowerManagerService extends SystemService } @Override // Binder call + public void updateWakeLockCallback(IBinder lock, IWakeLockCallback callback) { + if (lock == null) { + throw new IllegalArgumentException("lock must not be null"); + } + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + + final int callingUid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + updateWakeLockCallbackInternal(lock, callback, callingUid); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call public boolean isWakeLockLevelSupported(int level) { final long ident = Binder.clearCallingIdentity(); try { @@ -6510,4 +6583,15 @@ public final class PowerManagerService extends SystemService } }; + static boolean isSameCallback(IWakeLockCallback callback1, + IWakeLockCallback callback2) { + if (callback1 == callback2) { + return true; + } + if (callback1 != null && callback2 != null + && callback1.asBinder() == callback2.asBinder()) { + return true; + } + return false; + } } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index ceb723a407f9..33540c874c0a 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -160,11 +160,11 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl.onVirtualDisplayCreatedLocked(displayId); verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), - nullable(String.class), anyInt()); + nullable(String.class), anyInt(), eq(null)); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), - nullable(String.class), eq(displayId)); + nullable(String.class), eq(displayId), eq(null)); } @Test @@ -177,7 +177,7 @@ public class VirtualDeviceManagerServiceTest { TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), - nullable(String.class), eq(displayId)); + nullable(String.class), eq(displayId), eq(null)); } @Test @@ -196,7 +196,7 @@ public class VirtualDeviceManagerServiceTest { verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), - nullable(String.class), eq(displayId)); + nullable(String.class), eq(displayId), eq(null)); IBinder wakeLock = wakeLockCaptor.getValue(); mDeviceImpl.onVirtualDisplayRemovedLocked(displayId); @@ -212,7 +212,7 @@ public class VirtualDeviceManagerServiceTest { verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), - nullable(String.class), eq(displayId)); + nullable(String.class), eq(displayId), eq(null)); IBinder wakeLock = wakeLockCaptor.getValue(); // Close the VirtualDevice without first notifying it of the VirtualDisplay removal. diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 51dbd97c183b..827349ad433a 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -64,6 +64,7 @@ import android.os.BatterySaverPolicyConfig; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.IWakeLockCallback; import android.os.Looper; import android.os.PowerManager; import android.os.PowerSaveState; @@ -102,6 +103,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -479,21 +481,21 @@ public class PowerManagerServiceTest { // First, ensure that a normal full wake lock does not cause a wakeup int flags = PowerManager.FULL_WAKE_LOCK; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); // Ensure that the flag does *NOT* work with a partial wake lock. flags = PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); // Verify that flag forces a wakeup when paired to a FULL_WAKE_LOCK flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); } @@ -661,12 +663,12 @@ public class PowerManagerServiceTest { wakelockMap.put((String) inv.getArguments()[1], (int) inv.getArguments()[0]); return null; }).when(mNotifierMock).onWakeLockAcquired(anyInt(), anyString(), anyString(), anyInt(), - anyInt(), any(), any()); + anyInt(), any(), any(), any()); doAnswer(inv -> { wakelockMap.remove((String) inv.getArguments()[1]); return null; }).when(mNotifierMock).onWakeLockReleased(anyInt(), anyString(), anyString(), anyInt(), - anyInt(), any(), any()); + anyInt(), any(), any(), any()); // // TEST STARTS HERE @@ -679,7 +681,7 @@ public class PowerManagerServiceTest { // Create a wakelock mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(wakelockMap.get(tag)).isEqualTo(flags); // Verify wakelock is active. // Confirm that the wakelocks have been disabled when the forceSuspend is in flight. @@ -737,7 +739,7 @@ public class PowerManagerServiceTest { // Take a nap and verify we no longer hold the blocker int flags = PowerManager.DOZE_WAKE_LOCK; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); mService.getBinderServiceInstance().goToSleep(mClock.now(), PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0); @@ -893,7 +895,7 @@ public class PowerManagerServiceTest { mService.getBinderServiceInstance().acquireWakeLock(token, PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); advanceTime(60); @@ -919,7 +921,7 @@ public class PowerManagerServiceTest { mService.getBinderServiceInstance().acquireWakeLock(token, PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, tag, pkg, - null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY); + null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY, null); advanceTime(1500); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); @@ -995,7 +997,7 @@ public class PowerManagerServiceTest { mService.getBinderServiceInstance().acquireWakeLock(token, PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, - null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY); + null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( @@ -1035,7 +1037,7 @@ public class PowerManagerServiceTest { mService.getBinderServiceInstance().acquireWakeLock(token, PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null); assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( @@ -1076,7 +1078,7 @@ public class PowerManagerServiceTest { mService.getBinderServiceInstance().acquireWakeLock(token, PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, - null /* workSource */, null /* historyTag */, nonDefaultDisplay); + null /* workSource */, null /* historyTag */, nonDefaultDisplay, null); assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( WAKEFULNESS_AWAKE); @@ -1640,7 +1642,65 @@ public class PowerManagerServiceTest { IBinder token = new Binder(); String packageName = "pkg.name"; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, - null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY); + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, + null /* callback */); return mService.findWakeLockLocked(token); } + + /** + * Test IPowerManager.acquireWakeLock() with a IWakeLockCallback. + */ + @Test + public void testNotifyWakeLockCallback() { + createService(); + startSystem(); + final String tag = "wakelock1"; + final String packageName = "pkg.name"; + final IBinder token = new Binder(); + final int flags = PowerManager.PARTIAL_WAKE_LOCK; + final IWakeLockCallback callback = Mockito.mock(IWakeLockCallback.class); + final IBinder callbackBinder = Mockito.mock(Binder.class); + when(callback.asBinder()).thenReturn(callbackBinder); + mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback); + verify(mNotifierMock).onWakeLockAcquired(anyInt(), eq(tag), eq(packageName), anyInt(), + anyInt(), any(), any(), same(callback)); + + mService.getBinderServiceInstance().releaseWakeLock(token, 0); + verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(), + anyInt(), any(), any(), same(callback)); + } + + /** + * Test IPowerManager.updateWakeLockCallback() with a new IWakeLockCallback. + */ + @Test + public void testNotifyWakeLockCallbackChange() { + createService(); + startSystem(); + final String tag = "wakelock1"; + final String packageName = "pkg.name"; + final IBinder token = new Binder(); + int flags = PowerManager.PARTIAL_WAKE_LOCK; + final IWakeLockCallback callback1 = Mockito.mock(IWakeLockCallback.class); + final IBinder callbackBinder1 = Mockito.mock(Binder.class); + when(callback1.asBinder()).thenReturn(callbackBinder1); + mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, + null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback1); + verify(mNotifierMock).onWakeLockAcquired(anyInt(), eq(tag), eq(packageName), anyInt(), + anyInt(), any(), any(), same(callback1)); + + final IWakeLockCallback callback2 = Mockito.mock(IWakeLockCallback.class); + final IBinder callbackBinder2 = Mockito.mock(Binder.class); + when(callback2.asBinder()).thenReturn(callbackBinder2); + mService.getBinderServiceInstance().updateWakeLockCallback(token, callback2); + verify(mNotifierMock).onWakeLockChanging(anyInt(), eq(tag), eq(packageName), + anyInt(), anyInt(), any(), any(), same(callback1), + anyInt(), eq(tag), eq(packageName), anyInt(), anyInt(), any(), any(), + same(callback2)); + + mService.getBinderServiceInstance().releaseWakeLock(token, 0); + verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(), + anyInt(), any(), any(), same(callback2)); + } } |