diff options
| author | 2023-10-11 17:42:53 +0000 | |
|---|---|---|
| committer | 2023-10-11 17:42:53 +0000 | |
| commit | 5b361c07f928fd8c02a347b074a50b977e044f97 (patch) | |
| tree | fde858385c2e07c3620c0db45388f0f90eaa7b6d | |
| parent | bb44d8c09e2d503357f747da205f635e405a941a (diff) | |
| parent | 8d2f697646002e5d9075ae46606da25857deeee6 (diff) | |
Merge "Add Low memory state TileService rebinding delay" into main
5 files changed, 89 insertions, 35 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 2469a98140e3..78f2da53cd43 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -17,6 +17,7 @@ package com.android.systemui.qs.external; import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT; +import android.app.ActivityManager; import android.app.compat.CompatChanges; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -35,6 +36,7 @@ import android.os.UserHandle; import android.service.quicksettings.IQSService; import android.service.quicksettings.IQSTileService; import android.service.quicksettings.TileService; +import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Log; @@ -81,7 +83,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements // Bind retry control. private static final int MAX_BIND_RETRIES = 5; - private static final int DEFAULT_BIND_RETRY_DELAY = 1000; + private static final long DEFAULT_BIND_RETRY_DELAY = 5 * DateUtils.SECOND_IN_MILLIS; + private static final long LOW_MEMORY_BIND_RETRY_DELAY = 20 * DateUtils.SECOND_IN_MILLIS; // Shared prefs that hold tile lifecycle info. private static final String TILES = "tiles_prefs"; @@ -94,6 +97,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements private final IBinder mToken = new Binder(); private final PackageManagerAdapter mPackageManagerAdapter; private final BroadcastDispatcher mBroadcastDispatcher; + private final ActivityManager mActivityManager; private Set<Integer> mQueuedMessages = new ArraySet<>(); @Nullable @@ -102,7 +106,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements private IBinder mClickBinder; private int mBindTryCount; - private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY; + 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); private AtomicBoolean mUserReceiverRegistered = new AtomicBoolean(false); @@ -115,7 +120,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements @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, ActivityManager activityManager, @Background DelayableExecutor executor) { mContext = context; mHandler = handler; @@ -126,6 +131,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements mExecutor = executor; mPackageManagerAdapter = packageManagerAdapter; mBroadcastDispatcher = broadcastDispatcher; + mActivityManager = activityManager; if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser); } @@ -152,10 +158,6 @@ public class TileLifecycleManager extends BroadcastReceiver implements } } - public void setBindRetryDelay(int delayMs) { - mBindRetryDelay = delayMs; - } - public boolean isActiveTile() { try { ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(), @@ -250,19 +252,15 @@ public class TileLifecycleManager extends BroadcastReceiver implements private boolean bindServices() { String packageName = mIntent.getComponent().getPackageName(); + int flags = Context.BIND_AUTO_CREATE + | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE + | Context.BIND_WAIVE_PRIORITY; if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, packageName, mUser)) { - return mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE - | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE - | Context.BIND_WAIVE_PRIORITY, - mUser); + return mContext.bindServiceAsUser(mIntent, this, flags, mUser); } return mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE - | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE - | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS - | Context.BIND_WAIVE_PRIORITY, + flags | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, mUser); } @@ -352,8 +350,32 @@ public class TileLifecycleManager extends BroadcastReceiver implements if (!mBound.get()) return; if (DEBUG) Log.d(TAG, "handleDeath"); if (checkComponentState()) { - mExecutor.executeDelayed(() -> setBindService(true), mBindRetryDelay); + if (isDeathRebindScheduled.compareAndSet(false, true)) { + mExecutor.executeDelayed(() -> { + setBindService(true); + isDeathRebindScheduled.set(false); + }, getRebindDelay()); + } + } + } + + /** + * @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. + */ + private long getRebindDelay() { + final ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo(); + mActivityManager.getMemoryInfo(info); + + final long delay; + if (info.lowMemory) { + delay = LOW_MEMORY_BIND_RETRY_DELAY; + } else { + delay = mBindRetryDelay; } + Log.i(TAG, "Rebinding with a delay=" + delay); + return delay; } private boolean checkComponentState() { 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 941a9d6dc952..3ee4a1be40b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -75,13 +75,12 @@ public class TileServiceManager { private boolean mStarted = false; TileServiceManager(TileServices tileServices, Handler handler, ComponentName component, - BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, - CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) { + UserTracker userTracker, TileLifecycleManager.Factory tileLifecycleManagerFactory, + CustomTileAddedRepository customTileAddedRepository) { this(tileServices, handler, userTracker, customTileAddedRepository, - new TileLifecycleManager(handler, tileServices.getContext(), tileServices, - new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher, + tileLifecycleManagerFactory.create( new Intent(TileService.ACTION_QS_TILE).setComponent(component), - userTracker.getUserHandle(), executor)); + userTracker.getUserHandle())); } @VisibleForTesting 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 acee8e9ad2eb..c3744df5faeb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -81,6 +81,7 @@ public class TileServices extends IQSService.Stub { private final UserTracker mUserTracker; private final StatusBarIconController mStatusBarIconController; private final PanelInteractor mPanelInteractor; + private final TileLifecycleManager.Factory mTileLifecycleManagerFactory; private final CustomTileAddedRepository mCustomTileAddedRepository; private final DelayableExecutor mBackgroundExecutor; @@ -96,6 +97,7 @@ public class TileServices extends IQSService.Stub { CommandQueue commandQueue, StatusBarIconController statusBarIconController, PanelInteractor panelInteractor, + TileLifecycleManager.Factory tileLifecycleManagerFactory, CustomTileAddedRepository customTileAddedRepository, @Background DelayableExecutor backgroundExecutor) { mHost = host; @@ -109,6 +111,7 @@ public class TileServices extends IQSService.Stub { mStatusBarIconController = statusBarIconController; mCommandQueue.addCallback(mRequestListeningCallback); mPanelInteractor = panelInteractor; + mTileLifecycleManagerFactory = tileLifecycleManagerFactory; mCustomTileAddedRepository = customTileAddedRepository; mBackgroundExecutor = backgroundExecutor; } @@ -137,8 +140,8 @@ public class TileServices extends IQSService.Stub { protected TileServiceManager onCreateTileService(ComponentName component, BroadcastDispatcher broadcastDispatcher) { - return new TileServiceManager(this, mHandlerProvider.get(), component, - broadcastDispatcher, mUserTracker, mCustomTileAddedRepository, mBackgroundExecutor); + return new TileServiceManager(this, mHandlerProvider.get(), component, mUserTracker, + mTileLifecycleManagerFactory, mCustomTileAddedRepository); } public void freeService(CustomTileInterface tile, TileServiceManager service) { @@ -323,7 +326,7 @@ public class TileServices extends IQSService.Stub { if (info.applicationInfo.isSystemApp()) { final StatusBarIcon statusIcon = icon != null ? new StatusBarIcon(userHandle, packageName, icon, 0, 0, - contentDescription) + contentDescription) : null; final String slot = getStatusBarIconSlotName(componentName); mMainHandler.post(new Runnable() { @@ -356,11 +359,11 @@ public class TileServices extends IQSService.Stub { synchronized (mServices) { mTokenMap.forEach((iBinder, customTile) -> sb.append(iBinder.toString()) - .append(":") - .append(customTile.getComponent().flattenToShortString()) - .append(":") - .append(customTile.getUser()) - .append(",")); + .append(":") + .append(customTile.getComponent().flattenToShortString()) + .append(":") + .append(customTile.getUser()) + .append(",")); } sb.append("]"); return sb.toString(); 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 67587e3a8914..6cc52d70611a 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 @@ -29,12 +29,14 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.ActivityManager; import android.app.compat.CompatChanges; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -73,16 +75,18 @@ import org.mockito.MockitoSession; @SmallTest @RunWith(AndroidJUnit4.class) public class TileLifecycleManagerTest extends SysuiTestCase { - private static final int TEST_FAIL_TIMEOUT = 5000; private final PackageManagerAdapter mMockPackageManagerAdapter = mock(PackageManagerAdapter.class); private final BroadcastDispatcher mMockBroadcastDispatcher = mock(BroadcastDispatcher.class); private final IQSTileService.Stub mMockTileService = mock(IQSTileService.Stub.class); + private final ActivityManager mActivityManager = mock(ActivityManager.class); + private ComponentName mTileServiceComponentName; private Intent mTileServiceIntent; private UserHandle mUser; + private FakeSystemClock mClock; private FakeExecutor mExecutor; private HandlerThread mThread; private Handler mHandler; @@ -112,13 +116,15 @@ public class TileLifecycleManagerTest extends SysuiTestCase { mThread = new HandlerThread("TestThread"); mThread.start(); mHandler = Handler.createAsync(mThread.getLooper()); - mExecutor = new FakeExecutor(new FakeSystemClock()); + mClock = new FakeSystemClock(); + mExecutor = new FakeExecutor(mClock); mStateManager = new TileLifecycleManager(mHandler, mWrappedContext, mock(IQSService.class), mMockPackageManagerAdapter, mMockBroadcastDispatcher, mTileServiceIntent, mUser, + mActivityManager, mExecutor); } @@ -294,11 +300,32 @@ public class TileLifecycleManagerTest extends SysuiTestCase { mStateManager.onStartListening(); mStateManager.executeSetBindService(true); mExecutor.runAllReady(); - mStateManager.setBindRetryDelay(0); - mExecutor.runAllReady(); mStateManager.onServiceDisconnected(mTileServiceComponentName); + mClock.advanceTime(5000); + + // Two calls: one for the first bind, one for the restart. + verifyBind(2); + verify(mMockTileService, times(2)).onStartListening(); + } + + @Test + public void testKillProcessLowMemory() throws Exception { + doAnswer(invocation -> { + ActivityManager.MemoryInfo memoryInfo = invocation.getArgument(0); + memoryInfo.lowMemory = true; + return null; + }).when(mActivityManager).getMemoryInfo(any()); + mStateManager.onStartListening(); + mStateManager.executeSetBindService(true); mExecutor.runAllReady(); + mStateManager.onServiceDisconnected(mTileServiceComponentName); + + // Longer delay than a regular one + mClock.advanceTime(5000); + verifyBind(1); + verify(mMockTileService, times(1)).onStartListening(); + mClock.advanceTime(20000); // Two calls: one for the first bind, one for the restart. verifyBind(2); verify(mMockTileService, times(2)).onStartListening(); @@ -319,6 +346,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase { mMockBroadcastDispatcher, mTileServiceIntent, mUser, + mActivityManager, mExecutor); manager.executeSetBindService(true); @@ -340,6 +368,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase { mMockBroadcastDispatcher, mTileServiceIntent, mUser, + mActivityManager, mExecutor); manager.executeSetBindService(true); @@ -361,6 +390,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase { mMockBroadcastDispatcher, mTileServiceIntent, mUser, + mActivityManager, mExecutor); manager.executeSetBindService(true); 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 4bc16a52f8dc..d0118218134c 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 @@ -304,7 +304,7 @@ public class TileServicesTest extends SysuiTestCase { CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) { super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController, commandQueue, statusBarIconController, panelInteractor, - customTileAddedRepository, executor); + mTileLifecycleManagerFactory, customTileAddedRepository, executor); } @Override |