diff options
7 files changed, 121 insertions, 76 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 385e72017bae..2469a98140e3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -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; - setBindService(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; - setBindService(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. - if (DEBUG) Log.d(TAG, "Trying to rebind"); - setBindService(true); - } + 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() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index 7a10a27f6aca..941a9d6dc952 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -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())); + new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher, + new Intent(TileService.ACTION_QS_TILE).setComponent(component), + 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) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 121955cced1a..a07b955fdb73 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -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) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index e4d8b2598fe3..810ab344e7d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -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 -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java index 2e6b0cf7b0a8..67587e3a8914 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java index 9ca7a8521e95..28331bbfafb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java @@ -187,7 +187,7 @@ public class TileServiceManagerTest extends SysuiTestCase { mTileServiceManager.setBindAllowed(true); ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class); - verify(mTileLifecycle, times(1)).setBindService(captor.capture()); + verify(mTileLifecycle, times(1)).executeSetBindService(captor.capture()); assertTrue((boolean) captor.getValue()); mTileServiceManager.setBindRequested(false); @@ -198,7 +198,7 @@ public class TileServiceManagerTest extends SysuiTestCase { mTileServiceManager.setBindAllowed(false); captor = ArgumentCaptor.forClass(Boolean.class); - verify(mTileLifecycle, times(2)).setBindService(captor.capture()); + verify(mTileLifecycle, times(2)).executeSetBindService(captor.capture()); assertFalse((boolean) captor.getValue()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 12b5656725eb..4bc16a52f8dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -48,6 +48,9 @@ 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 com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Assert; @@ -118,7 +121,8 @@ public class TileServicesTest extends SysuiTestCase { mTileService = new TestTileServices(mQSHost, provider, mBroadcastDispatcher, mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController, - mPanelInteractor, mCustomTileAddedRepository); + mPanelInteractor, mCustomTileAddedRepository, + new FakeExecutor(new FakeSystemClock())); } @After @@ -297,10 +301,10 @@ public class TileServicesTest extends SysuiTestCase { BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, KeyguardStateController keyguardStateController, CommandQueue commandQueue, StatusBarIconController statusBarIconController, PanelInteractor panelInteractor, - CustomTileAddedRepository customTileAddedRepository) { + CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) { super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController, commandQueue, statusBarIconController, panelInteractor, - customTileAddedRepository); + customTileAddedRepository, executor); } @Override |