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

Commit 12bd016d authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Sending a TIME_TICK on screen_on

We used to send a single TIME_TICK on coming out of idle but now that is
delayed for a while after screen_on, which can lead to obsolete ui for
components relying on TIME_TICK for updating themselves.
Also, added a tag for TIME_TICK listener so it's easier to track in the
dump.

Test: atest FrameworksMockingServicesTests:AlarmManagerServiceTest

Bug: 119328963
Change-Id: I7740236c5c6dfd3c5338856c8e939a9c42bd519e
parent 19954a26
Loading
Loading
Loading
Loading
+10 −8
Original line number Original line Diff line number Diff line
@@ -1122,8 +1122,6 @@ class AlarmManagerService extends SystemService {
        rescheduleKernelAlarmsLocked();
        rescheduleKernelAlarmsLocked();
        updateNextAlarmClockLocked();
        updateNextAlarmClockLocked();


        // And send a TIME_TICK right now, since it is important to get the UI updated.
        mHandler.post(() ->  getContext().sendBroadcastAsUser(mTimeTickIntent, UserHandle.ALL));
    }
    }


    static final class InFlight {
    static final class InFlight {
@@ -1297,7 +1295,7 @@ class AlarmManagerService extends SystemService {
        mInjector.init();
        mInjector.init();


        synchronized (mLock) {
        synchronized (mLock) {
            mHandler = new AlarmHandler(Looper.myLooper());
            mHandler = new AlarmHandler();
            mConstants = new Constants(mHandler);
            mConstants = new Constants(mHandler);


            mNextWakeup = mNextNonWakeup = 0;
            mNextWakeup = mNextNonWakeup = 0;
@@ -3045,6 +3043,9 @@ class AlarmManagerService extends SystemService {
                        mNonInteractiveTime = dur;
                        mNonInteractiveTime = dur;
                    }
                    }
                }
                }
                // And send a TIME_TICK right now, since it is important to get the UI updated.
                mHandler.post(() ->
                        getContext().sendBroadcastAsUser(mTimeTickIntent, UserHandle.ALL));
            } else {
            } else {
                mNonInteractiveStartTime = nowELAPSED;
                mNonInteractiveStartTime = nowELAPSED;
            }
            }
@@ -3833,7 +3834,8 @@ class AlarmManagerService extends SystemService {
        mWakeLock.setWorkSource(null);
        mWakeLock.setWorkSource(null);
    }
    }


    private class AlarmHandler extends Handler {
    @VisibleForTesting
    class AlarmHandler extends Handler {
        public static final int ALARM_EVENT = 1;
        public static final int ALARM_EVENT = 1;
        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
        public static final int LISTENER_TIMEOUT = 3;
        public static final int LISTENER_TIMEOUT = 3;
@@ -3842,8 +3844,8 @@ class AlarmManagerService extends SystemService {
        public static final int APP_STANDBY_PAROLE_CHANGED = 6;
        public static final int APP_STANDBY_PAROLE_CHANGED = 6;
        public static final int REMOVE_FOR_STOPPED = 7;
        public static final int REMOVE_FOR_STOPPED = 7;


        AlarmHandler(Looper looper) {
        AlarmHandler() {
            super(looper);
            super(Looper.myLooper());
        }
        }


        public void postRemoveForStopped(int uid) {
        public void postRemoveForStopped(int uid) {
@@ -3956,8 +3958,8 @@ class AlarmManagerService extends SystemService {


            final WorkSource workSource = null; // Let system take blame for time tick events.
            final WorkSource workSource = null; // Let system take blame for time tick events.
            setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
            setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
                    0, null, mTimeTickTrigger, null, AlarmManager.FLAG_STANDALONE, workSource,
                    0, null, mTimeTickTrigger, "TIME_TICK", AlarmManager.FLAG_STANDALONE,
                    null, Process.myUid(), "android");
                    workSource, null, Process.myUid(), "android");


            // Finally, remember when we set the tick alarm
            // Finally, remember when we set the tick alarm
            synchronized (mLock) {
            synchronized (mLock) {
+20 −10
Original line number Original line Diff line number Diff line
@@ -25,7 +25,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -42,7 +41,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
@@ -66,7 +64,6 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;


import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


@@ -96,6 +93,8 @@ public class AlarmManagerServiceTest {
    @Mock
    @Mock
    private ContentResolver mMockResolver;
    private ContentResolver mMockResolver;
    @Mock
    @Mock
    private Context mMockContext;
    @Mock
    private IActivityManager mIActivityManager;
    private IActivityManager mIActivityManager;
    @Mock
    @Mock
    private UsageStatsManagerInternal mUsageStatsManagerInternal;
    private UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -221,17 +220,16 @@ public class AlarmManagerServiceTest {
                .thenReturn(STANDBY_BUCKET_ACTIVE);
                .thenReturn(STANDBY_BUCKET_ACTIVE);
        doReturn(Looper.getMainLooper()).when(Looper::myLooper);
        doReturn(Looper.getMainLooper()).when(Looper::myLooper);


        final Context context = spy(InstrumentationRegistry.getTargetContext());
        when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
        when(context.getContentResolver()).thenReturn(mMockResolver);
        doNothing().when(mMockResolver).registerContentObserver(any(), anyBoolean(), any());
        doReturn("min_futurity=0").when(() ->
        doReturn("min_futurity=0").when(() ->
                Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
                Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
        mInjector = new Injector(context);
        mInjector = new Injector(mMockContext);
        mService = new AlarmManagerService(context, mInjector);
        mService = new AlarmManagerService(mMockContext, mInjector);
        spyOn(mService);
        spyOn(mService);
        doNothing().when(mService).publishBinderService(any(), any());
        doNothing().when(mService).publishBinderService(any(), any());
        mService.onStart();
        mService.onStart();
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        spyOn(mService.mHandler);


        assertEquals(0, mService.mConstants.MIN_FUTURITY);
        assertEquals(0, mService.mConstants.MIN_FUTURITY);
        assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
        assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
@@ -273,7 +271,7 @@ public class AlarmManagerServiceTest {


        final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor =
        final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor =
                ArgumentCaptor.forClass(PendingIntent.OnFinished.class);
                ArgumentCaptor.forClass(PendingIntent.OnFinished.class);
        verify(alarmPi).send(any(Context.class), eq(0), any(Intent.class),
        verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
                onFinishedCaptor.capture(), any(Handler.class), isNull(), any());
                onFinishedCaptor.capture(), any(Handler.class), isNull(), any());
        verify(mWakeLock).acquire();
        verify(mWakeLock).acquire();
        onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null);
        onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null);
@@ -423,11 +421,23 @@ public class AlarmManagerServiceTest {
        assertNotNull(restrictedAlarms.get(TEST_CALLING_UID));
        assertNotNull(restrictedAlarms.get(TEST_CALLING_UID));


        listenerArgumentCaptor.getValue().unblockAlarmsForUid(TEST_CALLING_UID);
        listenerArgumentCaptor.getValue().unblockAlarmsForUid(TEST_CALLING_UID);
        verify(alarmPi).send(any(Context.class), eq(0), any(Intent.class), any(),
        verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), any(),
                any(Handler.class), isNull(), any());
                any(Handler.class), isNull(), any());
        assertNull(restrictedAlarms.get(TEST_CALLING_UID));
        assertNull(restrictedAlarms.get(TEST_CALLING_UID));
    }
    }


    @Test
    public void sendsTimeTickOnInteractive() {
        final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
        // Stubbing so the handler doesn't actually run the runnable.
        doReturn(true).when(mService.mHandler).post(runnableCaptor.capture());
        // change interactive state: false -> true
        mService.interactiveStateChangedLocked(false);
        mService.interactiveStateChangedLocked(true);
        runnableCaptor.getValue().run();
        verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
    }

    @After
    @After
    public void tearDown() {
    public void tearDown() {
        if (mMockingSession != null) {
        if (mMockingSession != null) {