summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarun Shah <varunshah@google.com>2021-04-09 17:20:10 -0700
committerVarun Shah <varunshah@google.com>2021-04-21 16:36:04 -0700
commit3288a170f7cba2c002883b5261c90f0c0335af7b (patch)
tree6448be04e10e0017e299a60e243acdc92df2455f
parentd78b21c54858a5164fd239097efcd0805f0767ba (diff)
Use direct-callback alarms in AppTimeLimitController.
Update SessionUsageGroups to use direct-callback alarms. Bug: 181983817 Test: atest AppTimeLimitControllerTests Change-Id: I73a755cb9a893952cef33c0d7cc1b2c0bf2a1318
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java52
-rw-r--r--services/usage/java/com/android/server/usage/AppTimeLimitController.java53
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
3 files changed, 80 insertions, 27 deletions
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 7d8696139245..b2e5ea07e626 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -21,13 +21,21 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManagerInternal;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.UserHandle;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,6 +43,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -89,6 +100,8 @@ public class AppTimeLimitControllerTests {
private AppTimeLimitController mController;
+ @Mock private AlarmManager mMockAlarmManager;
+
private HandlerThread mThread;
private long mElapsedTime;
@@ -112,7 +125,12 @@ public class AppTimeLimitControllerTests {
class MyAppTimeLimitController extends AppTimeLimitController {
MyAppTimeLimitController(AppTimeLimitController.TimeLimitCallbackListener listener,
Looper looper) {
- super(listener, looper);
+ super(InstrumentationRegistry.getContext(), listener, looper);
+ }
+
+ @Override
+ protected AlarmManager getAlarmManager() {
+ return mMockAlarmManager;
}
@Override
@@ -146,6 +164,8 @@ public class AppTimeLimitControllerTests {
mThread = new HandlerThread("Test");
mThread.start();
mController = new MyAppTimeLimitController(mListener, mThread.getLooper());
+
+ MockitoAnnotations.initMocks(this);
}
@After
@@ -486,9 +506,14 @@ public class AppTimeLimitControllerTests {
setTime(6_000L);
assertTrue(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mMockAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
// Usage has stopped, Session should end in a second. Verify session end occurs in a second
// (+/- 100ms, which is hopefully not too slim a margin)
assertFalse(mSessionEndLatch.await(900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
// Verify that the observer was not removed
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
@@ -597,9 +622,14 @@ public class AppTimeLimitControllerTests {
// Should call back by 11 seconds (6 earlier + 5 now)
assertTrue(mLimitReachedLatch.await(5_000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mMockAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
// Usage has stopped, Session should end in a second. Verify session end occurs in a second
// (+/- 100ms, which is hopefully not too slim a margin)
assertFalse(mSessionEndLatch.await(900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
// Verify that the observer was removed
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
@@ -849,9 +879,14 @@ public class AppTimeLimitControllerTests {
setTime(12_000L);
assertTrue(mLimitReachedLatch.await(1_000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mMockAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
// Usage has stopped, Session should end in 2 seconds. Verify session end occurs
// (+/- 100ms, which is hopefully not too slim a margin)
assertFalse(mSessionEndLatch.await(1_900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
// Verify that the observer was not removed
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
@@ -882,9 +917,14 @@ public class AppTimeLimitControllerTests {
setTime(18_000L);
assertTrue(mLimitReachedLatch.await(2000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mMockAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
// Usage has stopped, Session should end in 2 seconds. Verify session end occurs
// (+/- 100ms, which is hopefully not too slim a margin)
assertFalse(mSessionEndLatch.await(900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
// Verify that the observer was not removed
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
@@ -903,9 +943,14 @@ public class AppTimeLimitControllerTests {
setTime(11_000L);
assertTrue(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mMockAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
// Usage has stopped, Session should end in 1 seconds. Verify session end occurs
// (+/- 100ms, which is hopefully not too slim a margin)
assertFalse(mSessionEndLatch.await(900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
// Rearm the countdown latches
@@ -921,7 +966,10 @@ public class AppTimeLimitControllerTests {
setTime(31_000L);
assertTrue(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
stopUsage(PKG_SOC1);
+ verify(mMockAlarmManager, times(2)).setExact(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
+ anyString(), onAlarmListenerArgumentCaptor.capture(), any());
assertFalse(mSessionEndLatch.await(900L, TimeUnit.MILLISECONDS));
+ onAlarmListenerArgumentCaptor.getValue().onAlarm();
assertTrue(mSessionEndLatch.await(200L, TimeUnit.MILLISECONDS));
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 1dc1e7776b01..f169926fb3ac 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -17,8 +17,10 @@
package com.android.server.usage;
import android.annotation.UserIdInt;
+import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -58,6 +60,10 @@ public class AppTimeLimitController {
private final MyHandler mHandler;
+ private final Context mContext;
+
+ private AlarmManager mAlarmManager;
+
private TimeLimitCallbackListener mListener;
private static final long MAX_OBSERVER_PER_UID = 1000;
@@ -434,7 +440,7 @@ public class AppTimeLimitController {
}
}
- class SessionUsageGroup extends UsageGroup {
+ class SessionUsageGroup extends UsageGroup implements AlarmManager.OnAlarmListener {
private long mNewSessionThresholdMs;
private PendingIntent mSessionEndCallback;
@@ -466,7 +472,7 @@ public class AppTimeLimitController {
// New session has started, clear usage time.
mUsageTimeMs = 0;
}
- AppTimeLimitController.this.cancelInformSessionEndListener(this);
+ getAlarmManager().cancel(this);
}
super.noteUsageStart(startTimeMs, currentTimeMs);
}
@@ -479,10 +485,9 @@ public class AppTimeLimitController {
if (mUsageTimeMs >= mTimeLimitMs) {
// Usage has ended. Schedule the session end callback to be triggered once
// the new session threshold has been reached
- AppTimeLimitController.this.postInformSessionEndListenerLocked(this,
- mNewSessionThresholdMs);
+ getAlarmManager().setExact(AlarmManager.ELAPSED_REALTIME,
+ getElapsedRealtime() + mNewSessionThresholdMs, TAG, this, mHandler);
}
-
}
}
@@ -499,6 +504,13 @@ public class AppTimeLimitController {
}
@Override
+ public void onAlarm() {
+ synchronized (mLock) {
+ onSessionEnd();
+ }
+ }
+
+ @Override
@GuardedBy("mLock")
void dump(PrintWriter pw) {
super.dump(pw);
@@ -546,7 +558,6 @@ public class AppTimeLimitController {
private class MyHandler extends Handler {
static final int MSG_CHECK_TIMEOUT = 1;
static final int MSG_INFORM_LIMIT_REACHED_LISTENER = 2;
- static final int MSG_INFORM_SESSION_END = 3;
MyHandler(Looper looper) {
super(looper);
@@ -565,11 +576,6 @@ public class AppTimeLimitController {
((UsageGroup) msg.obj).onLimitReached();
}
break;
- case MSG_INFORM_SESSION_END:
- synchronized (mLock) {
- ((SessionUsageGroup) msg.obj).onSessionEnd();
- }
- break;
default:
super.handleMessage(msg);
break;
@@ -577,13 +583,24 @@ public class AppTimeLimitController {
}
}
- public AppTimeLimitController(TimeLimitCallbackListener listener, Looper looper) {
+ public AppTimeLimitController(Context context, TimeLimitCallbackListener listener,
+ Looper looper) {
+ mContext = context;
mHandler = new MyHandler(looper);
mListener = listener;
}
/** Overrideable by a test */
@VisibleForTesting
+ protected AlarmManager getAlarmManager() {
+ if (mAlarmManager == null) {
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ }
+ return mAlarmManager;
+ }
+
+ /** Overrideable by a test */
+ @VisibleForTesting
protected long getElapsedRealtime() {
return SystemClock.elapsedRealtime();
}
@@ -985,18 +1002,6 @@ public class AppTimeLimitController {
}
@GuardedBy("mLock")
- private void postInformSessionEndListenerLocked(SessionUsageGroup group, long timeout) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group),
- timeout);
- }
-
- @GuardedBy("mLock")
- private void cancelInformSessionEndListener(SessionUsageGroup group) {
- mHandler.removeMessages(MyHandler.MSG_INFORM_SESSION_END, group);
- }
-
- @GuardedBy("mLock")
private void postCheckTimeoutLocked(UsageGroup group, long timeout) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_CHECK_TIMEOUT, group),
timeout);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 309673d72dd4..f7e63757bd77 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -252,7 +252,7 @@ public class UsageStatsService extends SystemService implements
mAppStandby = mInjector.getAppStandbyController(getContext());
- mAppTimeLimit = new AppTimeLimitController(
+ mAppTimeLimit = new AppTimeLimitController(getContext(),
new AppTimeLimitController.TimeLimitCallbackListener() {
@Override
public void onLimitReached(int observerId, int userId, long timeLimit,