Merge cherrypicks of [12265987, 12265921] into rvc-release

Change-Id: Ieeedf8fa54ece8e2350733732a399802f1cc7c93
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 361a506..1c29c69 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
@@ -64,9 +65,6 @@
     private static final String TAG = "StorageUserConnection";
 
     private static final int DEFAULT_REMOTE_TIMEOUT_SECONDS = 20;
-    // TODO(b/161702661): Workaround for demo user to have shorter timeout.
-    // This allows the DevicePolicyManagerService#enableSystemApp call to succeed without ANR.
-    private static final int DEMO_USER_REMOTE_TIMEOUT_SECONDS = 5;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -75,6 +73,7 @@
     private final ActiveConnection mActiveConnection = new ActiveConnection();
     private final boolean mIsDemoUser;
     @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+    @GuardedBy("mLock") @Nullable private HandlerThread mHandlerThread;
 
     public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
         mContext = Objects.requireNonNull(context);
@@ -82,6 +81,10 @@
         mSessionController = controller;
         mIsDemoUser = LocalServices.getService(UserManagerInternal.class)
                 .getUserInfo(userId).isDemo();
+        if (mIsDemoUser) {
+            mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
+            mHandlerThread.start();
+        }
     }
 
     /**
@@ -188,6 +191,9 @@
      */
     public void close() {
         mActiveConnection.close();
+        if (mIsDemoUser) {
+            mHandlerThread.quit();
+        }
     }
 
     /** Returns all created sessions. */
@@ -207,8 +213,7 @@
 
     private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
         try {
-            if (!latch.await(mIsDemoUser ? DEMO_USER_REMOTE_TIMEOUT_SECONDS
-                            : DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+            if (!latch.await(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
                 // TODO(b/140025078): Call ActivityManager ANR API?
                 Slog.wtf(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
                 throw new TimeoutException("Latch wait for " + reason + " elapsed");
@@ -424,15 +429,32 @@
                 };
 
                 Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
-                if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
-                        UserHandle.of(mUserId))) {
-                    Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
-                    return mLatch;
+                if (mIsDemoUser) {
+                    // Schedule on a worker thread for demo user to avoid deadlock
+                    if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+                                    mServiceConnection,
+                                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                                    mHandlerThread.getThreadHandler(),
+                                    UserHandle.of(mUserId))) {
+                        Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+                        return mLatch;
+                    } else {
+                        mIsConnecting = false;
+                        throw new ExternalStorageServiceException(
+                                "Failed to bind to the ExternalStorageService for user " + mUserId);
+                    }
                 } else {
-                    mIsConnecting = false;
-                    throw new ExternalStorageServiceException(
-                            "Failed to bind to the ExternalStorageService for user " + mUserId);
+                    if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+                                    mServiceConnection,
+                                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                                    UserHandle.of(mUserId))) {
+                        Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+                        return mLatch;
+                    } else {
+                        mIsConnecting = false;
+                        throw new ExternalStorageServiceException(
+                                "Failed to bind to the ExternalStorageService for user " + mUserId);
+                    }
                 }
             }
         }