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

Commit 802110ea authored by Behnam Heydarshahi's avatar Behnam Heydarshahi Committed by Android (Google) Code Review
Browse files

Merge "Shorter rebind time for active tile service" into main

parents 17554c93 9262d19d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -287,6 +287,16 @@ flag {
   bug: "311147395"
}

flag {
  name: "qs_quick_rebind_active_tiles"
  namespace: "systemui"
  description: "Rebind active custom tiles quickly."
  bug: "362526228"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
    name: "coroutine_tracing"
    namespace: "systemui"
+29 −5
Original line number Diff line number Diff line
@@ -50,10 +50,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;

import com.android.systemui.Flags;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;

import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
@@ -95,6 +97,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    // Bind retry control.
    private static final int MAX_BIND_RETRIES = 5;
    private static final long DEFAULT_BIND_RETRY_DELAY = 5 * DateUtils.SECOND_IN_MILLIS;
    private static final long ACTIVE_TILE_BIND_RETRY_DELAY = 1 * DateUtils.SECOND_IN_MILLIS;
    private static final long LOW_MEMORY_BIND_RETRY_DELAY = 20 * DateUtils.SECOND_IN_MILLIS;
    private static final long TILE_SERVICE_ONCLICK_ALLOW_LIST_DEFAULT_DURATION_MS = 15_000;
    private static final String PROPERTY_TILE_SERVICE_ONCLICK_ALLOW_LIST_DURATION =
@@ -107,6 +110,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private final Intent mIntent;
    private final UserHandle mUser;
    private final DelayableExecutor mExecutor;
    private final SystemClock mSystemClock;
    private final IBinder mToken = new Binder();
    private final PackageManagerAdapter mPackageManagerAdapter;
    private final BroadcastDispatcher mBroadcastDispatcher;
@@ -120,7 +124,6 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private IBinder mClickBinder;

    private int mBindTryCount;
    private long mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
    private AtomicBoolean isDeathRebindScheduled = new AtomicBoolean(false);
    private AtomicBoolean mBound = new AtomicBoolean(false);
    private AtomicBoolean mPackageReceiverRegistered = new AtomicBoolean(false);
@@ -138,7 +141,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    TileLifecycleManager(@Main Handler handler, Context context, IQSService service,
            PackageManagerAdapter packageManagerAdapter, BroadcastDispatcher broadcastDispatcher,
            @Assisted Intent intent, @Assisted UserHandle user, ActivityManager activityManager,
            IDeviceIdleController deviceIdleController, @Background DelayableExecutor executor) {
            IDeviceIdleController deviceIdleController, @Background DelayableExecutor executor,
            SystemClock systemClock) {
        mContext = context;
        mHandler = handler;
        mIntent = intent;
@@ -146,6 +150,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
        mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
        mUser = user;
        mExecutor = executor;
        mSystemClock = systemClock;
        mPackageManagerAdapter = packageManagerAdapter;
        mBroadcastDispatcher = broadcastDispatcher;
        mActivityManager = activityManager;
@@ -436,25 +441,31 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            // If mBound is true (meaning that we should be bound), then reschedule binding for
            // later.
            if (mBound.get() && checkComponentState()) {
                if (isDeathRebindScheduled.compareAndSet(false, true)) {
                if (isDeathRebindScheduled.compareAndSet(false, true)) { // if already not scheduled


                    mExecutor.executeDelayed(() -> {
                        // Only rebind if we are supposed to, but remove the scheduling anyway.
                        if (mBound.get()) {
                            setBindService(true);
                        }
                        isDeathRebindScheduled.set(false);
                        isDeathRebindScheduled.set(false); // allow scheduling again
                    }, getRebindDelay());
                }
            }
        });
    }

    private long mLastRebind = 0;
    /**
     * @return the delay to automatically rebind after a service died. It provides a longer delay if
     * the device is a low memory state because the service is likely to get killed again by the
     * system. In this case we want to rebind later and not to cause a loop of a frequent rebinds.
     * It also provides a longer delay if called quickly (a few seconds) after a first call.
     */
    private long getRebindDelay() {
        final long now = mSystemClock.currentTimeMillis();

        final ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
        mActivityManager.getMemoryInfo(info);

@@ -462,7 +473,20 @@ public class TileLifecycleManager extends BroadcastReceiver implements
        if (info.lowMemory) {
            delay = LOW_MEMORY_BIND_RETRY_DELAY;
        } else {
            delay = mBindRetryDelay;
            if (Flags.qsQuickRebindActiveTiles()) {
                final long elapsedTimeSinceLastRebind = now - mLastRebind;
                final boolean justAttemptedRebind =
                        elapsedTimeSinceLastRebind < DEFAULT_BIND_RETRY_DELAY;
                if (isActiveTile() && !justAttemptedRebind) {
                    delay = ACTIVE_TILE_BIND_RETRY_DELAY;
                } else {
                    delay = DEFAULT_BIND_RETRY_DELAY;
                }
            } else {
                delay = DEFAULT_BIND_RETRY_DELAY;
            }

            mLastRebind = now;
        }
        if (mDebug) Log.i(TAG, "Rebinding with a delay=" + delay + " - " + getComponent());
        return delay;
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
/**
 * Manages the priority which lets {@link TileServices} make decisions about which tiles
 * to bind.  Also holds on to and manages the {@link TileLifecycleManager}, informing it
 * of when it is allowed to bind based on decisions frome the {@link TileServices}.
 * of when it is allowed to bind based on decisions from the {@link TileServices}.
 */
public class TileServiceManager {

+140 −15
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PEN
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX;
import static com.android.systemui.Flags.FLAG_QS_QUICK_REBIND_ACTIVE_TILES;

import static com.google.common.truth.Truth.assertThat;

@@ -75,6 +76,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;

import com.google.common.truth.Truth;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -95,7 +98,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {

    @Parameters(name = "{0}")
    public static List<FlagsParameterization> getParams() {
        return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX);
        return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX,
                FLAG_QS_QUICK_REBIND_ACTIVE_TILES);
    }

    private final PackageManagerAdapter mMockPackageManagerAdapter =
@@ -154,7 +158,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);
    }

    @After
@@ -169,12 +174,12 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mStateManager.handleDestroy();
    }

    private void setPackageEnabled(boolean enabled) throws Exception {
    private void setPackageEnabledAndActive(boolean enabled, boolean active) throws Exception {
        ServiceInfo defaultServiceInfo = null;
        if (enabled) {
            defaultServiceInfo = new ServiceInfo();
            defaultServiceInfo.metaData = new Bundle();
            defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true);
            defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, active);
            defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_TOGGLEABLE_TILE, true);
        }
        when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt()))
@@ -186,6 +191,10 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                .thenReturn(defaultPackageInfo);
    }

    private void setPackageEnabled(boolean enabled) throws Exception {
        setPackageEnabledAndActive(enabled, true);
    }

    private void setPackageInstalledForUser(
            boolean installed,
            boolean active,
@@ -396,18 +405,125 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
    }

    @Test
    public void testKillProcess() throws Exception {
    public void testKillProcessWhenTileServiceIsNotActive() throws Exception {
        setPackageEnabledAndActive(true, false);
        mStateManager.onStartListening();
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
        verify(mMockTileService, times(1)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName);
        mExecutor.runAllReady();
        mClock.advanceTime(5000);
        mClock.advanceTime(1000);
        mExecutor.runAllReady();

        // still 4 seconds left because non active tile service rebind time is 5 seconds
        Truth.assertThat(mContext.isBound(mTileServiceComponentName)).isFalse();

        mClock.advanceTime(4000); // 5 seconds delay for nonActive service rebinding
        mExecutor.runAllReady();
        verifyBind(2);
        verify(mMockTileService, times(2)).onStartListening();
    }

    @EnableFlags(FLAG_QS_QUICK_REBIND_ACTIVE_TILES)
    @Test
    public void testKillProcessWhenTileServiceIsActive_withRebindFlagOn() throws Exception {
        mStateManager.onStartListening();
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
        verify(mMockTileService, times(1)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName);
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();

        // Two calls: one for the first bind, one for the restart.
        verifyBind(2);
        verify(mMockTileService, times(2)).onStartListening();
    }

    @DisableFlags(FLAG_QS_QUICK_REBIND_ACTIVE_TILES)
    @Test
    public void testKillProcessWhenTileServiceIsActive_withRebindFlagOff() throws Exception {
        mStateManager.onStartListening();
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
        verify(mMockTileService, times(1)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName);
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();
        verifyBind(0); // the rebind happens after 4 more seconds

        mClock.advanceTime(4000);
        mExecutor.runAllReady();
        verifyBind(1);
    }

    @EnableFlags(FLAG_QS_QUICK_REBIND_ACTIVE_TILES)
    @Test
    public void testKillProcessWhenTileServiceIsActiveTwice_withRebindFlagOn_delaysSecondRebind()
            throws Exception {
        mStateManager.onStartListening();
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
        verify(mMockTileService, times(1)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName);
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();

        // Two calls: one for the first bind, one for the restart.
        verifyBind(2);
        verify(mMockTileService, times(2)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName);
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();
        // because active tile will take 5 seconds to bind the second time, not 1
        verifyBind(0);

        mClock.advanceTime(4000);
        mExecutor.runAllReady();
        verifyBind(1);
    }

    @DisableFlags(FLAG_QS_QUICK_REBIND_ACTIVE_TILES)
    @Test
    public void testKillProcessWhenTileServiceIsActiveTwice_withRebindFlagOff_rebindsFromFirstKill()
            throws Exception {
        mStateManager.onStartListening();
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
        verify(mMockTileService, times(1)).onStartListening();

        mStateManager.onBindingDied(mTileServiceComponentName); // rebind scheduled for 5 seconds
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();

        verifyBind(0); // it would bind in 4 more seconds

        mStateManager.onBindingDied(mTileServiceComponentName); // this does not affect the rebind
        mExecutor.runAllReady();
        mClock.advanceTime(1000);
        mExecutor.runAllReady();

        verifyBind(0); // only 2 seconds passed from first kill

        mClock.advanceTime(3000);
        mExecutor.runAllReady();
        verifyBind(1); // the rebind scheduled 5 seconds from the first kill should now happen
    }

    @Test
@@ -510,7 +626,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        manager.executeSetBindService(true);
        mExecutor.runAllReady();
@@ -533,7 +650,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        manager.executeSetBindService(true);
        mExecutor.runAllReady();
@@ -556,7 +674,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        manager.executeSetBindService(true);
        mExecutor.runAllReady();
@@ -581,7 +700,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        manager.executeSetBindService(true);
        mExecutor.runAllReady();
@@ -607,7 +727,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        assertThat(manager.isActiveTile()).isTrue();
    }
@@ -626,7 +747,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        assertThat(manager.isActiveTile()).isTrue();
    }
@@ -644,7 +766,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        assertThat(manager.isToggleableTile()).isTrue();
    }
@@ -663,7 +786,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        assertThat(manager.isToggleableTile()).isTrue();
    }
@@ -682,7 +806,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
                mExecutor,
                mClock);

        assertThat(manager.isToggleableTile()).isFalse();
        assertThat(manager.isActiveTile()).isFalse();
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.tiles.impl.custom.packageManagerAdapterFacade
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.fakeSystemClock

val Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
    Kosmos.Fixture {
@@ -39,6 +40,7 @@ val Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
                activityManager,
                mock(),
                fakeExecutor,
                fakeSystemClock,
            )
        }
    }