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();
+ }
+}