Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cb4aa35 authored by Varun Shah's avatar Varun Shah Committed by Android (Google) Code Review
Browse files

Merge "Use direct-callback alarms in AppTimeLimitController." into sc-dev

parents 0498394f 3288a170
Loading
Loading
Loading
Loading
+50 −2
Original line number Diff line number Diff line
@@ -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));
    }
+29 −24
Original line number Diff line number Diff line
@@ -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);
                }

            }
        }

@@ -498,6 +503,13 @@ public class AppTimeLimitController {
            }
        }

        @Override
        public void onAlarm() {
            synchronized (mLock) {
                onSessionEnd();
            }
        }

        @Override
        @GuardedBy("mLock")
        void dump(PrintWriter 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,11 +583,22 @@ 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() {
@@ -984,18 +1001,6 @@ public class AppTimeLimitController {
                group));
    }

    @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),
+1 −1
Original line number Diff line number Diff line
@@ -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,