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

Commit b3fcc618 authored by Rasheed Lewis's avatar Rasheed Lewis
Browse files

Move TileLifecycleManager calls to background thread

Fixes: 271860825
Test: atest TileLifecycleManagerTest
Test: Built on device
Change-Id: Ib6d56b0218fee9081770a5b0cea43987684aa5ff
parent 4918bf7b
Loading
Loading
Loading
Loading
+47 −38
Original line number Diff line number Diff line
@@ -42,7 +42,9 @@ import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;

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 dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
@@ -88,6 +90,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private final Handler mHandler;
    private final Intent mIntent;
    private final UserHandle mUser;
    private final DelayableExecutor mExecutor;
    private final IBinder mToken = new Binder();
    private final PackageManagerAdapter mPackageManagerAdapter;
    private final BroadcastDispatcher mBroadcastDispatcher;
@@ -100,25 +103,27 @@ public class TileLifecycleManager extends BroadcastReceiver implements

    private int mBindTryCount;
    private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
    private boolean mBound;
    private AtomicBoolean mBound = new AtomicBoolean(false);
    private AtomicBoolean mPackageReceiverRegistered = new AtomicBoolean(false);
    private AtomicBoolean mUserReceiverRegistered = new AtomicBoolean(false);
    private boolean mUnbindImmediate;
    private AtomicBoolean mUnbindImmediate = new AtomicBoolean(false);
    @Nullable
    private TileChangeListener mChangeListener;
    // Return value from bindServiceAsUser, determines whether safe to call unbind.
    private boolean mIsBound;
    private AtomicBoolean mIsBound = new AtomicBoolean(false);

    @AssistedInject
    TileLifecycleManager(@Main Handler handler, Context context, IQSService service,
            PackageManagerAdapter packageManagerAdapter, BroadcastDispatcher broadcastDispatcher,
            @Assisted Intent intent, @Assisted UserHandle user) {
            @Assisted Intent intent, @Assisted UserHandle user,
            @Background DelayableExecutor executor) {
        mContext = context;
        mHandler = handler;
        mIntent = intent;
        mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder());
        mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
        mUser = user;
        mExecutor = executor;
        mPackageManagerAdapter = packageManagerAdapter;
        mBroadcastDispatcher = broadcastDispatcher;
        if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
@@ -184,22 +189,21 @@ public class TileLifecycleManager extends BroadcastReceiver implements
     * Binds just long enough to send any queued messages, then unbinds.
     */
    public void flushMessagesAndUnbind() {
        mUnbindImmediate = true;
        mExecutor.execute(() -> {
            mUnbindImmediate.set(true);
            setBindService(true);
        });
    }

    /**
     * Binds or unbinds to IQSService
     */
    @WorkerThread
    public void setBindService(boolean bind) {
        if (mBound && mUnbindImmediate) {
    private void setBindService(boolean bind) {
        if (mBound.get() && mUnbindImmediate.get()) {
            // If we are already bound and expecting to unbind, this means we should stay bound
            // because something else wants to hold the connection open.
            mUnbindImmediate = false;
            mUnbindImmediate.set(false);
            return;
        }
        mBound = bind;
        mBound.set(bind);
        if (bind) {
            if (mBindTryCount == MAX_BIND_RETRIES) {
                // Too many failures, give up on this tile until an update.
@@ -212,31 +216,38 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
            mBindTryCount++;
            try {
                mIsBound = bindServices();
                if (!mIsBound) {
                mIsBound.set(bindServices());
                if (!mIsBound.get()) {
                    mContext.unbindService(this);
                }
            } catch (SecurityException e) {
                Log.e(TAG, "Failed to bind to service", e);
                mIsBound = false;
                mIsBound.set(false);
            }
        } else {
            if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser);
            // Give it another chance next time it needs to be bound, out of kindness.
            mBindTryCount = 0;
            freeWrapper();
            if (mIsBound) {
            if (mIsBound.get()) {
                try {
                    mContext.unbindService(this);
                } catch (Exception e) {
                    Log.e(TAG, "Failed to unbind service "
                            + mIntent.getComponent().flattenToShortString(), e);
                }
                mIsBound = false;
                mIsBound.set(false);
            }
        }
    }

    /**
     * Binds or unbinds to IQSService
     */
    public void executeSetBindService(boolean bind) {
        mExecutor.execute(() -> setBindService(bind));
    }

    private boolean bindServices() {
        String packageName = mIntent.getComponent().getPackageName();
        if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, packageName,
@@ -317,10 +328,12 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            }
            onTileRemoved();
        }
        if (mUnbindImmediate) {
            mUnbindImmediate = false;
        mExecutor.execute(() -> {
            if (mUnbindImmediate.get()) {
                mUnbindImmediate.set(false);
                setBindService(false);
            }
        });
    }

    public void handleDestroy() {
@@ -335,19 +348,11 @@ public class TileLifecycleManager extends BroadcastReceiver implements
        if (mWrapper == null) return;
        freeWrapper();
        // Clearly not bound anymore
        mIsBound = false;
        if (!mBound) return;
        mIsBound.set(false);
        if (!mBound.get()) return;
        if (DEBUG) Log.d(TAG, "handleDeath");
        if (checkComponentState()) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mBound) {
                        // Retry binding.
                        setBindService(true);
                    }
                }
            }, mBindRetryDelay);
            mExecutor.executeDelayed(() -> setBindService(true), mBindRetryDelay);
        }
    }

@@ -410,11 +415,15 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            mChangeListener.onTileChanged(mIntent.getComponent());
        }
        stopPackageListening();
        if (mBound) {
            // Trying to bind again will check the state of the package before bothering to bind.
        mExecutor.execute(() -> {
            if (mBound.get()) {
                // Trying to bind again will check the state of the package before bothering to
                // bind.
                if (DEBUG) Log.d(TAG, "Trying to rebind");
                setBindService(true);
            }

        });
    }

    private boolean isComponentAvailable() {
+7 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.DelayableExecutor;

import java.util.List;
import java.util.Objects;
@@ -75,12 +76,12 @@ public class TileServiceManager {

    TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
            BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
            CustomTileAddedRepository customTileAddedRepository) {
            CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) {
        this(tileServices, handler, userTracker, customTileAddedRepository,
                new TileLifecycleManager(handler, tileServices.getContext(), tileServices,
                        new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher,
                        new Intent(TileService.ACTION_QS_TILE).setComponent(component),
                userTracker.getUserHandle()));
                        userTracker.getUserHandle(), executor));
    }

    @VisibleForTesting
@@ -203,7 +204,7 @@ public class TileServiceManager {
        mBound = true;
        mJustBound = true;
        mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
    }

    private void unbindService() {
@@ -213,7 +214,7 @@ public class TileServiceManager {
        }
        mBound = false;
        mJustBound = false;
        mStateManager.setBindService(false);
        mStateManager.executeSetBindService(false);
    }

    public void calculateBindPriority(long currentTime) {
+7 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
@@ -47,6 +48,7 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;

import java.util.ArrayList;
import java.util.Collections;
@@ -79,6 +81,7 @@ public class TileServices extends IQSService.Stub {
    private final StatusBarIconController mStatusBarIconController;
    private final PanelInteractor mPanelInteractor;
    private final CustomTileAddedRepository mCustomTileAddedRepository;
    private final DelayableExecutor mBackgroundExecutor;

    private int mMaxBound = DEFAULT_MAX_BOUND;

@@ -92,7 +95,8 @@ public class TileServices extends IQSService.Stub {
            CommandQueue commandQueue,
            StatusBarIconController statusBarIconController,
            PanelInteractor panelInteractor,
            CustomTileAddedRepository customTileAddedRepository) {
            CustomTileAddedRepository customTileAddedRepository,
            @Background DelayableExecutor backgroundExecutor) {
        mHost = host;
        mKeyguardStateController = keyguardStateController;
        mContext = mHost.getContext();
@@ -105,6 +109,7 @@ public class TileServices extends IQSService.Stub {
        mCommandQueue.addCallback(mRequestListeningCallback);
        mPanelInteractor = panelInteractor;
        mCustomTileAddedRepository = customTileAddedRepository;
        mBackgroundExecutor = backgroundExecutor;
    }

    public Context getContext() {
@@ -132,7 +137,7 @@ public class TileServices extends IQSService.Stub {
    protected TileServiceManager onCreateTileService(ComponentName component,
            BroadcastDispatcher broadcastDispatcher) {
        return new TileServiceManager(this, mHandlerProvider.get(), component,
                broadcastDispatcher, mUserTracker, mCustomTileAddedRepository);
                broadcastDispatcher, mUserTracker, mCustomTileAddedRepository, mBackgroundExecutor);
    }

    public void freeService(CustomTile tile, TileServiceManager service) {
+2 −1
Original line number Diff line number Diff line
@@ -145,7 +145,8 @@ public class QSTileHostTest extends SysuiTestCase {
        mMainExecutor = new FakeExecutor(new FakeSystemClock());

        mSharedPreferencesByUser = new SparseArray<>();
        when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
        when(mTileLifecycleManagerFactory
                .create(any(Intent.class), any(UserHandle.class)))
                .thenReturn(mTileLifecycleManager);
        when(mUserFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
                .thenAnswer((Answer<SharedPreferences>) invocation -> {
+49 −24
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ import androidx.test.runner.AndroidJUnit4;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.After;
import org.junit.Before;
@@ -81,6 +83,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
    private ComponentName mTileServiceComponentName;
    private Intent mTileServiceIntent;
    private UserHandle mUser;
    private FakeExecutor mExecutor;
    private HandlerThread mThread;
    private Handler mHandler;
    private TileLifecycleManager mStateManager;
@@ -109,12 +112,14 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mThread = new HandlerThread("TestThread");
        mThread.start();
        mHandler = Handler.createAsync(mThread.getLooper());
        mExecutor = new FakeExecutor(new FakeSystemClock());
        mStateManager = new TileLifecycleManager(mHandler, mWrappedContext,
                mock(IQSService.class),
                mMockPackageManagerAdapter,
                mMockBroadcastDispatcher,
                mTileServiceIntent,
                mUser);
                mUser,
                mExecutor);
    }

    @After
@@ -152,7 +157,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {

    @Test
    public void testBind() {
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        verifyBind(1);
    }

@@ -160,7 +166,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
    public void testPackageReceiverExported() throws Exception {
        // Make sure that we register a receiver
        setPackageEnabled(false);
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        IntentFilter filter = mWrappedContext.mLastIntentFilter;
        assertTrue(filter.hasAction(Intent.ACTION_PACKAGE_ADDED));
        assertTrue(filter.hasAction(Intent.ACTION_PACKAGE_CHANGED));
@@ -170,14 +177,17 @@ public class TileLifecycleManagerTest extends SysuiTestCase {

    @Test
    public void testUnbind() {
        mStateManager.setBindService(true);
        mStateManager.setBindService(false);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        mStateManager.executeSetBindService(false);
        mExecutor.runAllReady();
        assertFalse(mContext.isBound(mTileServiceComponentName));
    }

    @Test
    public void testTileServiceCallbacks() throws Exception {
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        mStateManager.onTileAdded();
        verify(mMockTileService).onTileAdded();
        mStateManager.onStartListening();
@@ -193,7 +203,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
    @Test
    public void testAddedBeforeBind() throws Exception {
        mStateManager.onTileAdded();
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verifyBind(1);
        verify(mMockTileService).onTileAdded();
@@ -203,7 +214,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
    public void testListeningBeforeBind() throws Exception {
        mStateManager.onTileAdded();
        mStateManager.onStartListening();
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verifyBind(1);
        verify(mMockTileService).onTileAdded();
@@ -215,7 +227,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mStateManager.onTileAdded();
        mStateManager.onStartListening();
        mStateManager.onClick(null);
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verifyBind(1);
        verify(mMockTileService).onTileAdded();
@@ -228,10 +241,12 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mStateManager.onTileAdded();
        mStateManager.onStartListening();
        mStateManager.onStopListening();
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verifyBind(1);
        mStateManager.setBindService(false);
        mStateManager.executeSetBindService(false);
        mExecutor.runAllReady();
        assertFalse(mContext.isBound(mTileServiceComponentName));
        verify(mMockTileService, never()).onStartListening();
    }
@@ -242,10 +257,12 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mStateManager.onStartListening();
        mStateManager.onClick(null);
        mStateManager.onStopListening();
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verifyBind(1);
        mStateManager.setBindService(false);
        mStateManager.executeSetBindService(false);
        mExecutor.runAllReady();
        assertFalse(mContext.isBound(mTileServiceComponentName));
        verify(mMockTileService, never()).onClick(null);
    }
@@ -255,7 +272,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        mStateManager.onTileAdded();
        mStateManager.onStartListening();
        setPackageEnabled(false);
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        // Package not available, not yet created.
        verifyBind(0);

@@ -267,18 +285,19 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                        Intent.ACTION_PACKAGE_CHANGED,
                        Uri.fromParts(
                                "package", mTileServiceComponentName.getPackageName(), null)));
        mExecutor.runAllReady();
        verifyBind(1);
    }

    @Test
    public void testKillProcess() throws Exception {
        mStateManager.onStartListening();
        mStateManager.setBindService(true);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();
        mStateManager.setBindRetryDelay(0);
        mExecutor.runAllReady();
        mStateManager.onServiceDisconnected(mTileServiceComponentName);

        // Guarantees mHandler has processed all messages.
        assertTrue(mHandler.runWithScissors(()->{}, TEST_FAIL_TIMEOUT));
        mExecutor.runAllReady();

        // Two calls: one for the first bind, one for the restart.
        verifyBind(2);
@@ -299,9 +318,11 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mMockPackageManagerAdapter,
                mMockBroadcastDispatcher,
                mTileServiceIntent,
                mUser);
                mUser,
                mExecutor);

        manager.setBindService(true);
        manager.executeSetBindService(true);
        mExecutor.runAllReady();

        ArgumentCaptor<ServiceConnection> captor = ArgumentCaptor.forClass(ServiceConnection.class);
        verify(falseContext).bindServiceAsUser(any(), captor.capture(), anyInt(), any());
@@ -318,9 +339,11 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mMockPackageManagerAdapter,
                mMockBroadcastDispatcher,
                mTileServiceIntent,
                mUser);
                mUser,
                mExecutor);

        manager.setBindService(true);
        manager.executeSetBindService(true);
        mExecutor.runAllReady();
        int flags = Context.BIND_AUTO_CREATE
                | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
                | Context.BIND_WAIVE_PRIORITY;
@@ -337,9 +360,11 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mMockPackageManagerAdapter,
                mMockBroadcastDispatcher,
                mTileServiceIntent,
                mUser);
                mUser,
                mExecutor);

        manager.setBindService(true);
        manager.executeSetBindService(true);
        mExecutor.runAllReady();
        int flags = Context.BIND_AUTO_CREATE
                | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
Loading