New Importance API for Rb
Bug: 292533010
Test: atest CtsGetBindingUidImportanceTest
... with and without android.app.get_binding_uid_importance set.
Change-Id: Iee6f0e08ba499f2f51d8173e45168c69933cd451
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0ad73af..0cfd10f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -133,6 +133,7 @@
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_METADATA = "android.permission.GET_APP_METADATA";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
+ field @FlaggedApi("android.app.get_binding_uid_importance") public static final String GET_BINDING_UID_IMPORTANCE = "android.permission.GET_BINDING_UID_IMPORTANCE";
field public static final String GET_HISTORICAL_APP_OPS_STATS = "android.permission.GET_HISTORICAL_APP_OPS_STATS";
field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
@@ -542,6 +543,7 @@
public class ActivityManager {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
+ method @FlaggedApi("android.app.get_binding_uid_importance") @RequiresPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE) public int getBindingUidImportance(int);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
method @FlaggedApi("android.app.app_start_info") @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f68681b..8b4ebae 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -73,7 +73,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -4269,6 +4268,33 @@
}
/**
+ * Same as {@link #getUidImportance(int)}, but it only works on UIDs that currently
+ * have a service binding, or provider reference, to the calling UID, even if the target UID
+ * belong to another android user or profile.
+ *
+ * <p>This will return {@link RunningAppProcessInfo#IMPORTANCE_GONE} on all other UIDs,
+ * regardless of if they're valid or not.
+ *
+ * <p>Privileged system apps may prefer this API to {@link #getUidImportance(int)} to
+ * avoid requesting the permission {@link Manifest.permission#PACKAGE_USAGE_STATS}, which
+ * would allow access to APIs that return more senstive information.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_GET_BINDING_UID_IMPORTANCE)
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GET_BINDING_UID_IMPORTANCE)
+ public @RunningAppProcessInfo.Importance int getBindingUidImportance(int uid) {
+ try {
+ int procState = getService().getBindingUidProcessState(uid,
+ mContext.getOpPackageName());
+ return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback to get reports about changes to the importance of a uid. Use with
* {@link #addOnUidImportanceListener}.
* @hide
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 520bf7d..260e985 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -949,4 +949,5 @@
* @param err The binder transaction error
*/
oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
+ int getBindingUidProcessState(int uid, in String callingPackage);
}
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 2076e85..b303ea6 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -5,4 +5,11 @@
name: "app_start_info"
description: "Control collecting of ApplicationStartInfo records and APIs."
bug: "247814855"
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "backstage_power"
+ name: "get_binding_uid_importance"
+ description: "API to get importance of UID that's binding to the caller"
+ bug: "292533010"
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8c91be8..25958ee 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7765,6 +7765,15 @@
<permission android:name="android.permission.WRITE_FLAGS"
android:protectionLevel="signature" />
+ <!-- @hide @SystemApi
+ @FlaggedApi("android.app.get_binding_uid_importance")
+ Allows to get the importance of an UID that has a service
+ binding to the app.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @hide Allows internal applications to manage displays.
<p>This means intercept internal signals about displays being (dis-)connected
and being able to enable or disable the external displays.
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 69aa401..ab18a50 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -529,6 +529,7 @@
<permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
<!-- Permission required for CTS test IntentRedirectionTest -->
<permission name="android.permission.QUERY_CLONED_APPS"/>
+ <permission name="android.permission.GET_BINDING_UID_IMPORTANCE"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 10d04d3..5bd37c3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -863,6 +863,7 @@
<!-- Permissions required for CTS test - CtsVoiceInteractionTestCases -->
<uses-permission android:name="android.permission.RESET_HOTWORD_TRAINING_DATA_EGRESS_COUNT" />
<uses-permission android:name="android.permission.RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA" />
+ <uses-permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE" />
<application
android:label="@string/app_label"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ae79f19..82f6724 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -79,6 +79,7 @@
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_BTOP;
@@ -7698,14 +7699,100 @@
"getUidProcessState", callingPackage); // Ignore return value
synchronized (mProcLock) {
- if (mPendingStartActivityUids.isPendingTopUid(uid)) {
- return PROCESS_STATE_TOP;
- }
- return mProcessList.getUidProcStateLOSP(uid);
+ return getUidProcessStateInnerLOSP(uid);
}
}
@Override
+ public int getBindingUidProcessState(int targetUid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE,
+ "getBindingUidProcessState");
+ }
+ // We don't need to do a cross-user check here (unlike getUidProcessState),
+ // because we only allow to see UIDs that are actively communicating with the caller.
+
+ final int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final boolean allowed = (callingUid == targetUid)
+ || hasServiceBindingOrProviderUseLocked(callingUid, targetUid);
+ if (!allowed) {
+ return PROCESS_STATE_NONEXISTENT;
+ }
+ return getUidProcessStateInnerLOSP(targetUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @GuardedBy(anyOf = {"this", "mProcLock"})
+ private int getUidProcessStateInnerLOSP(int uid) {
+ if (mPendingStartActivityUids.isPendingTopUid(uid)) {
+ return PROCESS_STATE_TOP;
+ }
+ return mProcessList.getUidProcStateLOSP(uid);
+ }
+
+ /**
+ * Ensure that {@code clientUid} has a bound service client to {@code callingUid}
+ */
+ @GuardedBy("this")
+ private boolean hasServiceBindingOrProviderUseLocked(int callingUid, int clientUid) {
+ // See if there's a service binding
+ final Boolean hasBinding = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessServiceRecord psr = pr.mServices;
+ final int serviceCount = psr.mServices.size();
+ for (int svc = 0; svc < serviceCount; svc++) {
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ psr.mServices.valueAt(svc).getConnections();
+ final int size = conns.size();
+ for (int conni = 0; conni < size; conni++) {
+ final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+ for (int con = 0; con < crs.size(); con++) {
+ final ConnectionRecord cr = crs.get(con);
+ final ProcessRecord clientPr = cr.binding.client;
+
+ if (clientPr.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ });
+ if (Boolean.TRUE.equals(hasBinding)) {
+ return true;
+ }
+
+ final Boolean hasProviderClient = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessProviderRecord ppr = pr.mProviders;
+ for (int provi = ppr.numberOfProviders() - 1; provi >= 0; provi--) {
+ ContentProviderRecord cpr = ppr.getProviderAt(provi);
+
+ for (int i = cpr.connections.size() - 1; i >= 0; i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ if (client.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ return null;
+ });
+
+ return Boolean.TRUE.equals(hasProviderClient);
+ }
+
+ @Override
public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,