diff options
| -rw-r--r-- | services/core/java/com/android/server/power/Notifier.java | 162 | ||||
| -rw-r--r-- | services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java | 126 |
2 files changed, 236 insertions, 52 deletions
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 11b9e776204c..f85b8cc9c1bb 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -17,6 +17,7 @@ package com.android.server.power; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; @@ -197,9 +198,10 @@ public class Notifier { FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) { mContext = context; + mInjector = (injector == null) ? new RealInjector() : injector; mFlags = powerManagerFlags; mBatteryStats = batteryStats; - mAppOps = mContext.getSystemService(AppOpsManager.class); + mAppOps = mInjector.getAppOpsManager(context); mSuspendBlocker = suspendBlocker; mPolicy = policy; mFaceDownDetector = faceDownDetector; @@ -230,7 +232,6 @@ public class Notifier { mShowWirelessChargingAnimationConfig = context.getResources().getBoolean( com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim); - mInjector = (injector == null) ? new RealInjector() : injector; mWakeLockLog = mInjector.getWakeLockLog(context); // Initialize interactive state for battery stats. try { @@ -264,6 +265,7 @@ public class Notifier { /** * Called when a wake lock is acquired. */ + @SuppressLint("AndroidFrameworkRequiresPermission") public void onWakeLockAcquired(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, IWakeLockCallback callback) { @@ -273,27 +275,28 @@ public class Notifier { + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid + ", workSource=" + workSource); } - notifyWakeLockListener(callback, tag, true, ownerUid, flags); - final int monitorType = getBatteryStatsWakeLockMonitorType(flags); - if (monitorType >= 0) { - try { - final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID - && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; - if (workSource != null) { - mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, - historyTag, monitorType, unimportantForLogging); - } else { - mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, - monitorType, unimportantForLogging); - // XXX need to deal with disabled operations. - mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + notifyWakeLockListener(callback, tag, true, ownerUid, ownerPid, flags, workSource, + packageName, historyTag); + if (!mFlags.improveWakelockLatency()) { + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + if (monitorType >= 0) { + try { + final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID + && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; + if (workSource != null) { + mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, + historyTag, monitorType, unimportantForLogging); + } else { + mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, + monitorType, unimportantForLogging); + // XXX need to deal with disabled operations. + mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, + false, null, null); + } + } catch (RemoteException ex) { + // Ignore } - } catch (RemoteException ex) { - // Ignore } - } - - if (!mFlags.improveWakelockLatency()) { mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1); } mWakefulnessSessionObserver.onWakeLockAcquired(flags); @@ -404,6 +407,7 @@ public class Notifier { /** * Called when a wake lock is released. */ + @SuppressLint("AndroidFrameworkRequiresPermission") public void onWakeLockReleased(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, IWakeLockCallback callback, int releaseReason) { @@ -413,23 +417,24 @@ public class Notifier { + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid + ", workSource=" + workSource); } - notifyWakeLockListener(callback, tag, false, ownerUid, flags); - final int monitorType = getBatteryStatsWakeLockMonitorType(flags); - if (monitorType >= 0) { - try { - if (workSource != null) { - mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, - historyTag, monitorType); - } else { - mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, - historyTag, monitorType); - mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + notifyWakeLockListener(callback, tag, false, ownerUid, ownerPid, flags, workSource, + packageName, historyTag); + if (!mFlags.improveWakelockLatency()) { + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + if (monitorType >= 0) { + try { + if (workSource != null) { + mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, + historyTag, monitorType); + } else { + mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, + historyTag, monitorType); + mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null); + } + } catch (RemoteException ex) { + // Ignore } - } catch (RemoteException ex) { - // Ignore } - } - if (!mFlags.improveWakelockLatency()) { mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1); } mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason); @@ -1049,24 +1054,75 @@ public class Notifier { } private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled, - int ownerUid, int flags) { - if (callback != null) { - long currentTime = mInjector.currentTimeMillis(); - mHandler.post(() -> { + int ownerUid, int ownerPid, int flags, WorkSource workSource, String packageName, + String historyTag) { + mHandler.post(() -> { + if (mFlags.improveWakelockLatency()) { + long currentTime = mInjector.currentTimeMillis(); + if (isEnabled) { + notifyWakelockAcquisition(tag, ownerUid, ownerPid, flags, + workSource, packageName, historyTag, currentTime); + } else { + notifyWakelockRelease(tag, ownerUid, ownerPid, flags, + workSource, packageName, historyTag, currentTime); + } + } + + if (callback != null) { try { - if (mFlags.improveWakelockLatency()) { - if (isEnabled) { - mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime); - } else { - mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime); - } - } callback.onStateChanged(isEnabled); } catch (RemoteException e) { Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e); } - }); + } + }); + } + + @SuppressLint("AndroidFrameworkRequiresPermission") + private void notifyWakelockAcquisition(String tag, int ownerUid, int ownerPid, int flags, + WorkSource workSource, String packageName, String historyTag, long currentTime) { + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + if (monitorType >= 0) { + try { + final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID + && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; + if (workSource != null) { + mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, + historyTag, monitorType, unimportantForLogging); + } else { + mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, + monitorType, unimportantForLogging); + // XXX need to deal with disabled operations. + mAppOps.startOpNoThrow( + AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, + false, null, null); + } + } catch (RemoteException ex) { + // Do Nothing + } + } + mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime); + } + + @SuppressLint("AndroidFrameworkRequiresPermission") + private void notifyWakelockRelease(String tag, int ownerUid, int ownerPid, int flags, + WorkSource workSource, String packageName, String historyTag, long currentTime) { + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + if (monitorType >= 0) { + try { + if (workSource != null) { + mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, + historyTag, monitorType); + } else { + mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, + historyTag, monitorType); + mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null); + } + } catch (RemoteException ex) { + // Ignore + } } + mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime); } private final class NotifierHandler extends Handler { @@ -1114,6 +1170,11 @@ public class Notifier { * Gets the WakeLockLog object */ WakeLockLog getWakeLockLog(Context context); + + /** + * Gets the AppOpsManager system service + */ + AppOpsManager getAppOpsManager(Context context); } static class RealInjector implements Injector { @@ -1126,5 +1187,10 @@ public class Notifier { public WakeLockLog getWakeLockLog(Context context) { return new WakeLockLog(context); } + + @Override + public AppOpsManager getAppOpsManager(Context context) { + return context.getSystemService(AppOpsManager.class); + } } } diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java index 4460c6af0691..ce2bb95b790a 100644 --- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.content.Context; import android.content.res.Resources; import android.hardware.SensorManager; @@ -41,7 +42,6 @@ import android.os.IWakeLockCallback; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.VibrationAttributes; import android.os.Vibrator; import android.os.test.TestLooper; @@ -82,8 +82,12 @@ public class NotifierTest { @Mock private StatusBarManagerInternal mStatusBarManagerInternal; @Mock private WakeLockLog mWakeLockLog; + @Mock private IBatteryStats mBatteryStats; + @Mock private PowerManagerFlags mPowerManagerFlags; + @Mock private AppOpsManager mAppOpsManager; + private PowerManagerService mService; private Context mContextSpy; private Resources mResourcesSpy; @@ -230,7 +234,7 @@ public class NotifierTest { public void testOnWakeLockListener_RemoteException_NoRethrow() { when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true); createNotifier(); - + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() { @Override public void onStateChanged(boolean enabled) throws RemoteException { throw new RemoteException("Just testing"); @@ -245,6 +249,7 @@ public class NotifierTest { verifyZeroInteractions(mWakeLockLog); mTestLooper.dispatchAll(); verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1); + mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag", "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, exceptingCallback); @@ -277,6 +282,115 @@ public class NotifierTest { verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1); } + + @Test + public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException { + when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true); + createNotifier(); + + IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() { + @Override public void onStateChanged(boolean enabled) throws RemoteException { + throw new RemoteException("Just testing"); + } + }; + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); + + final int uid = 1234; + final int pid = 5678; + + // Release the wakelock + mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + + // No interaction because we expect that to happen in async + verifyZeroInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager); + + // Progressing the looper, and validating all the interactions + mTestLooper.dispatchAll(); + verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1); + verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null, + BatteryStats.WAKE_TYPE_FULL); + verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid, + "my.package.name", null); + + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); + + // Acquire the wakelock + mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + + // No interaction because we expect that to happen in async + verifyNoMoreInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager); + + // Progressing the looper, and validating all the interactions + mTestLooper.dispatchAll(); + verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1); + verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null, + BatteryStats.WAKE_TYPE_FULL, false); + verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid, + "my.package.name", false, null, null); + + // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same + // thread + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); + when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false); + + mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1); + + mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1); + } + + @Test + public void testOnWakeLockListener_FullWakeLock_ProcessesInSync() throws RemoteException { + createNotifier(); + + IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() { + @Override public void onStateChanged(boolean enabled) throws RemoteException { + throw new RemoteException("Just testing"); + } + }; + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); + + final int uid = 1234; + final int pid = 5678; + + // Release the wakelock + mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + + verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1); + verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null, + BatteryStats.WAKE_TYPE_FULL); + verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid, + "my.package.name", null); + + clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager); + + // Acquire the wakelock + mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag", + "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null, + exceptingCallback); + + mTestLooper.dispatchAll(); + verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1); + verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null, + BatteryStats.WAKE_TYPE_FULL, false); + verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid, + "my.package.name", false, null, null); + } + private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, @@ -365,13 +479,17 @@ public class NotifierTest { public WakeLockLog getWakeLockLog(Context context) { return mWakeLockLog; } + + @Override + public AppOpsManager getAppOpsManager(Context context) { + return mAppOpsManager; + } }; mNotifier = new Notifier( mTestLooper.getLooper(), mContextSpy, - IBatteryStats.Stub.asInterface(ServiceManager.getService( - BatteryStats.SERVICE_NAME)), + mBatteryStats, mInjector.createSuspendBlocker(mService, "testBlocker"), null, null, |