Use Service instead of broadcast for package installation callback.

Test: btest com.android.bedstead.nene.packages.PackagesTest
Fixes: 272644914
Change-Id: I4e6b4cf4d685d0f6778813cecf9a70e7d7fe4ead
diff --git a/common/device-side/bedstead/nene/src/main/AndroidManifest.xml b/common/device-side/bedstead/nene/src/main/AndroidManifest.xml
index 67d2c88..4c8e43e 100644
--- a/common/device-side/bedstead/nene/src/main/AndroidManifest.xml
+++ b/common/device-side/bedstead/nene/src/main/AndroidManifest.xml
@@ -31,5 +31,11 @@
                 <action android:name="android.service.notification.NotificationListenerService" />
             </intent-filter>
         </service>
+
+        <service
+            android:name="com.android.bedstead.nene.utils.BlockingIntentSenderService"
+            android:label="Blocking Intent Sender Service"
+            android:exported="true">
+        </service>
     </application>
 </manifest>
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
index c94a5c7..fc79941 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
@@ -375,14 +375,7 @@
             return null;
         }
 
-        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
-                || !user.isRunning()) {
-            // We can use the old adb version - as the new way fails for non-running users
-            return installPreS(user, apkFile);
-        }
-
-        // Temp: let's always use the old version so we're not reliant on broadcasts for now
-        if (true) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
             return installPreS(user, apkFile);
         }
 
@@ -423,7 +416,7 @@
 
                     if (intent == null) {
                         throw new NeneException(
-                                "Did not receive broadcast from package installer session when"
+                                "Did not receive intent from package installer session when"
                                         + " installing bytes on user " + user);
                     }
 
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
index 2729b61..a77f79a 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
@@ -21,9 +21,8 @@
 import android.content.IntentSender;
 
 import com.android.bedstead.nene.TestApis;
-import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 
-import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provider of a blocking version of {@link IntentSender}.
@@ -40,52 +39,38 @@
  */
 public class BlockingIntentSender implements AutoCloseable {
 
-    private static final String ACTION_PREFIX = "com.android.bedstead.intentsender.";
-
-    private final TestApis mTestApis = new TestApis();
+    private Intent mIntent;
 
     /** Create and register a {@link BlockingIntentSender}. */
     public static BlockingIntentSender create() {
-        BlockingIntentSender blockingIntentSender =
-                new BlockingIntentSender(
-                        ACTION_PREFIX + UUID.randomUUID().getLeastSignificantBits());
+        BlockingIntentSender blockingIntentSender = new BlockingIntentSender();
         blockingIntentSender.register();
 
         return blockingIntentSender;
     }
 
-    private final String mAction;
     private IntentSender mIntentSender;
-    private BlockingBroadcastReceiver mBlockingBroadcastReceiver;
-
-    private BlockingIntentSender(String action) {
-        mAction = action;
+    private BlockingIntentSender() {
     }
 
     private void register() {
-        mBlockingBroadcastReceiver = BlockingBroadcastReceiver.create(
-                mTestApis.context().instrumentedContext(), mAction);
-        mBlockingBroadcastReceiver.register();
+        mIntent = BlockingIntentSenderService.register();
 
-        Intent intent = new Intent(mAction);
-        intent.setPackage(mTestApis.context().instrumentedContext().getPackageName());
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(
-                mTestApis.context().instrumentedContext(),
-                /* requestCode= */ 0,
-                intent,
+        PendingIntent pendingIntent = PendingIntent.getService(
+                TestApis.context().instrumentedContext(),
+                /* requestCode= */ 0, mIntent,
                 PendingIntent.FLAG_MUTABLE);
         mIntentSender = pendingIntent.getIntentSender();
     }
 
     /** Wait for the {@link #intentSender()} to be used. */
     public Intent await() {
-        return mBlockingBroadcastReceiver.awaitForBroadcast();
+        return BlockingIntentSenderService.await(mIntent);
     }
 
     /** Wait for the {@link #intentSender()} to be used. */
     public Intent await(long timeoutMillis) {
-        return mBlockingBroadcastReceiver.awaitForBroadcast(timeoutMillis);
+        return BlockingIntentSenderService.await(mIntent, timeoutMillis, TimeUnit.MILLISECONDS);
     }
 
     /** Get the intent sender. */
@@ -95,6 +80,8 @@
 
     @Override
     public void close() {
-        mBlockingBroadcastReceiver.close();
+        if (mIntent != null) {
+            BlockingIntentSenderService.unregister(mIntent);
+        }
     }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSenderService.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSenderService.java
new file mode 100644
index 0000000..068cd60
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSenderService.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.utils;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.bedstead.nene.TestApis;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Service used by {@link BlockingIntentSender}.
+ *
+ * <p>See {@link BlockingIntentSender} for usage.
+ */
+public final class BlockingIntentSenderService extends IntentService {
+
+    private static final String LOG_TAG = "BlockingIntentSenderService";
+
+    private static final String BLOCKING_INTENT_SENDER_ID_KEY = "BlockingIntentSenderId";
+
+    private static final long DEFAULT_TIMEOUT = 30;
+    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;
+
+    private static final Map<String, CountDownLatch> sLatches = new ConcurrentHashMap<>();
+    private static final Map<String, Intent> sReceivedIntents = new ConcurrentHashMap<>();
+
+    // TODO(b/273197248): This only allows us to have one intentsender at a time - this is because
+    // for some reason it appeared to be losing the extra value on receiving the intent -
+    // to reproduce just comment out the FIXED_ID stuff and run
+    // com.android.bedstead.nene.packages.PackagesTest#install_instrumentedUser_isInstalled
+    private static final String FIXED_ID = "FIXED";
+
+    /** Only for use by {@link BlockingIntentSender}. */
+    public BlockingIntentSenderService() {
+        super("BlockingIntentSenderService");
+    }
+
+    /** Only for use by {@link BlockingIntentSender}. */
+    public static Intent register() {
+        String id = Long.toString(new Random().nextLong());
+        id = FIXED_ID;
+
+        Intent intent = new Intent();
+        intent.setClass(
+                TestApis.context().instrumentedContext(), BlockingIntentSenderService.class);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.putExtra(BLOCKING_INTENT_SENDER_ID_KEY, id);
+
+        sLatches.put(id, new CountDownLatch(1));
+
+        return intent;
+    }
+
+    private static String getId(Intent intent) {
+//        return intent.getStringExtra(BLOCKING_INTENT_SENDER_ID_KEY);
+        return FIXED_ID;
+    }
+
+    /** Only for use by {@link BlockingIntentSender}. */
+    public static void unregister(Intent intent) {
+        String id = getId(intent);
+        sLatches.remove(id);
+        sReceivedIntents.remove(id);
+    }
+
+    /** Only for use by {@link BlockingIntentSender}. */
+    public static Intent await(Intent intent) {
+        return await(intent, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
+    }
+
+    /** Only for use by {@link BlockingIntentSender}. */
+    public static Intent await(Intent intent, long timeout, TimeUnit unit) {
+        String id = getId(intent);
+
+        CountDownLatch latch = sLatches.get(id);
+        if (latch == null) {
+            throw new IllegalStateException(
+                    "Awaiting but no latch registered for intent " + intent);
+        }
+
+        try {
+            latch.await(timeout, unit);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        return sReceivedIntents.get(id);
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        String id = getId(intent);
+
+        CountDownLatch latch = sLatches.get(id);
+        if (latch == null) {
+            Log.e(LOG_TAG,
+                    "Received start intent at BlockingIntentSenderService but no "
+                            + "latch registered for id " + id + " intent " + intent);
+            return;
+        }
+
+        sReceivedIntents.put(id, intent);
+        latch.countDown();
+    }
+}