summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt4
-rw-r--r--core/java/android/app/BackgroundInstallControlManager.java101
-rw-r--r--core/java/android/app/SystemServiceRegistry.java14
-rw-r--r--core/java/android/app/background_install_control_manager.aconfig9
-rw-r--r--core/java/android/content/pm/IBackgroundInstallControlService.aidl11
-rw-r--r--services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java97
-rw-r--r--services/core/java/com/android/server/pm/BackgroundInstallControlService.java181
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/Android.bp1
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml11
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java37
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml3
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java222
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java95
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java541
-rw-r--r--tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java12
16 files changed, 1025 insertions, 322 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2898705b75d4..1c60db9f250d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -862,6 +862,10 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
}
+ @FlaggedApi("android.app.bic_client") public final class BackgroundInstallControlManager {
+ method @FlaggedApi("android.app.bic_client") @NonNull @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES) public java.util.List<android.content.pm.PackageInfo> getBackgroundInstalledPackages(long);
+ }
+
public class BroadcastOptions {
method public void clearRequireCompatChange();
method public int getPendingIntentBackgroundActivityStartMode();
diff --git a/core/java/android/app/BackgroundInstallControlManager.java b/core/java/android/app/BackgroundInstallControlManager.java
new file mode 100644
index 000000000000..f5b68788f0ea
--- /dev/null
+++ b/core/java/android/app/BackgroundInstallControlManager.java
@@ -0,0 +1,101 @@
+/*
+ * 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 android.app;
+
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.pm.IBackgroundInstallControlService;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.ServiceManager;
+
+import java.util.List;
+
+/**
+ * BackgroundInstallControlManager client allows apps to query apps installed in background.
+ *
+ * <p>Any applications that was installed without an accompanying installer UI activity paired
+ * with recorded user interaction event is considered background installed. This is determined by
+ * analysis of user-activity logs.
+ *
+ * <p>Warning: BackgroundInstallControl should not be considered a reliable or accurate
+ * determination of background install application. Consumers can use this as a supplementary
+ * signal, but must perform additional due diligence to confirm the install nature of the package.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_BIC_CLIENT)
+@SystemApi(client = PRIVILEGED_APPS)
+@SystemService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE)
+public final class BackgroundInstallControlManager {
+
+ private static final String TAG = "BackgroundInstallControlManager";
+ private static IBackgroundInstallControlService sService;
+ private final Context mContext;
+
+ BackgroundInstallControlManager(Context context) {
+ mContext = context;
+ }
+
+ private static IBackgroundInstallControlService getService() {
+ if (sService == null) {
+ sService =
+ IBackgroundInstallControlService.Stub.asInterface(
+ ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+ }
+ return sService;
+ }
+
+ /**
+ * Returns a full list of {@link PackageInfo} of apps currently installed that are considered
+ * installed in the background.
+ *
+ * <p>Refer to top level doc {@link BackgroundInstallControlManager} for more details on
+ * background-installed applications.
+ * <p>
+ *
+ * @param flags - Flags will be used to call
+ * {@link PackageManager#getInstalledPackages(PackageInfoFlags)} to retrieve installed packages.
+ * @return A list of packages retrieved from {@link PackageManager} with non-background
+ * installed app filter applied.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_BIC_CLIENT)
+ @SystemApi
+ @RequiresPermission(QUERY_ALL_PACKAGES)
+ public @NonNull List<PackageInfo> getBackgroundInstalledPackages(
+ @PackageManager.PackageInfoFlagsBits long flags) {
+ try {
+ return getService()
+ .getBackgroundInstalledPackages(flags, mContext.getUserId())
+ .getList();
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9cf732abb86a..390fa2212298 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1603,6 +1603,20 @@ public final class SystemServiceRegistry {
}
});
+ // DO NOT do a flag check like this unless the flag is read-only.
+ // (because this code is executed during preload in zygote.)
+ // If the flag is mutable, the check should be inside CachedServiceFetcher.
+ if (Flags.bicClient()) {
+ registerService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE,
+ BackgroundInstallControlManager.class,
+ new CachedServiceFetcher<BackgroundInstallControlManager>() {
+ @Override
+ public BackgroundInstallControlManager createService(ContextImpl ctx) {
+ return new BackgroundInstallControlManager(ctx);
+ }
+ });
+ }
+
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
new file mode 100644
index 000000000000..029b93ab4534
--- /dev/null
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -0,0 +1,9 @@
+package: "android.app"
+
+flag {
+ namespace: "background_install_control"
+ name: "bic_client"
+ description: "System API for background install control."
+ is_fixed_read_only: true
+ bug: "287507984"
+}
diff --git a/core/java/android/content/pm/IBackgroundInstallControlService.aidl b/core/java/android/content/pm/IBackgroundInstallControlService.aidl
index c8e7caebc821..4bc8fe16b249 100644
--- a/core/java/android/content/pm/IBackgroundInstallControlService.aidl
+++ b/core/java/android/content/pm/IBackgroundInstallControlService.aidl
@@ -16,11 +16,20 @@
package android.content.pm;
+
import android.content.pm.ParceledListSlice;
+import android.os.IRemoteCallback;
/**
* {@hide}
*/
interface IBackgroundInstallControlService {
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)")
ParceledListSlice getBackgroundInstalledPackages(long flags, int userId);
-}
+
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.QUERY_ALL_PACKAGES, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})")
+ void registerBackgroundInstallCallback(IRemoteCallback callback);
+
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.QUERY_ALL_PACKAGES, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})")
+ void unregisterBackgroundInstallCallback(IRemoteCallback callback);
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java b/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
new file mode 100644
index 000000000000..4454601f2254
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server.pm;
+
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+
+import android.annotation.NonNull;
+import android.app.BackgroundInstallControlManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IRemoteCallback;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ServiceThread;
+
+public class BackgroundInstallControlCallbackHelper {
+
+ @VisibleForTesting static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
+ @VisibleForTesting static final String FLAGGED_USER_ID_KEY = "userId";
+ private static final String TAG = "BackgroundInstallControlCallbackHelper";
+
+ private final Handler mHandler;
+
+ BackgroundInstallControlCallbackHelper() {
+ HandlerThread backgroundThread =
+ new ServiceThread(
+ "BackgroundInstallControlCallbackHelperBg",
+ THREAD_PRIORITY_BACKGROUND,
+ true);
+ backgroundThread.start();
+ mHandler = new Handler(backgroundThread.getLooper());
+ }
+
+ @NonNull @VisibleForTesting
+ final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<>();
+
+ /** Registers callback that gets invoked upon detection of an MBA
+ *
+ * NOTE: The callback is user context agnostic and currently broadcasts to all users of other
+ * users app installs. This is fine because the API is for SystemServer use only.
+ */
+ public void registerBackgroundInstallCallback(IRemoteCallback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.register(callback, null);
+ }
+ }
+
+ /** Unregisters callback */
+ public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.unregister(callback);
+ }
+ }
+
+ /**
+ * Invokes all registered callbacks Callbacks are processed through user provided-threads and
+ * parameters are passed in via {@link BackgroundInstallControlManager} InstallEvent
+ */
+ public void notifyAllCallbacks(int userId, String packageName) {
+ Bundle extras = new Bundle();
+ extras.putCharSequence(FLAGGED_PACKAGE_NAME_KEY, packageName);
+ extras.putInt(FLAGGED_USER_ID_KEY, userId);
+ synchronized (mCallbacks) {
+ mHandler.post(
+ () ->
+ mCallbacks.broadcast(
+ callback -> {
+ try {
+ callback.sendResult(extras);
+ } catch (RemoteException e) {
+ Slog.e(
+ TAG,
+ "error detected: " + e.getLocalizedMessage(),
+ e);
+ }
+ }));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index 7f0aadce3143..3a9dedcf2d7b 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -16,7 +16,12 @@
package com.android.server.pm;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
@@ -30,6 +35,7 @@ import android.content.pm.ParceledListSlice;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
@@ -69,8 +75,10 @@ public class BackgroundInstallControlService extends SystemService {
private static final String DISK_FILE_NAME = "states";
private static final String DISK_DIR_NAME = "bic";
- private static final int MAX_FOREGROUND_TIME_FRAMES_SIZE = 10;
+ private static final String ENFORCE_PERMISSION_ERROR_MSG =
+ "User is not permitted to call service: ";
+ private static final int MAX_FOREGROUND_TIME_FRAMES_SIZE = 10;
private static final int MSG_USAGE_EVENT_RECEIVED = 0;
private static final int MSG_PACKAGE_ADDED = 1;
private static final int MSG_PACKAGE_REMOVED = 2;
@@ -78,19 +86,20 @@ public class BackgroundInstallControlService extends SystemService {
private final Context mContext;
private final BinderService mBinderService;
private final PackageManager mPackageManager;
+ // TODO migrate all internal PackageManager calls to PackageManagerInternal where possible.
+ // b/310983905
private final PackageManagerInternal mPackageManagerInternal;
private final UsageStatsManagerInternal mUsageStatsManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
private final Handler mHandler;
private final File mDiskFile;
-
private SparseSetArray<String> mBackgroundInstalledPackages = null;
+ private final BackgroundInstallControlCallbackHelper mCallbackHelper;
// User ID -> package name -> set of foreground time frame
- private final SparseArrayMap<String,
- TreeSet<ForegroundTimeFrame>> mInstallerForegroundTimeFrames =
- new SparseArrayMap<>();
+ private final SparseArrayMap<String, TreeSet<ForegroundTimeFrame>>
+ mInstallerForegroundTimeFrames = new SparseArrayMap<>();
public BackgroundInstallControlService(@NonNull Context context) {
this(new InjectorImpl(context));
@@ -106,13 +115,11 @@ public class BackgroundInstallControlService extends SystemService {
mHandler = new EventHandler(injector.getLooper(), this);
mDiskFile = injector.getDiskFile();
mUsageStatsManagerInternal = injector.getUsageStatsManagerInternal();
+ mCallbackHelper = injector.getBackgroundInstallControlCallbackHelper();
mUsageStatsManagerInternal.registerListener(
(userId, event) ->
- mHandler.obtainMessage(MSG_USAGE_EVENT_RECEIVED,
- userId,
- 0,
- event).sendToTarget()
- );
+ mHandler.obtainMessage(MSG_USAGE_EVENT_RECEIVED, userId, 0, event)
+ .sendToTarget());
mBinderService = new BinderService(this);
}
@@ -126,12 +133,15 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public ParceledListSlice<PackageInfo> getBackgroundInstalledPackages(
@PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ mService.enforceCallerQueryPackagesPermissions();
if (!Build.IS_DEBUGGABLE) {
return mService.getBackgroundInstalledPackages(flags, userId);
}
// The debug.transparency.bg-install-apps (only works for debuggable builds)
// is used to set mock list of background installed apps for testing.
// The list of apps' names is delimited by ",".
+ // TODO: Remove after migrating test to new background install method using
+ // {@link BackgroundInstallControlCallbackHelperTest}.installPackage b/310983905
String propertyString = SystemProperties.get("debug.transparency.bg-install-apps");
if (TextUtils.isEmpty(propertyString)) {
return mService.getBackgroundInstalledPackages(flags, userId);
@@ -139,16 +149,41 @@ public class BackgroundInstallControlService extends SystemService {
return mService.getMockBackgroundInstalledPackages(propertyString);
}
}
+
+ @Override
+ public void registerBackgroundInstallCallback(IRemoteCallback callback) {
+ mService.enforceCallerQueryPackagesPermissions();
+ mService.enforceCallerInteractCrossUserPermissions();
+ mService.mCallbackHelper.registerBackgroundInstallCallback(callback);
+ }
+
+ @Override
+ public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
+ mService.enforceCallerQueryPackagesPermissions();
+ mService.enforceCallerInteractCrossUserPermissions();
+ mService.mCallbackHelper.unregisterBackgroundInstallCallback(callback);
+ }
+ }
+
+ @RequiresPermission(QUERY_ALL_PACKAGES)
+ void enforceCallerQueryPackagesPermissions() throws SecurityException {
+ mContext.enforceCallingPermission(QUERY_ALL_PACKAGES,
+ ENFORCE_PERMISSION_ERROR_MSG + QUERY_ALL_PACKAGES);
+ }
+
+ @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+ void enforceCallerInteractCrossUserPermissions() throws SecurityException {
+ mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL,
+ ENFORCE_PERMISSION_ERROR_MSG + INTERACT_ACROSS_USERS_FULL);
}
@VisibleForTesting
ParceledListSlice<PackageInfo> getBackgroundInstalledPackages(
@PackageManager.PackageInfoFlagsBits long flags, int userId) {
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.PackageInfoFlags.of(flags), userId);
+ PackageManager.PackageInfoFlags.of(flags), userId);
initBackgroundInstalledPackages();
-
ListIterator<PackageInfo> iter = packages.listIterator();
while (iter.hasNext()) {
String packageName = iter.next().packageName;
@@ -170,8 +205,9 @@ public class BackgroundInstallControlService extends SystemService {
List<PackageInfo> mockPackages = new ArrayList<>();
for (String name : mockPackageNames) {
try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(name,
- PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL));
+ PackageInfo packageInfo =
+ mPackageManager.getPackageInfo(
+ name, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL));
mockPackages.add(packageInfo);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Package's PackageInfo not found " + name);
@@ -192,18 +228,16 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_USAGE_EVENT_RECEIVED: {
- mService.handleUsageEvent((UsageEvents.Event) msg.obj, msg.arg1 /* userId */);
+ case MSG_USAGE_EVENT_RECEIVED:
+ mService.handleUsageEvent(
+ (UsageEvents.Event) msg.obj, msg.arg1 /* userId */);
break;
- }
- case MSG_PACKAGE_ADDED: {
+ case MSG_PACKAGE_ADDED:
mService.handlePackageAdd((String) msg.obj, msg.arg1 /* userId */);
break;
- }
- case MSG_PACKAGE_REMOVED: {
+ case MSG_PACKAGE_REMOVED:
mService.handlePackageRemove((String) msg.obj, msg.arg1 /* userId */);
break;
- }
default:
Slog.w(TAG, "Unknown message: " + msg.what);
}
@@ -213,8 +247,9 @@ public class BackgroundInstallControlService extends SystemService {
void handlePackageAdd(String packageName, int userId) {
ApplicationInfo appInfo = null;
try {
- appInfo = mPackageManager.getApplicationInfoAsUser(packageName,
- PackageManager.ApplicationInfoFlags.of(0), userId);
+ appInfo =
+ mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.ApplicationInfoFlags.of(0), userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Package's appInfo not found " + packageName);
return;
@@ -233,15 +268,18 @@ public class BackgroundInstallControlService extends SystemService {
// the installers without INSTALL_PACKAGES perm can't perform
// the installation in background. So we can just filter out them.
- if (mPermissionManager.checkPermission(installerPackageName,
- android.Manifest.permission.INSTALL_PACKAGES, Context.DEVICE_ID_DEFAULT,
- userId) != PackageManager.PERMISSION_GRANTED) {
+ if (mPermissionManager.checkPermission(
+ installerPackageName,
+ android.Manifest.permission.INSTALL_PACKAGES,
+ Context.DEVICE_ID_DEFAULT,
+ userId)
+ != PERMISSION_GRANTED) {
return;
}
// convert up-time to current time.
- final long installTimestamp = System.currentTimeMillis()
- - (SystemClock.uptimeMillis() - appInfo.createTimestamp);
+ final long installTimestamp =
+ System.currentTimeMillis() - (SystemClock.uptimeMillis() - appInfo.createTimestamp);
if (installedByAdb(initiatingPackageName)
|| wasForegroundInstallation(installerPackageName, userId, installTimestamp)) {
@@ -250,6 +288,7 @@ public class BackgroundInstallControlService extends SystemService {
initBackgroundInstalledPackages();
mBackgroundInstalledPackages.add(userId, packageName);
+ mCallbackHelper.notifyAllCallbacks(userId, packageName);
writeBackgroundInstalledPackagesToDisk();
}
@@ -259,8 +298,8 @@ public class BackgroundInstallControlService extends SystemService {
return PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName);
}
- private boolean wasForegroundInstallation(String installerPackageName,
- int userId, long installTimestamp) {
+ private boolean wasForegroundInstallation(
+ String installerPackageName, int userId, long installTimestamp) {
TreeSet<BackgroundInstallControlService.ForegroundTimeFrame> foregroundTimeFrames =
mInstallerForegroundTimeFrames.get(userId, installerPackageName);
@@ -349,12 +388,12 @@ public class BackgroundInstallControlService extends SystemService {
for (int i = 0; i < mBackgroundInstalledPackages.size(); i++) {
int userId = mBackgroundInstalledPackages.keyAt(i);
for (String packageName : mBackgroundInstalledPackages.get(userId)) {
- long token = protoOutputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token =
+ protoOutputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
protoOutputStream.write(
BackgroundInstalledPackageProto.PACKAGE_NAME, packageName);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.USER_ID, userId + 1);
+ protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, userId + 1);
protoOutputStream.end(token);
}
}
@@ -387,23 +426,28 @@ public class BackgroundInstallControlService extends SystemService {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token = protoInputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token =
+ protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName = protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName =
+ protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId = protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID) - 1;
+ userId =
+ protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID)
+ - 1;
break;
default:
- Slog.w(TAG, "Undefined field in proto: "
- + protoInputStream.getFieldNumber());
+ Slog.w(
+ TAG,
+ "Undefined field in proto: "
+ + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -432,9 +476,12 @@ public class BackgroundInstallControlService extends SystemService {
if (mInstallerForegroundTimeFrames.contains(userId, pkgName)) {
return true;
}
- return mPermissionManager.checkPermission(pkgName,
- android.Manifest.permission.INSTALL_PACKAGES, Context.DEVICE_ID_DEFAULT,
- userId) == PackageManager.PERMISSION_GRANTED;
+ return mPermissionManager.checkPermission(
+ pkgName,
+ android.Manifest.permission.INSTALL_PACKAGES,
+ Context.DEVICE_ID_DEFAULT,
+ userId)
+ == PERMISSION_GRANTED;
}
@Override
@@ -448,21 +495,22 @@ public class BackgroundInstallControlService extends SystemService {
publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService);
}
- mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- final int userId = UserHandle.getUserId(uid);
- mHandler.obtainMessage(MSG_PACKAGE_ADDED,
- userId, 0, packageName).sendToTarget();
- }
+ mPackageManagerInternal.getPackageList(
+ new PackageManagerInternal.PackageListObserver() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName)
+ .sendToTarget();
+ }
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- final int userId = UserHandle.getUserId(uid);
- mHandler.obtainMessage(MSG_PACKAGE_REMOVED,
- userId, 0, packageName).sendToTarget();
- }
- });
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName)
+ .sendToTarget();
+ }
+ });
}
// The foreground time frame (ForegroundTimeFrame) represents the period
@@ -518,7 +566,7 @@ public class BackgroundInstallControlService extends SystemService {
}
/**
- * Dependency injector for {@link #BackgroundInstallControlService)}.
+ * Dependency injector for {@link BackgroundInstallControlService}.
*/
interface Injector {
Context getContext();
@@ -534,6 +582,8 @@ public class BackgroundInstallControlService extends SystemService {
Looper getLooper();
File getDiskFile();
+
+ BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper();
}
private static final class InjectorImpl implements Injector {
@@ -570,11 +620,11 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public Looper getLooper() {
- ServiceThread serviceThread = new ServiceThread(TAG,
- android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ ServiceThread serviceThread =
+ new ServiceThread(
+ TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
serviceThread.start();
return serviceThread.getLooper();
-
}
@Override
@@ -583,5 +633,10 @@ public class BackgroundInstallControlService extends SystemService {
File file = new File(dir, DISK_FILE_NAME);
return file;
}
+
+ @Override
+ public BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper() {
+ return new BackgroundInstallControlCallbackHelper();
+ }
}
}
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/Android.bp b/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
index 4fcdbfc21f6c..e3954355491d 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
+++ b/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
@@ -33,6 +33,7 @@ java_test_host {
":BackgroundInstallControlServiceTestApp",
":BackgroundInstallControlMockApp1",
":BackgroundInstallControlMockApp2",
+ ":BackgroundInstallControlMockApp3",
],
test_suites: [
"general-tests",
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml b/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
index 1e7a78aa6f93..031d57fbe182 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
+++ b/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
@@ -29,11 +29,14 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file"
- key="BackgroundInstallControlMockApp1.apk"
- value="/data/local/tmp/BackgroundInstallControlMockApp1.apk" />
+ key="BackgroundInstallControlMockApp1.apk"
+ value="/data/local/tmp/BackgroundInstallControlMockApp1.apk" />
<option name="push-file"
- key="BackgroundInstallControlMockApp2.apk"
- value="/data/local/tmp/BackgroundInstallControlMockApp2.apk" />
+ key="BackgroundInstallControlMockApp2.apk"
+ value="/data/local/tmp/BackgroundInstallControlMockApp2.apk" />
+ <option name="push-file"
+ key="BackgroundInstallControlMockApp3.apk"
+ value="/data/local/tmp/BackgroundInstallControlMockApp3.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java b/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
index 74506076d82f..5092a4659eb9 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
+++ b/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
@@ -41,17 +41,26 @@ public final class BackgroundInstallControlServiceHostTest extends BaseHostJUnit
private static final String MOCK_APK_FILE_1 = "BackgroundInstallControlMockApp1.apk";
private static final String MOCK_APK_FILE_2 = "BackgroundInstallControlMockApp2.apk";
+ // TODO: Move the silent installs to test-app using {@link
+ // BackgroundInstallControlServiceTest#installPackage(String, String)} and remove deviceConfig
+ // branch in BICS.
+ // b/310983905
@Test
public void testGetMockBackgroundInstalledPackages() throws Exception {
- installPackage(TEST_DATA_DIR + MOCK_APK_FILE_1);
+ installPackage(TEST_DATA_DIR + MOCK_APK_FILE_1);
installPackage(TEST_DATA_DIR + MOCK_APK_FILE_2);
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_1)).isNotNull();
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_2)).isNotNull();
- assertThat(getDevice().setProperty("debug.transparency.bg-install-apps",
- MOCK_PACKAGE_NAME_1 + "," + MOCK_PACKAGE_NAME_2)).isTrue();
- runDeviceTest("testGetMockBackgroundInstalledPackages");
+ assertThat(
+ getDevice()
+ .setProperty(
+ "debug.transparency.bg-install-apps",
+ MOCK_PACKAGE_NAME_1 + "," + MOCK_PACKAGE_NAME_2))
+ .isTrue();
+ runDeviceTest(
+ "BackgroundInstallControlServiceTest", "testGetMockBackgroundInstalledPackages");
assertThat(getDevice().uninstallPackage(MOCK_PACKAGE_NAME_1)).isNull();
assertThat(getDevice().uninstallPackage(MOCK_PACKAGE_NAME_2)).isNull();
@@ -59,16 +68,30 @@ public final class BackgroundInstallControlServiceHostTest extends BaseHostJUnit
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_2)).isNull();
}
+ @Test
+ public void testRegisterCallback() throws Exception {
+ runDeviceTest(
+ "BackgroundInstallControlServiceTest",
+ "testRegisterBackgroundInstallControlCallback");
+ }
+
+ @Test
+ public void testUnregisterCallback() throws Exception {
+ runDeviceTest(
+ "BackgroundInstallControlServiceTest",
+ "testUnregisterBackgroundInstallControlCallback");
+ }
+
private void installPackage(String path) throws DeviceNotAvailableException {
String cmd = "pm install -t --force-queryable " + path;
CommandResult result = getDevice().executeShellV2Command(cmd);
assertThat(result.getStatus() == CommandStatus.SUCCESS).isTrue();
}
- private void runDeviceTest(String method) throws DeviceNotAvailableException {
+ private void runDeviceTest(String testName, String method) throws DeviceNotAvailableException {
var options = new DeviceTestRunOptions(PACKAGE_NAME);
- options.setTestClassName(PACKAGE_NAME + ".BackgroundInstallControlServiceTest");
+ options.setTestClassName(PACKAGE_NAME + "." + testName);
options.setTestMethodName(method);
runDeviceTests(options);
}
-}
+} \ No newline at end of file
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
index 1fa1f84cd04e..b5b8ea0f40c7 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
@@ -21,6 +21,9 @@
<uses-library android:name="android.test.runner" />
</application>
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:label="APCT tests for background install control service"
android:targetPackage="com.android.server.pm.test.app" />
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
index b74e5619fd0c..f033fed73b27 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
@@ -16,54 +16,256 @@
package com.android.server.pm.test.app;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
import static com.google.common.truth.Truth.assertThat;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.IBackgroundInstallControlService;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.os.Bundle;
+import android.os.IRemoteCallback;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
+import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.ThrowingRunnable;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
public class BackgroundInstallControlServiceTest {
private static final String TAG = "BackgroundInstallControlServiceTest";
+ private static final String ACTION_INSTALL_COMMIT =
+ "com.android.server.pm.test.app.BackgroundInstallControlServiceTest"
+ + ".ACTION_INSTALL_COMMIT";
+ private static final String MOCK_PACKAGE_NAME = "com.android.servicestests.apps.bicmockapp3";
+
+ private static final String TEST_DATA_DIR = "/data/local/tmp/";
+ private static final String MOCK_APK_FILE = "BackgroundInstallControlMockApp3.apk";
private IBackgroundInstallControlService mIBics;
@Before
public void setUp() {
- mIBics = IBackgroundInstallControlService.Stub.asInterface(
- ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+ mIBics =
+ IBackgroundInstallControlService.Stub.asInterface(
+ ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
assertThat(mIBics).isNotNull();
}
+ @After
+ public void tearDown() {
+ runShellCommand("pm uninstall " + MOCK_PACKAGE_NAME);
+ }
+
@Test
public void testGetMockBackgroundInstalledPackages() throws RemoteException {
- ParceledListSlice<PackageInfo> slice = mIBics.getBackgroundInstalledPackages(
- PackageManager.MATCH_ALL,
- UserHandle.USER_ALL);
+ ParceledListSlice<PackageInfo> slice =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mIBics,
+ (bics) -> {
+ try {
+ return bics.getBackgroundInstalledPackages(
+ PackageManager.MATCH_ALL, Process.myUserHandle()
+ .getIdentifier());
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ },
+ QUERY_ALL_PACKAGES);
assertThat(slice).isNotNull();
var packageList = slice.getList();
assertThat(packageList).isNotNull();
assertThat(packageList).hasSize(2);
- var expectedPackageNames = Set.of("com.android.servicestests.apps.bicmockapp1",
- "com.android.servicestests.apps.bicmockapp2");
- var actualPackageNames = packageList.stream().map((packageInfo) -> packageInfo.packageName)
- .collect(Collectors.toSet());
+ var expectedPackageNames =
+ Set.of(
+ "com.android.servicestests.apps.bicmockapp1",
+ "com.android.servicestests.apps.bicmockapp2");
+ var actualPackageNames =
+ packageList.stream()
+ .map((packageInfo) -> packageInfo.packageName)
+ .collect(Collectors.toSet());
assertThat(actualPackageNames).containsExactlyElementsIn(expectedPackageNames);
}
+
+ @Test
+ public void testRegisterBackgroundInstallControlCallback()
+ throws Exception {
+ String testPackageName = "test";
+ int testUserId = 1;
+ ArrayList<Pair<String, Integer>> sharedResource = new ArrayList<>();
+ IRemoteCallback testCallback =
+ new IRemoteCallback.Stub() {
+ private final ArrayList<Pair<String, Integer>> mArray = sharedResource;
+
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ mArray.add(new Pair(testPackageName, testUserId));
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mIBics,
+ (bics) -> {
+ try {
+ bics.registerBackgroundInstallCallback(testCallback);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ },
+ QUERY_ALL_PACKAGES,
+ INTERACT_ACROSS_USERS_FULL);
+ installPackage(TEST_DATA_DIR + MOCK_APK_FILE, MOCK_PACKAGE_NAME);
+
+ assertUntil(() -> sharedResource.size() == 1, 2000);
+ assertThat(sharedResource.get(0).first).isEqualTo(testPackageName);
+ assertThat(sharedResource.get(0).second).isEqualTo(testUserId);
+ }
+
+ @Test
+ public void testUnregisterBackgroundInstallControlCallback() {
+ String testValue = "test";
+ ArrayList<String> sharedResource = new ArrayList<>();
+ IRemoteCallback testCallback =
+ new IRemoteCallback.Stub() {
+ private final ArrayList<String> mArray = sharedResource;
+
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ mArray.add(testValue);
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mIBics,
+ (bics) -> {
+ try {
+ bics.registerBackgroundInstallCallback(testCallback);
+ bics.unregisterBackgroundInstallCallback(testCallback);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ },
+ QUERY_ALL_PACKAGES,
+ INTERACT_ACROSS_USERS_FULL);
+ installPackage(TEST_DATA_DIR + MOCK_APK_FILE, MOCK_PACKAGE_NAME);
+
+ assertUntil(() -> sharedResource.isEmpty(), 2000);
+ }
+
+ private static boolean installPackage(String apkPath, String packageName) {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ final CountDownLatch installLatch = new CountDownLatch(1);
+ final BroadcastReceiver installReceiver =
+ new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ int packageInstallStatus =
+ intent.getIntExtra(
+ PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE_INVALID);
+ if (packageInstallStatus == PackageInstaller.STATUS_SUCCESS) {
+ installLatch.countDown();
+ }
+ }
+ };
+ final IntentFilter intentFilter = new IntentFilter(ACTION_INSTALL_COMMIT);
+ context.registerReceiver(installReceiver, intentFilter, Context.RECEIVER_EXPORTED);
+
+ PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+ PackageInstaller.SessionParams params =
+ new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED);
+ try {
+ int sessionId = packageInstaller.createSession(params);
+ PackageInstaller.Session session = packageInstaller.openSession(sessionId);
+ OutputStream out = session.openWrite(packageName, 0, -1);
+ FileInputStream fis = new FileInputStream(apkPath);
+ byte[] buffer = new byte[65536];
+ int size;
+ while ((size = fis.read(buffer)) != -1) {
+ out.write(buffer, 0, size);
+ }
+ session.fsync(out);
+ fis.close();
+ out.close();
+
+ runWithShellPermissionIdentity(
+ () -> {
+ session.commit(createPendingIntent(context).getIntentSender());
+ installLatch.await(5, TimeUnit.SECONDS);
+ });
+ return true;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static PendingIntent createPendingIntent(Context context) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ 1,
+ new Intent(ACTION_INSTALL_COMMIT)
+ .setPackage(
+ BackgroundInstallControlServiceTest.class.getPackageName()),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
+ return pendingIntent;
+ }
+
+ private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
+ throws Exception {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ command.run();
+ } finally {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ private static void assertUntil(Supplier<Boolean> condition, int timeoutMs) {
+ long endTime = System.currentTimeMillis() + timeoutMs;
+ while (System.currentTimeMillis() <= endTime) {
+ if (condition.get()) return;
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ assertThat(condition.get()).isTrue();
+ }
}
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp b/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
index 7804f4ce9d02..39b0ff782b72 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
@@ -50,3 +50,11 @@ android_test_helper_app {
"--rename-manifest-package com.android.servicestests.apps.bicmockapp2",
],
}
+
+android_test_helper_app {
+ name: "BackgroundInstallControlMockApp3",
+ defaults: ["bic-mock-app-defaults"],
+ aaptflags: [
+ "--rename-manifest-package com.android.servicestests.apps.bicmockapp3",
+ ],
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java
new file mode 100644
index 000000000000..e1fce9b75906
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.server.pm;
+
+import static com.android.server.pm.BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY;
+import static com.android.server.pm.BackgroundInstallControlCallbackHelper.FLAGGED_USER_ID_KEY;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.os.Bundle;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+
+/** Unit tests for {@link BackgroundInstallControlCallbackHelperTest} */
+@Presubmit
+@RunWith(JUnit4.class)
+public class BackgroundInstallControlCallbackHelperTest {
+
+ private final IRemoteCallback mCallback =
+ spy(
+ new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle extras) {}
+ });
+
+ private BackgroundInstallControlCallbackHelper mCallbackHelper;
+
+ @Before
+ public void setup() {
+ mCallbackHelper = new BackgroundInstallControlCallbackHelper();
+ }
+
+ @Test
+ public void registerBackgroundInstallControlCallback_registers_successfully() {
+ mCallbackHelper.registerBackgroundInstallCallback(mCallback);
+
+ synchronized (mCallbackHelper.mCallbacks) {
+ assertEquals(1, mCallbackHelper.mCallbacks.getRegisteredCallbackCount());
+ assertEquals(mCallback, mCallbackHelper.mCallbacks.getRegisteredCallbackItem(0));
+ }
+ }
+
+ @Test
+ public void unregisterBackgroundInstallControlCallback_unregisters_successfully() {
+ synchronized (mCallbackHelper.mCallbacks) {
+ mCallbackHelper.mCallbacks.register(mCallback);
+ }
+
+ mCallbackHelper.unregisterBackgroundInstallCallback(mCallback);
+
+ synchronized (mCallbackHelper.mCallbacks) {
+ assertEquals(0, mCallbackHelper.mCallbacks.getRegisteredCallbackCount());
+ }
+ }
+
+ @Test
+ public void notifyAllCallbacks_broadcastsToCallbacks()
+ throws RemoteException {
+ String testPackageName = "testname";
+ int testUserId = 1;
+ mCallbackHelper.registerBackgroundInstallCallback(mCallback);
+
+ mCallbackHelper.notifyAllCallbacks(testUserId, testPackageName);
+
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mCallback, after(1000).times(1)).sendResult(bundleCaptor.capture());
+ Bundle receivedBundle = bundleCaptor.getValue();
+ assertEquals(testPackageName, receivedBundle.getString(FLAGGED_PACKAGE_NAME_KEY));
+ assertEquals(testUserId, receivedBundle.getInt(FLAGGED_USER_ID_KEY));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
index daf18edaf2de..3069d25e39d7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
@@ -16,6 +16,10 @@
package com.android.server.pm;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -27,6 +31,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -97,7 +102,6 @@ public final class BackgroundInstallControlServiceTest {
private Looper mLooper;
private File mFile;
-
@Mock
private Context mContext;
@Mock
@@ -108,8 +112,12 @@ public final class BackgroundInstallControlServiceTest {
private UsageStatsManagerInternal mUsageStatsManagerInternal;
@Mock
private PermissionManagerServiceInternal mPermissionManager;
+ @Mock
+ private BackgroundInstallControlCallbackHelper mCallbackHelper;
+
@Captor
private ArgumentCaptor<PackageManagerInternal.PackageListObserver> mPackageListObserverCaptor;
+
@Captor
private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
@@ -119,11 +127,12 @@ public final class BackgroundInstallControlServiceTest {
mTestLooper = new TestLooper();
mLooper = mTestLooper.getLooper();
- mFile = new File(
- InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(),
- "test");
- mBackgroundInstallControlService = new BackgroundInstallControlService(
- new MockInjector(mContext));
+ mFile =
+ new File(
+ InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(),
+ "test");
+ mBackgroundInstallControlService =
+ new BackgroundInstallControlService(new MockInjector(mContext));
verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture());
mUsageEventListener = mUsageEventListenerCaptor.getValue();
@@ -143,8 +152,7 @@ public final class BackgroundInstallControlServiceTest {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
mBackgroundInstallControlService.initBackgroundInstalledPackages();
assertNotNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- assertEquals(0,
- mBackgroundInstallControlService.getBackgroundInstalledPackages().size());
+ assertEquals(0, mBackgroundInstallControlService.getBackgroundInstalledPackages().size());
}
@Test
@@ -161,12 +169,9 @@ public final class BackgroundInstallControlServiceTest {
// Write test data to the file on the disk.
try {
ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
- long token = protoOutputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
+ long token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
+ protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
protoOutputStream.end(token);
protoOutputStream.flush();
atomicFile.finishWrite(fileOutputStream);
@@ -198,20 +203,14 @@ public final class BackgroundInstallControlServiceTest {
try {
ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
- long token = protoOutputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
+ long token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
+ protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
protoOutputStream.end(token);
- token = protoOutputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_2);
- protoOutputStream.write(
- BackgroundInstalledPackageProto.USER_ID, USER_ID_2 + 1);
+ token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_2);
+ protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_2 + 1);
protoOutputStream.end(token);
protoOutputStream.flush();
@@ -241,7 +240,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -249,23 +248,25 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token = protoInputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token =
+ protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName = protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName =
+ protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId = protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID) - 1;
+ userId =
+ protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID)
+ - 1;
break;
default:
- fail("Undefined field in proto: "
- + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -296,7 +297,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -304,23 +305,25 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token = protoInputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token =
+ protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName = protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName =
+ protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId = protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID) - 1;
+ userId =
+ protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID)
+ - 1;
break;
default:
- fail("Undefined field in proto: "
- + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -353,7 +356,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -361,23 +364,25 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token = protoInputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token =
+ protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName = protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName =
+ protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId = protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID) - 1;
+ userId =
+ protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID)
+ - 1;
break;
default:
- fail("Undefined field in proto: "
- + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -399,51 +404,55 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_permissionDenied() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_DENIED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_permissionGranted() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(1,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(
+ 1, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_ignoredEvent() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.USER_INTERACTION,
- USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.USER_INTERACTION, USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_firstActivityResumedHalfTimeFrame() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_1);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -461,14 +470,18 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstActivityResumedOneTimeFrame() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -486,16 +499,23 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstActivityResumedOneAndHalfTimeFrame() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_3);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -517,12 +537,13 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstNoneActivityResumed() {
- assertEquals(0,
- mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ assertEquals(
+ 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -535,27 +556,26 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedNoUsageEvent() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedNoUsageEvent()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -572,27 +592,26 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedInsideTimeFrame() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedInsideTimeFrame()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -604,12 +623,16 @@ public final class BackgroundInstallControlServiceTest {
// The 2 usage events make the package adding inside a time frame.
// So it's not a background install. Thus, it's null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -617,27 +640,26 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedOutsideTimeFrame1() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedOutsideTimeFrame1()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -650,12 +672,16 @@ public final class BackgroundInstallControlServiceTest {
// Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
// it's a background install. Thus, it's not null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -665,28 +691,28 @@ public final class BackgroundInstallControlServiceTest {
assertEquals(1, packages.size());
assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
}
+
@Test
- public void testHandleUsageEvent_packageAddedOutsideTimeFrame2() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedOutsideTimeFrame2()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -700,12 +726,16 @@ public final class BackgroundInstallControlServiceTest {
// Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
// it's a background install. Thus, it's not null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_2,
+ INSTALLER_NAME_2,
+ USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -715,31 +745,31 @@ public final class BackgroundInstallControlServiceTest {
assertEquals(1, packages.size());
assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
}
+
@Test
- public void testHandleUsageEvent_packageAddedThroughAdb() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedThroughAdb()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
// This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
// initiatingPackageName used to be null but is now "com.android.shell". This test ensures
// that the behavior is still the same for when the initiatingPackageName is null.
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ null,
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ null,
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
// b/265203007
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -751,12 +781,16 @@ public final class BackgroundInstallControlServiceTest {
// for ADB installs the initiatingPackageName used to be null, despite being detected
// as a background install. Since we do not want to treat side-loaded apps as background
// install getBackgroundInstalledPackages() is expected to return null
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -764,31 +798,31 @@ public final class BackgroundInstallControlServiceTest {
var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
assertNull(packages);
}
+
@Test
- public void testHandleUsageEvent_packageAddedThroughAdb2() throws
- NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedThroughAdb2()
+ throws NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
// This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
// initiatingPackageName used to be null but is now "com.android.shell". This test ensures
// that the behavior is still the same after this change.
- InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- /* initiatingPackageName = */ "com.android.shell",
- /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null,
- /* installingPackageName = */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo =
+ new InstallSourceInfo(
+ /* initiatingPackageName= */ "com.android.shell",
+ /* initiatingPackageSigningInfo= */ null,
+ /* originatingPackageName= */ null,
+ /* installingPackageName= */ INSTALLER_NAME_1);
// b/265203007
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(
- eq(PACKAGE_NAME_1),
- any(),
- anyInt())
- ).thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
+ .thenReturn(appInfo);
- long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
- - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(appInfo,
+ long createTimestamp =
+ PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(
+ appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -800,12 +834,16 @@ public final class BackgroundInstallControlServiceTest {
// for ADB installs the initiatingPackageName is com.android.shell, despite being detected
// as a background install. Since we do not want to treat side-loaded apps as background
// install getBackgroundInstalledPackages() is expected to return null
- doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
- anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(Event.ACTIVITY_STOPPED,
- USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManager)
+ .checkPermission(anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(
+ UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1,
+ INSTALLER_NAME_1,
+ USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(
+ Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -813,6 +851,7 @@ public final class BackgroundInstallControlServiceTest {
var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
assertNull(packages);
}
+
@Test
public void testPackageRemoved() {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
@@ -859,8 +898,7 @@ public final class BackgroundInstallControlServiceTest {
packages.add(packageInfo2);
var packageInfo3 = makePackageInfo(PACKAGE_NAME_3);
packages.add(packageInfo3);
- doReturn(packages).when(mPackageManager).getInstalledPackagesAsUser(
- any(), anyInt());
+ doReturn(packages).when(mPackageManager).getInstalledPackagesAsUser(any(), anyInt());
var resultPackages =
mBackgroundInstallControlService.getBackgroundInstalledPackages(0L, USER_ID_1);
@@ -870,18 +908,44 @@ public final class BackgroundInstallControlServiceTest {
assertFalse(resultPackages.getList().contains(packageInfo3));
}
+ @Test(expected = SecurityException.class)
+ public void enforceCallerQueryPackagesPermissionsThrowsSecurityException() {
+ doThrow(new SecurityException("test")).when(mContext)
+ .enforceCallingPermission(eq(QUERY_ALL_PACKAGES), anyString());
+
+ mBackgroundInstallControlService.enforceCallerQueryPackagesPermissions();
+ }
+
+ @Test
+ public void enforceCallerQueryPackagesPermissionsDoesNotThrowSecurityException() {
+ //enforceCallerQueryPackagesPermissions do not throw
+
+ mBackgroundInstallControlService.enforceCallerQueryPackagesPermissions();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void enforceCallerInteractCrossUserPermissionsThrowsSecurityException() {
+ doThrow(new SecurityException("test")).when(mContext)
+ .enforceCallingPermission(eq(INTERACT_ACROSS_USERS_FULL), anyString());
+
+ mBackgroundInstallControlService.enforceCallerInteractCrossUserPermissions();
+ }
+ @Test
+ public void enforceCallerInteractCrossUserPermissionsDoesNotThrowSecurityException() {
+ //enforceCallerQueryPackagesPermissions do not throw
+
+ mBackgroundInstallControlService.enforceCallerInteractCrossUserPermissions();
+ }
+
/**
* Mock a usage event occurring.
*
* @param usageEventId id of a usage event
- * @param userId user id of a usage event
- * @param pkgName package name of a usage event
- * @param timestamp timestamp of a usage event
+ * @param userId user id of a usage event
+ * @param pkgName package name of a usage event
+ * @param timestamp timestamp of a usage event
*/
- private void generateUsageEvent(int usageEventId,
- int userId,
- String pkgName,
- long timestamp) {
+ private void generateUsageEvent(int usageEventId, int userId, String pkgName, long timestamp) {
Event event = new Event(usageEventId, timestamp);
event.mPackage = pkgName;
mUsageEventListener.onUsageEvent(userId, event);
@@ -935,5 +999,10 @@ public final class BackgroundInstallControlServiceTest {
public File getDiskFile() {
return mFile;
}
+
+ @Override
+ public BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper() {
+ return mCallbackHelper;
+ }
}
}
diff --git a/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
index 2bc056ee743f..fee1b25f04e5 100644
--- a/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
+++ b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
@@ -16,6 +16,9 @@
package android.transparency.test.app;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -27,6 +30,7 @@ import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.internal.os.IBinaryTransparencyService.AppInfo;
import org.junit.Before;
@@ -116,7 +120,13 @@ public class BinaryTransparencyTest {
@Test
public void testCollectAllSilentInstalledMbaInfo() {
// Action
- var appInfoList = mBt.collectAllSilentInstalledMbaInfo(new Bundle());
+ var appInfoList =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mBt,
+ (Bt) ->
+ mBt.collectAllSilentInstalledMbaInfo(new Bundle()),
+ QUERY_ALL_PACKAGES,
+ INTERACT_ACROSS_USERS_FULL);
// Verify
assertThat(appInfoList).isNotEmpty(); // because we just installed from the host side