Snap for 7756953 from 1ea704c05a6f6120da0bba83663c28e4b69f02d7 to sc-v2-release

Change-Id: Ifa0d5fae1cf6a3b548ef17dc6ed8891c9434daa2
diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java
index ae24257..cc71c7b 100644
--- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java
+++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java
@@ -110,7 +110,6 @@
               /* availabilityListener= */ this,
               scheduledExecutorService,
               availabilityRestrictions);
-      crossProfileSender.beginMonitoringAvailabilityChanges();
     }
     return crossProfileSender;
   }
diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java
index fe34d09..9cc287b 100644
--- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java
+++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java
@@ -18,6 +18,9 @@
 import static com.google.android.enterprise.connectedapps.CrossProfileSDKUtilities.filterUsersByAvailabilityRestrictions;
 import static com.google.android.enterprise.connectedapps.CrossProfileSDKUtilities.selectUserHandleToBind;
 
+import static java.util.Collections.newSetFromMap;
+import static java.util.Collections.synchronizedSet;
+
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -27,6 +30,7 @@
 import android.content.pm.CrossProfileApps;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Parcel;
@@ -41,8 +45,13 @@
 import com.google.android.enterprise.connectedapps.internal.ParcelCallReceiver;
 import com.google.android.enterprise.connectedapps.internal.ParcelUtilities;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ScheduledExecutorService;
@@ -238,6 +247,11 @@
   @Nullable private volatile ScheduledFuture<Void> automaticDisconnectionFuture;
   private final AvailabilityRestrictions availabilityRestrictions;
 
+  // This is synchronized which isn't massively performant but it only gets accessed once straight
+  // after creating a Sender, and once each time availability changes
+  private static final Set<CrossProfileSender> senders =
+          synchronizedSet(newSetFromMap(new WeakHashMap<>()));
+
   private boolean isManuallyManagingConnection = false;
   private ConcurrentLinkedDeque<OngoingCrossProfileCall> ongoingCrossProfileCalls =
       new ConcurrentLinkedDeque<>();
@@ -277,13 +291,18 @@
     canUseReflectedApis = ReflectionUtilities.canUseReflectedApis();
     this.scheduledExecutorService = scheduledExecutorService;
     this.availabilityRestrictions = availabilityRestrictions;
+
+    senders.add(this);
+    beginMonitoringAvailabilityChanges();
   }
 
-  private final BroadcastReceiver profileAvailabilityReceiver =
+  private static final BroadcastReceiver profileAvailabilityReceiver =
       new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-          checkAvailability();
+          for (CrossProfileSender sender : senders) {
+            sender.scheduledExecutorService.execute(sender::checkAvailability);
+          }
         }
       };
 
@@ -370,7 +389,13 @@
     return null;
   }
 
-  void beginMonitoringAvailabilityChanges() {
+  private static final AtomicBoolean isMonitoringAvailabilityChanges = new AtomicBoolean(false);
+
+  private void beginMonitoringAvailabilityChanges() {
+    if (isMonitoringAvailabilityChanges.getAndSet(true)) {
+      return;
+    }
+
     IntentFilter filter = new IntentFilter();
     filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
     filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
@@ -593,10 +618,17 @@
    * @throws UnavailableProfileException if a connection is not already established
    */
   public Parcel call(long crossProfileTypeIdentifier, int methodIdentifier, Parcel params)
-      throws UnavailableProfileException {
+          throws UnavailableProfileException {
     try {
       return callWithExceptions(crossProfileTypeIdentifier, methodIdentifier, params);
-    } catch (UnavailableProfileException | RuntimeException e) {
+    } catch (UnavailableProfileException | RuntimeException | Error e) {
+      StackTraceElement[] remoteStack = e.getStackTrace();
+      StackTraceElement[] localStack = Thread.currentThread().getStackTrace();
+      StackTraceElement[] totalStack =
+              Arrays.copyOf(remoteStack, remoteStack.length + localStack.length - 1);
+      // We cut off the first element of localStack as it is just getting the stack trace
+      System.arraycopy(localStack, 1, totalStack, remoteStack.length, localStack.length - 1);
+      e.setStackTrace(totalStack);
       throw e;
     } catch (Throwable e) {
       throw new UnavailableProfileException("Unexpected checked exception", e);