Support package private shared isolated processes.

BUG: 312706530
Test: atest ActiveServicesTest
Test: atest android.externalservice.cts.SharedIsolatedServiceTest
Change-Id: I1e9a9fd83a3c56b1a17d926c128eca6b3ac4998a
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index ce311d0..0916227 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -74,6 +74,7 @@
     ":android.chre.flags-aconfig-java{.generated_srcjars}",
     ":android.speech.flags-aconfig-java{.generated_srcjars}",
     ":power_flags_lib{.generated_srcjars}",
+    ":android.content.flags-aconfig-java{.generated_srcjars}",
 ]
 
 filegroup {
@@ -940,3 +941,16 @@
     aconfig_declarations: "power_flags",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// Content
+aconfig_declarations {
+    name: "android.content.flags-aconfig",
+    package: "android.content.flags",
+    srcs: ["core/java/android/content/flags/flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.content.flags-aconfig-java",
+    aconfig_declarations: "android.content.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index 46c8f82..177cff1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10545,6 +10545,7 @@
     field public static final int BIND_INCLUDE_CAPABILITIES = 4096; // 0x1000
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_NOT_PERCEPTIBLE = 256; // 0x100
+    field @FlaggedApi("android.content.flags.enable_bind_package_isolated_process") public static final int BIND_PACKAGE_ISOLATED_PROCESS = 16384; // 0x4000
     field public static final int BIND_SHARED_ISOLATED_PROCESS = 8192; // 0x2000
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
     field public static final String BIOMETRIC_SERVICE = "biometric";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fa76e39..31c7c78 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
+
 import android.annotation.AttrRes;
 import android.annotation.CallbackExecutor;
 import android.annotation.CheckResult;
@@ -296,6 +298,7 @@
             BIND_ALLOW_ACTIVITY_STARTS,
             BIND_INCLUDE_CAPABILITIES,
             BIND_SHARED_ISOLATED_PROCESS,
+            BIND_PACKAGE_ISOLATED_PROCESS,
             BIND_EXTERNAL_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -318,6 +321,7 @@
             BIND_ALLOW_ACTIVITY_STARTS,
             BIND_INCLUDE_CAPABILITIES,
             BIND_SHARED_ISOLATED_PROCESS,
+            BIND_PACKAGE_ISOLATED_PROCESS,
             // Intentionally not include BIND_EXTERNAL_SERVICE, because it'd cause sign-extension.
             // This would allow Android Studio to show a warning, if someone tries to use
             // BIND_EXTERNAL_SERVICE BindServiceFlags.
@@ -511,6 +515,26 @@
      */
     public static final int BIND_SHARED_ISOLATED_PROCESS = 0x00002000;
 
+    /**
+     * Flag for {@link #bindIsolatedService}: Bind the service into a shared isolated process,
+     * but only with other isolated services from the same package that declare the same process
+     * name.
+     *
+     * <p>Specifying this flag allows multiple isolated services defined in the same package to be
+     * running in a single shared isolated process. This shared isolated process must be specified
+     * since this flag will not work with the default application process.
+     *
+     * <p>This flag is different from {@link #BIND_SHARED_ISOLATED_PROCESS} since it only
+     * allows binding services from the same package in the same shared isolated process. This also
+     * means the shared package isolated process is global, and not scoped to each potential
+     * calling app.
+     *
+     * <p>The shared isolated process instance is identified by the "android:process" attribute
+     * defined by the service. This flag cannot be used without this attribute set.
+     */
+    @FlaggedApi(FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS)
+    public static final int BIND_PACKAGE_ISOLATED_PROCESS = 1 << 14;
+
     /***********    Public flags above this line ***********/
     /***********    Hidden flags below this line ***********/
 
diff --git a/core/java/android/content/flags/flags.aconfig b/core/java/android/content/flags/flags.aconfig
new file mode 100644
index 0000000..3445fb5
--- /dev/null
+++ b/core/java/android/content/flags/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.content.flags"
+
+flag {
+    name: "enable_bind_package_isolated_process"
+    namespace: "machine_learning"
+    description: "This flag enables the newly added flag for binding package-private isolated processes."
+    bug: "312706530"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0cff8b7..c90cc3d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -94,6 +94,8 @@
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
+import static android.content.flags.Flags.enableBindPackageIsolatedProcess;
+
 
 import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH;
 import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_DELEGATE;
@@ -791,13 +793,15 @@
 
     static String getProcessNameForService(ServiceInfo sInfo, ComponentName name,
             String callingPackage, String instanceName, boolean isSdkSandbox,
-            boolean inSharedIsolatedProcess) {
+            boolean inSharedIsolatedProcess, boolean inPrivateSharedIsolatedProcess) {
         if (isSdkSandbox) {
             // For SDK sandbox, the process name is passed in as the instanceName
             return instanceName;
         }
-        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
-            // For regular processes, just the name in sInfo
+        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0
+                || (inPrivateSharedIsolatedProcess && !isDefaultProcessService(sInfo))) {
+            // For regular processes, or private package-shared isolated processes, just the name
+            // in sInfo
             return sInfo.processName;
         }
         // Isolated processes remain.
@@ -809,6 +813,10 @@
         }
     }
 
+    private static boolean isDefaultProcessService(ServiceInfo serviceInfo) {
+        return serviceInfo.applicationInfo.processName.equals(serviceInfo.processName);
+    }
+
     private static void traceInstant(@NonNull String message, @NonNull ServiceRecord service) {
         if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
             return;
@@ -864,7 +872,7 @@
 
         ServiceLookupResult res = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                 sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, callingPackage,
-                callingPid, callingUid, userId, true, callerFg, false, false, null, false);
+                callingPid, callingUid, userId, true, callerFg, false, false, null, false, false);
         if (res == null) {
             return null;
         }
@@ -1550,7 +1558,7 @@
         ServiceLookupResult r = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                 sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, null,
                 Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false,
-                null, false);
+                null, false, false);
         if (r != null) {
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
@@ -1642,7 +1650,7 @@
     IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
         ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage,
                 Binder.getCallingPid(), Binder.getCallingUid(),
-                UserHandle.getCallingUserId(), false, false, false, false, false);
+                UserHandle.getCallingUserId(), false, false, false, false, false, false);
 
         IBinder ret = null;
         if (r != null) {
@@ -3714,6 +3722,9 @@
                 || (flags & Context.BIND_EXTERNAL_SERVICE_LONG) != 0;
         final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
         final boolean inSharedIsolatedProcess = (flags & Context.BIND_SHARED_ISOLATED_PROCESS) != 0;
+        final boolean inPrivateSharedIsolatedProcess =
+                ((flags & Context.BIND_PACKAGE_ISOLATED_PROCESS) != 0)
+                        && enableBindPackageIsolatedProcess();
         final boolean matchQuarantined =
                 (flags & Context.BIND_MATCH_QUARANTINED_COMPONENTS) != 0;
 
@@ -3725,7 +3736,7 @@
                 isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
                 resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
                 isBindExternal, allowInstant, null /* fgsDelegateOptions */,
-                inSharedIsolatedProcess, matchQuarantined);
+                inSharedIsolatedProcess, inPrivateSharedIsolatedProcess, matchQuarantined);
         if (res == null) {
             return 0;
         }
@@ -4204,14 +4215,14 @@
     }
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
-            String instanceName, String resolvedType, String callingPackage,
-            int callingPid, int callingUid, int userId,
-            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
-            boolean allowInstant, boolean inSharedIsolatedProcess) {
+            String instanceName, String resolvedType, String callingPackage, int callingPid,
+            int callingUid, int userId, boolean createIfNeeded, boolean callingFromFg,
+            boolean isBindExternal, boolean allowInstant, boolean inSharedIsolatedProcess,
+            boolean inPrivateSharedIsolatedProcess) {
         return retrieveServiceLocked(service, instanceName, false, INVALID_UID, null, resolvedType,
                 callingPackage, callingPid, callingUid, userId, createIfNeeded, callingFromFg,
                 isBindExternal, allowInstant, null /* fgsDelegateOptions */,
-                inSharedIsolatedProcess);
+                inSharedIsolatedProcess, inPrivateSharedIsolatedProcess);
     }
 
     // TODO(b/265746493): Special case for HotwordDetectionService,
@@ -4233,21 +4244,22 @@
             String callingPackage, int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
             boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions,
-            boolean inSharedIsolatedProcess) {
+            boolean inSharedIsolatedProcess, boolean inPrivateSharedIsolatedProcess) {
         return retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                 sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, callingPackage,
                 callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
                 allowInstant, fgsDelegateOptions, inSharedIsolatedProcess,
-                false /* matchQuarantined */);
+                inPrivateSharedIsolatedProcess, false /* matchQuarantined */);
     }
 
-    private ServiceLookupResult retrieveServiceLocked(Intent service,
-            String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
-            String sdkSandboxClientAppPackage, String resolvedType,
+    private ServiceLookupResult retrieveServiceLocked(
+            Intent service, String instanceName, boolean isSdkSandboxService,
+            int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String resolvedType,
             String callingPackage, int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
             boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions,
-            boolean inSharedIsolatedProcess, boolean matchQuarantined) {
+            boolean inSharedIsolatedProcess, boolean inPrivateSharedIsolatedProcess,
+            boolean matchQuarantined) {
         if (isSdkSandboxService && instanceName == null) {
             throw new IllegalArgumentException("No instanceName provided for sdk sandbox process");
         }
@@ -4344,7 +4356,8 @@
                 final ServiceRestarter res = new ServiceRestarter();
                 final String processName = getProcessNameForService(sInfo, cn, callingPackage,
                         null /* instanceName */, false /* isSdkSandbox */,
-                        false /* inSharedIsolatedProcess */);
+                        false /* inSharedIsolatedProcess */,
+                        false /*inPrivateSharedIsolatedProcess*/);
                 r = new ServiceRecord(mAm, cn /* name */, cn /* instanceName */,
                         sInfo.applicationInfo.packageName, sInfo.applicationInfo.uid, filter, sInfo,
                         callingFromFg, res, processName,
@@ -4415,6 +4428,10 @@
                             throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
                                     + className + " is not exported");
                         }
+                        if (inPrivateSharedIsolatedProcess) {
+                            throw new SecurityException("BIND_PACKAGE_ISOLATED_PROCESS cannot be "
+                                    + "applied to an external service.");
+                        }
                         if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
                             throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
                                     + className + " is not an isolatedProcess");
@@ -4448,20 +4465,30 @@
                     throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
                             " is not an externalService");
                 }
-                if (inSharedIsolatedProcess) {
+                if (inSharedIsolatedProcess && inPrivateSharedIsolatedProcess) {
+                    throw new SecurityException("Either BIND_SHARED_ISOLATED_PROCESS or "
+                            + "BIND_PACKAGE_ISOLATED_PROCESS should be set. Not both.");
+                }
+                if (inSharedIsolatedProcess || inPrivateSharedIsolatedProcess) {
                     if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
                         throw new SecurityException("BIND_SHARED_ISOLATED_PROCESS failed, "
                                 + className + " is not an isolatedProcess");
                     }
+                }
+                if (inPrivateSharedIsolatedProcess && isDefaultProcessService(sInfo)) {
+                    throw new SecurityException("BIND_PACKAGE_ISOLATED_PROCESS cannot be used for "
+                            + "services running in the main app process.");
+                }
+                if (inSharedIsolatedProcess) {
+                    if (instanceName == null) {
+                        throw new IllegalArgumentException("instanceName must be provided for "
+                                + "binding a service into a shared isolated process.");
+                    }
                     if ((sInfo.flags & ServiceInfo.FLAG_ALLOW_SHARED_ISOLATED_PROCESS) == 0) {
                         throw new SecurityException("BIND_SHARED_ISOLATED_PROCESS failed, "
                                 + className + " has not set the allowSharedIsolatedProcess "
                                 + " attribute.");
                     }
-                    if (instanceName == null) {
-                        throw new IllegalArgumentException("instanceName must be provided for "
-                                + "binding a service into a shared isolated process.");
-                    }
                 }
                 if (userId > 0) {
                     if (mAm.isSystemUserOnly(sInfo.flags)) {
@@ -4503,11 +4530,13 @@
                             = new Intent.FilterComparison(service.cloneFilter());
                     final ServiceRestarter res = new ServiceRestarter();
                     String processName = getProcessNameForService(sInfo, name, callingPackage,
-                            instanceName, isSdkSandboxService, inSharedIsolatedProcess);
+                            instanceName, isSdkSandboxService, inSharedIsolatedProcess,
+                            inPrivateSharedIsolatedProcess);
                     r = new ServiceRecord(mAm, className, name, definingPackageName,
                             definingUid, filter, sInfo, callingFromFg, res,
                             processName, sdkSandboxClientAppUid,
-                            sdkSandboxClientAppPackage, inSharedIsolatedProcess);
+                            sdkSandboxClientAppPackage,
+                            (inSharedIsolatedProcess || inPrivateSharedIsolatedProcess));
                     res.setService(r);
                     smap.mServicesByInstanceName.put(name, r);
                     smap.mServicesByIntent.put(filter, r);
@@ -8504,7 +8533,8 @@
                 null /* sdkSandboxClientAppPackage */, null /* resolvedType */, callingPackage,
                 callingPid, callingUid, userId, true /* createIfNeeded */,
                 false /* callingFromFg */, false /* isBindExternal */, false /* allowInstant */ ,
-                options, false /* inSharedIsolatedProcess */);
+                options, false /* inSharedIsolatedProcess */,
+                false /*inPrivateSharedIsolatedProcess*/);
         if (res == null || res.record == null) {
             Slog.d(TAG,
                     "startForegroundServiceDelegateLocked retrieveServiceLocked returns null");
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java
index e2c338a..7e1dc08 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java
@@ -202,7 +202,7 @@
         final ServiceInfo regularService = new ServiceInfo();
         regularService.processName = "com.foo";
         String processName = ActiveServices.getProcessNameForService(regularService, null, null,
-                null, false, false);
+                null, false, false, false);
         assertEquals("com.foo", processName);
 
         // Isolated service
@@ -211,29 +211,90 @@
         isolatedService.flags = ServiceInfo.FLAG_ISOLATED_PROCESS;
         final ComponentName component = new ComponentName("com.foo", "barService");
         processName = ActiveServices.getProcessNameForService(isolatedService, component,
-                null, null, false, false);
+                null, null, false, false, false);
         assertEquals("com.foo:barService", processName);
 
+        // Isolated Service in package private process.
+        final ServiceInfo isolatedService1 = new ServiceInfo();
+        isolatedService1.processName = "com.foo:trusted_isolated";
+        isolatedService1.flags = ServiceInfo.FLAG_ISOLATED_PROCESS;
+        final ComponentName componentName = new ComponentName("com.foo", "barService");
+        processName = ActiveServices.getProcessNameForService(isolatedService1, componentName,
+                null, null, false, false, false);
+        assertEquals("com.foo:trusted_isolated:barService", processName);
+
+        // Isolated service in package-private shared process (main process)
+        final ServiceInfo isolatedPackageSharedService = new ServiceInfo();
+        final ComponentName componentName1 = new ComponentName("com.foo", "barService");
+        isolatedPackageSharedService.processName = "com.foo";
+        isolatedPackageSharedService.applicationInfo = new ApplicationInfo();
+        isolatedPackageSharedService.applicationInfo.processName = "com.foo";
+        isolatedPackageSharedService.flags = ServiceInfo.FLAG_ISOLATED_PROCESS;
+        String packageSharedIsolatedProcessName = ActiveServices.getProcessNameForService(
+                isolatedPackageSharedService, componentName1, null, null, false, false, true);
+        assertEquals("com.foo:barService", packageSharedIsolatedProcessName);
+
+        // Isolated service in package-private shared process
+        final ServiceInfo isolatedPackageSharedService1 = new ServiceInfo(
+                isolatedPackageSharedService);
+        isolatedPackageSharedService1.processName = "com.foo:trusted_isolated";
+        isolatedPackageSharedService1.applicationInfo = new ApplicationInfo();
+        isolatedPackageSharedService1.applicationInfo.processName = "com.foo";
+        isolatedPackageSharedService1.flags = ServiceInfo.FLAG_ISOLATED_PROCESS;
+        packageSharedIsolatedProcessName = ActiveServices.getProcessNameForService(
+                isolatedPackageSharedService1, componentName1, null, null, false, false, true);
+        assertEquals("com.foo:trusted_isolated", packageSharedIsolatedProcessName);
+
+
+        // Bind another one in the same isolated process
+        final ServiceInfo isolatedPackageSharedService2 = new ServiceInfo(
+                isolatedPackageSharedService1);
+        packageSharedIsolatedProcessName = ActiveServices.getProcessNameForService(
+                isolatedPackageSharedService2, componentName1, null, null, false, false, true);
+        assertEquals("com.foo:trusted_isolated", packageSharedIsolatedProcessName);
+
+        // Simulate another app trying to do the bind.
+        final ServiceInfo isolatedPackageSharedService3 = new ServiceInfo(
+                isolatedPackageSharedService1);
+        final String auxCallingPackage = "com.bar";
+        packageSharedIsolatedProcessName = ActiveServices.getProcessNameForService(
+                isolatedPackageSharedService3, componentName1, auxCallingPackage, null,
+                false, false, true);
+        assertEquals("com.foo:trusted_isolated", packageSharedIsolatedProcessName);
+
+        // Simulate another app owning the service
+        final ServiceInfo isolatedOtherPackageSharedService = new ServiceInfo(
+                isolatedPackageSharedService1);
+        final ComponentName componentName2 = new ComponentName("com.bar", "barService");
+        isolatedOtherPackageSharedService.processName = "com.bar:isolated";
+        isolatedPackageSharedService.applicationInfo.processName = "com.bar";
+        final String mainCallingPackage = "com.foo";
+        packageSharedIsolatedProcessName = ActiveServices.getProcessNameForService(
+                isolatedOtherPackageSharedService, componentName2, mainCallingPackage,
+                null, false, false, true);
+        assertEquals("com.bar:isolated", packageSharedIsolatedProcessName);
+
         // Isolated service in shared isolated process
         final ServiceInfo isolatedServiceShared1 = new ServiceInfo();
         isolatedServiceShared1.flags = ServiceInfo.FLAG_ISOLATED_PROCESS;
         final String instanceName = "pool";
         final String callingPackage = "com.foo";
         final String sharedIsolatedProcessName1 = ActiveServices.getProcessNameForService(
-                isolatedServiceShared1, null, callingPackage, instanceName, false, true);
+                isolatedServiceShared1, null, callingPackage, instanceName, false, true, false);
         assertEquals("com.foo:ishared:pool", sharedIsolatedProcessName1);
 
         // Bind another one in the same isolated process
         final ServiceInfo isolatedServiceShared2 = new ServiceInfo(isolatedServiceShared1);
         final String sharedIsolatedProcessName2 = ActiveServices.getProcessNameForService(
-                isolatedServiceShared2, null, callingPackage, instanceName, false, true);
+                isolatedServiceShared2, null, callingPackage, instanceName, false, true, false);
         assertEquals(sharedIsolatedProcessName1, sharedIsolatedProcessName2);
 
         // Simulate another app trying to do the bind
         final ServiceInfo isolatedServiceShared3 = new ServiceInfo(isolatedServiceShared1);
         final String otherCallingPackage = "com.bar";
         final String sharedIsolatedProcessName3 = ActiveServices.getProcessNameForService(
-                isolatedServiceShared3, null, otherCallingPackage, instanceName, false, true);
+                isolatedServiceShared3, null, otherCallingPackage, instanceName, false, true,
+                false);
         Assert.assertNotEquals(sharedIsolatedProcessName2, sharedIsolatedProcessName3);
     }