Wait for TIS cleanup after unbind before binding again
Fixes: 375315062
Test: Switch users 10 times, no crash (also check logs)
Flag: EXEMPT bug fix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:21172dbf21a8fc2754a4e6fb7a951e1fc32a58a4)
Merged-In: I7b3ac7114d519be9f46d0c38758bdcc7239d033a
Change-Id: I7b3ac7114d519be9f46d0c38758bdcc7239d033a
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 83ca496..2b71c87 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -19,10 +19,11 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
+import android.os.IRemoteCallback;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.ISystemUiProxy;
-// Next ID: 34
+// Next ID: 36
oneway interface IOverviewProxy {
void onActiveNavBarRegionChanges(in Region activeRegion) = 11;
@@ -137,4 +138,10 @@
* Sent when {@link TaskbarDelegate#appTransitionPending} is called.
*/
void appTransitionPending(boolean pending) = 34;
+
+ /**
+ * Sent right after OverviewProxy calls unbindService() on the TouchInteractionService.
+ * TouchInteractionService is expected to send the reply once it has finished cleaning up.
+ */
+ void onUnbind(IRemoteCallback reply) = 35;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e3cf411..adf9eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -58,6 +58,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.PatternMatcher;
import android.os.Process;
@@ -146,7 +147,6 @@
public static final String TAG_OPS = "OverviewProxyService";
private static final long BACKOFF_MILLIS = 1000;
private static final long DEFERRED_CALLBACK_MILLIS = 5000;
-
// Max backoff caps at 5 mins
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
@@ -183,6 +183,10 @@
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
+ // This is set to false when the overview service is requested to be bound until it is notified
+ // that the previous service has been cleaned up in IOverviewProxy#onUnbind(). It is also set to
+ // true after a 1000ms timeout by mDeferredBindAfterTimedOutCleanup.
+ private boolean mIsPrevServiceCleanedUp = true;
private boolean mIsSystemOrVisibleBgUser;
private int mCurrentBoundedUserId = -1;
@@ -489,6 +493,12 @@
retryConnectionWithBackoff();
};
+ private final Runnable mDeferredBindAfterTimedOutCleanup = () -> {
+ Log.w(TAG_OPS, "Timed out waiting for previous service to clean up, binding to new one");
+ mIsPrevServiceCleanedUp = true;
+ maybeBindService();
+ };
+
private final BroadcastReceiver mUserEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -859,6 +869,7 @@
mShadeViewControllerLazy.get().cancelInputFocusTransfer();
});
}
+ mIsPrevServiceCleanedUp = true;
startConnectionToCurrentUser();
}
@@ -889,6 +900,19 @@
}
mHandler.removeCallbacks(mConnectionRunnable);
+ maybeBindService();
+ }
+
+ private void maybeBindService() {
+ if (!mIsPrevServiceCleanedUp) {
+ Log.w(TAG_OPS, "Skipping connection to TouchInteractionService until previous"
+ + " instance is cleaned up.");
+ if (!mHandler.hasCallbacks(mDeferredConnectionCallback)) {
+ mHandler.postDelayed(mDeferredBindAfterTimedOutCleanup, BACKOFF_MILLIS);
+ }
+ return;
+ }
+
// Avoid creating TouchInteractionService because the System user in HSUM mode does not
// interact with UI elements
UserHandle currentUser = UserHandle.of(mUserTracker.getUserId());
@@ -907,6 +931,7 @@
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
if (mBound) {
+ mIsPrevServiceCleanedUp = false;
// Ensure that connection has been established even if it thinks it is bound
mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
} else {
@@ -960,6 +985,24 @@
// Always unbind the service (ie. if called through onNullBinding or onBindingDied)
mContext.unbindService(mOverviewServiceConnection);
mBound = false;
+ if (mOverviewProxy != null) {
+ try {
+ mOverviewProxy.onUnbind(new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ // Received Launcher reply, try to bind anew.
+ mIsPrevServiceCleanedUp = true;
+ if (mHandler.hasCallbacks(mDeferredBindAfterTimedOutCleanup)) {
+ mHandler.removeCallbacks(mDeferredBindAfterTimedOutCleanup);
+ maybeBindService();
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.w(TAG_OPS, "disconnectFromLauncherService failed to notify Launcher");
+ mIsPrevServiceCleanedUp = true;
+ }
+ }
}
if (mOverviewProxy != null) {
@@ -1189,6 +1232,7 @@
pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
pw.print(" mNavBarMode="); pw.println(mNavBarMode);
+ pw.print(" mIsPrevServiceCleanedUp="); pw.println(mIsPrevServiceCleanedUp);
mSysUiState.dump(pw, args);
}