Merge "Move TileLifecycleManager calls to background thread" into udc-dev

This commit is contained in:
Rasheed Lewis
2023-05-08 19:09:26 +00:00
committed by Android (Google) Code Review
7 changed files with 121 additions and 76 deletions

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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 -> {

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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