From 72d234ea09b428032d3e89cf2de101f75352c705 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 2 Dec 2022 14:33:10 +0100 Subject: [PATCH 1/2] Support shared isolated processes. This introduces a new flag, Context.BIND_SHARED_ISOLATED_PROCESS, which allows a single client to bind multiple isolated services into a single isolated process. This allows the system to save resources when multiple isolated services can safely be co-located into a single isolated process. We reuse the existing instanceName parameter to specify the name of the isolated process. After the first bind for a client with a particular instanceName, subsequent service binds with the same flag and instanceName will result in the service being bound into the already existing isolated process. These are scoped to the client app; it is not possible for an app to bind an isolated service into a shared isolated process that belongs to another app. Bug: 243554393 Test: atest ActiveServicesTest Test: atest android.externalservice.cts.SharedIsolatedServiceTest Change-Id: I6b88c551082be849f384849955d3a43e0aa707c1 --- core/api/current.txt | 1 + core/java/android/content/Context.java | 19 ++- .../com/android/server/am/ActiveServices.java | 130 ++++++++++++++---- .../server/am/ActivityManagerService.java | 2 +- .../com/android/server/am/ProcessList.java | 10 ++ .../com/android/server/am/ServiceRecord.java | 20 ++- .../android/server/am/ActiveServicesTest.java | 43 ++++++ 7 files changed, 182 insertions(+), 43 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 64f95774d601f..a75dbcf00d145 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9945,6 +9945,7 @@ package android.content { 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 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"; field public static final String BLOB_STORE_SERVICE = "blob_store"; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index bb3bf5cc2b184..86e353cfc935f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -276,7 +276,8 @@ public abstract class Context { BIND_IMPORTANT, BIND_ADJUST_WITH_ACTIVITY, BIND_NOT_PERCEPTIBLE, - BIND_INCLUDE_CAPABILITIES + BIND_INCLUDE_CAPABILITIES, + BIND_SHARED_ISOLATED_PROCESS }) @Retention(RetentionPolicy.SOURCE) public @interface BindServiceFlags {} @@ -393,6 +394,22 @@ public abstract class Context { */ public static final int BIND_INCLUDE_CAPABILITIES = 0x000001000; + /** + * Flag for {@link #bindIsolatedService}: Bind the service into a shared isolated process. + * Specifying this flag allows multiple isolated services to be running in a single shared + * isolated process. + * + * The shared isolated process instance is identified by the instanceName + * parameter in {@link #bindIsolatedService(Intent, int, String, Executor, ServiceConnection)}. + * + * Subsequent calls to {@link #bindIsolatedService} with the same instanceName + * will cause the isolated service to be co-located in the same shared isolated process. + * + * Note that the shared isolated process is scoped to the calling app; once created, only + * the calling app can bind additional isolated services into the shared process. + */ + public static final int BIND_SHARED_ISOLATED_PROCESS = 0x00002000; + /*********** Public flags above this line ***********/ /*********** Hidden flags below this line ***********/ diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 87daa6d35a824..1a74c2ba1c135 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -704,6 +704,26 @@ public final class ActiveServices { } } + static String getProcessNameForService(ServiceInfo sInfo, ComponentName name, + String callingPackage, String instanceName, boolean isSdkSandbox, + boolean inSharedIsolatedProcess) { + 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 + return sInfo.processName; + } + // Isolated processes remain. + if (inSharedIsolatedProcess) { + // Shared isolated processes are scoped to the calling package + return callingPackage + ":ishared:" + instanceName; + } else { + return sInfo.processName + ":" + name.getClassName(); + } + } + ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, @Nullable String callingFeatureId, final int userId) @@ -736,7 +756,7 @@ public final class ActiveServices { ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType, callingPackage, - callingPid, callingUid, userId, true, callerFg, false, false); + callingPid, callingUid, userId, true, callerFg, false, false, false); if (res == null) { return null; } @@ -1338,7 +1358,8 @@ public final class ActiveServices { // If this service is active, make sure it is stopped. ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, null, - Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false); + Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false, + false); if (r != null) { if (r.record != null) { final long origId = Binder.clearCallingIdentity(); @@ -1430,7 +1451,7 @@ public final class ActiveServices { 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); + UserHandle.getCallingUserId(), false, false, false, false, false); IBinder ret = null; if (r != null) { @@ -3237,11 +3258,13 @@ public final class ActiveServices { != ProcessList.SCHED_GROUP_BACKGROUND; final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0; final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0; + final boolean inSharedIsolatedProcess = (flags & Context.BIND_SHARED_ISOLATED_PROCESS) != 0; ServiceLookupResult res = retrieveServiceLocked(service, instanceName, isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, - isBindExternal, allowInstant, null /* fgsDelegateOptions */); + isBindExternal, allowInstant, null /* fgsDelegateOptions */, + inSharedIsolatedProcess); if (res == null) { return 0; } @@ -3697,10 +3720,11 @@ public final class ActiveServices { String instanceName, String resolvedType, String callingPackage, int callingPid, int callingUid, int userId, boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal, - boolean allowInstant) { - return retrieveServiceLocked(service, instanceName, false, 0, null, resolvedType, + boolean allowInstant, boolean inSharedIsolatedProcess) { + return retrieveServiceLocked(service, instanceName, false, INVALID_UID, null, resolvedType, callingPackage, callingPid, callingUid, userId, createIfNeeded, callingFromFg, - isBindExternal, allowInstant, null /* fgsDelegateOptions */); + isBindExternal, allowInstant, null /* fgsDelegateOptions */, + inSharedIsolatedProcess); } private ServiceLookupResult retrieveServiceLocked(Intent service, @@ -3708,7 +3732,8 @@ public final class ActiveServices { String sdkSandboxClientAppPackage, String resolvedType, String callingPackage, int callingPid, int callingUid, int userId, boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal, - boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions) { + boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions, + boolean inSharedIsolatedProcess) { if (isSdkSandboxService && instanceName == null) { throw new IllegalArgumentException("No instanceName provided for sdk sandbox process"); } @@ -3803,11 +3828,15 @@ public final class ActiveServices { final Intent.FilterComparison filter = new Intent.FilterComparison(service.cloneFilter()); final ServiceRestarter res = new ServiceRestarter(); + final String processName = getProcessNameForService(sInfo, cn, callingPackage, + null /* instanceName */, false /* isSdkSandbox */, + false /* inSharedIsolatedProcess */); r = new ServiceRecord(mAm, cn /* name */, cn /* instanceName */, sInfo.applicationInfo.packageName, sInfo.applicationInfo.uid, filter, sInfo, - callingFromFg, res, null /* sdkSandboxProcessName */, + callingFromFg, res, processName, INVALID_UID /* sdkSandboxClientAppUid */, - null /* sdkSandboxClientAppPackage */); + null /* sdkSandboxClientAppPackage */, + false /* inSharedIsolatedProcess */); res.setService(r); smap.mServicesByInstanceName.put(cn, r); smap.mServicesByIntent.put(filter, r); @@ -3901,6 +3930,16 @@ public final class ActiveServices { throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name + " is not an externalService"); } + if (inSharedIsolatedProcess) { + if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) { + throw new SecurityException("BIND_SHARED_ISOLATED_PROCESS failed, " + + className + " is not an isolatedProcess"); + } + if (instanceName == null) { + throw new IllegalArgumentException("instanceName must be provided for " + + "binding a service into a shared isolated process."); + } + } if (userId > 0) { if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo, sInfo.name, sInfo.flags) @@ -3934,12 +3973,12 @@ public final class ActiveServices { final Intent.FilterComparison filter = new Intent.FilterComparison(service.cloneFilter()); final ServiceRestarter res = new ServiceRestarter(); - String sdkSandboxProcessName = isSdkSandboxService ? instanceName - : null; + String processName = getProcessNameForService(sInfo, name, callingPackage, + instanceName, false, inSharedIsolatedProcess); r = new ServiceRecord(mAm, className, name, definingPackageName, definingUid, filter, sInfo, callingFromFg, res, - sdkSandboxProcessName, sdkSandboxClientAppUid, - sdkSandboxClientAppPackage); + processName, sdkSandboxClientAppUid, + sdkSandboxClientAppPackage, inSharedIsolatedProcess); res.setService(r); smap.mServicesByInstanceName.put(name, r); smap.mServicesByIntent.put(filter, r); @@ -4728,21 +4767,52 @@ public final class ActiveServices { } } } else { - // If this service runs in an isolated process, then each time - // we call startProcessLocked() we will get a new isolated - // process, starting another process if we are currently waiting - // for a previous process to come up. To deal with this, we store - // in the service any current isolated process it is running in or - // waiting to have come up. - app = r.isolationHostProc; - if (WebViewZygote.isMultiprocessEnabled() - && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) { - hostingRecord = HostingRecord.byWebviewZygote(r.instanceName, r.definingPackageName, - r.definingUid, r.serviceInfo.processName); - } - if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) { - hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName, - r.definingUid, r.serviceInfo.processName); + if (r.inSharedIsolatedProcess) { + app = mAm.mProcessList.getSharedIsolatedProcess(procName, r.appInfo.uid, + r.appInfo.packageName); + if (app != null) { + final IApplicationThread thread = app.getThread(); + final int pid = app.getPid(); + final UidRecord uidRecord = app.getUidRecord(); + if (thread != null) { + try { + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "realStartServiceLocked: " + r.shortInstanceName); + } + realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg, + enqueueOomAdj); + return null; + } catch (TransactionTooLargeException e) { + throw e; + } catch (RemoteException e) { + Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, + e); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + // If a dead object exception was thrown -- fall through to + // restart the application. + } + } + } else { + // If this service runs in an isolated process, then each time + // we call startProcessLocked() we will get a new isolated + // process, starting another process if we are currently waiting + // for a previous process to come up. To deal with this, we store + // in the service any current isolated process it is running in or + // waiting to have come up. + app = r.isolationHostProc; + if (WebViewZygote.isMultiprocessEnabled() + && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) { + hostingRecord = HostingRecord.byWebviewZygote(r.instanceName, + r.definingPackageName, + r.definingUid, r.serviceInfo.processName); + } + if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) { + hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName, + r.definingUid, r.serviceInfo.processName); + } } } @@ -7649,7 +7719,7 @@ public final class ActiveServices { null /* sdkSandboxClientAppPackage */, null /* resolvedType */, callingPackage, callingPid, callingUid, userId, true /* createIfNeeded */, false /* callingFromFg */, false /* isBindExternal */, false /* allowInstant */ , - options); + options, false /* inSharedIsolatedProcess */); if (res == null || res.record == null) { Slog.d(TAG, "startForegroundServiceDelegateLocked retrieveServiceLocked returns null"); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ccaf353607b15..1c307b627ba42 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13079,7 +13079,7 @@ public class ActivityManagerService extends IActivityManager.Stub String resolvedType, IServiceConnection connection, int flags, String instanceName, String callingPackage, int userId) throws TransactionTooLargeException { return bindServiceInstance(caller, token, service, resolvedType, connection, flags, - instanceName, false, 0, null, callingPackage, userId); + instanceName, false, INVALID_UID, null, callingPackage, userId); } private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service, diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 4d559b095c53c..12dc1f499ec4e 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -3004,6 +3004,16 @@ public final class ProcessList { } } + ProcessRecord getSharedIsolatedProcess(String processName, int uid, String packageName) { + for (int i = 0, size = mIsolatedProcesses.size(); i < size; i++) { + final ProcessRecord app = mIsolatedProcesses.valueAt(i); + if (app.info.uid == uid && app.info.packageName.equals(packageName) + && app.processName.equals(processName)) { + return app; + } + } + return null; + } @Nullable @GuardedBy("mService") List getIsolatedProcessesLocked(int uid) { diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 05726f4c39eb1..8c242743fe0bd 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.os.PowerExemptionManager.REASON_DENIED; +import static android.os.Process.INVALID_UID; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; @@ -118,6 +119,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN boolean fgWaiting; // is a timeout for going foreground already scheduled? boolean isNotAppComponentUsage; // is service binding not considered component/package usage? boolean isForeground; // is service currently in foreground mode? + boolean inSharedIsolatedProcess; // is the service in a shared isolated process int foregroundId; // Notification ID of last foreground req. Notification foregroundNoti; // Notification record of foreground state. long fgDisplayTime; // time at which the FGS notification should become visible @@ -723,6 +725,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN isSdkSandbox = false; sdkSandboxClientAppUid = 0; sdkSandboxClientAppPackage = null; + inSharedIsolatedProcess = false; } public static ServiceRecord newEmptyInstanceForTest(ActivityManagerService ams) { @@ -734,14 +737,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg, Runnable restarter) { this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg, - restarter, null, 0, null); + restarter, sInfo.processName, INVALID_UID, null, false); } ServiceRecord(ActivityManagerService ams, ComponentName name, ComponentName instanceName, String definingPackageName, int definingUid, Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg, - Runnable restarter, String sdkSandboxProcessName, int sdkSandboxClientAppUid, - String sdkSandboxClientAppPackage) { + Runnable restarter, String processName, int sdkSandboxClientAppUid, + String sdkSandboxClientAppPackage, boolean inSharedIsolatedProcess) { this.ams = ams; this.name = name; this.instanceName = instanceName; @@ -752,16 +755,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN serviceInfo = sInfo; appInfo = sInfo.applicationInfo; packageName = sInfo.applicationInfo.packageName; - this.isSdkSandbox = sdkSandboxProcessName != null; + this.isSdkSandbox = sdkSandboxClientAppUid != INVALID_UID; this.sdkSandboxClientAppUid = sdkSandboxClientAppUid; this.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage; - if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) { - processName = sInfo.processName + ":" + instanceName.getClassName(); - } else if (sdkSandboxProcessName != null) { - processName = sdkSandboxProcessName; - } else { - processName = sInfo.processName; - } + this.inSharedIsolatedProcess = inSharedIsolatedProcess; + this.processName = processName; permission = sInfo.permission; exported = sInfo.exported; this.restarter = restarter; 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 b3dc3eda362c3..e2c338ac8767c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import android.app.compat.CompatChanges; +import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.ServiceInfo; import android.os.SystemClock; @@ -40,6 +41,7 @@ import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -194,6 +196,47 @@ public class ActiveServicesTest { rd2 + btwn + extra, rd2 + (btwn + extra) * 2}); } + @Test + public void testGetProcessNameForService() throws Exception { + // Regular service + final ServiceInfo regularService = new ServiceInfo(); + regularService.processName = "com.foo"; + String processName = ActiveServices.getProcessNameForService(regularService, null, null, + null, false, false); + assertEquals("com.foo", processName); + + // Isolated service + final ServiceInfo isolatedService = new ServiceInfo(); + isolatedService.processName = "com.foo"; + isolatedService.flags = ServiceInfo.FLAG_ISOLATED_PROCESS; + final ComponentName component = new ComponentName("com.foo", "barService"); + processName = ActiveServices.getProcessNameForService(isolatedService, component, + null, null, false, false); + assertEquals("com.foo:barService", processName); + + // 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); + 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); + 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); + Assert.assertNotEquals(sharedIsolatedProcessName2, sharedIsolatedProcessName3); + } + private void prepareTestRescheduleServiceRestarts() { mService = mock(ActivityManagerService.class); mService.mConstants = mock(ActivityManagerConstants.class); From 4eae49c1558a3e889ddccd7800f3a7b7d10f6b9e Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 16 Dec 2022 16:18:24 +0100 Subject: [PATCH 2/2] Add allowedSharedIsolatedProcess attribute. Isolated services can use this attribute to indicate that they are ok being bound into a shared isolated process. The default is false. Bug: 243554393 Test: atest android.externalservice.cts.SharedIsolatedServiceTest Change-Id: Ia4e4e60e801ad4d914ab159892411127e1163d91 --- core/api/current.txt | 2 ++ core/java/android/content/pm/ServiceInfo.java | 14 ++++++++++++++ core/res/res/values/attrs_manifest.xml | 12 ++++++++++++ core/res/res/values/public-staging.xml | 1 + .../java/com/android/server/am/ActiveServices.java | 5 +++++ .../pm/pkg/component/ParsedServiceUtils.java | 2 ++ 6 files changed, 36 insertions(+) diff --git a/core/api/current.txt b/core/api/current.txt index a75dbcf00d145..38d7063382b22 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -363,6 +363,7 @@ package android { field public static final int allowGameFpsOverride = 16844378; // 0x101065a field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612 field public static final int allowParallelSyncs = 16843570; // 0x1010332 + field public static final int allowSharedIsolatedProcess; field public static final int allowSingleTap = 16843353; // 0x1010259 field public static final int allowTaskReparenting = 16843268; // 0x1010204 field public static final int allowUndo = 16843999; // 0x10104df @@ -12521,6 +12522,7 @@ package android.content.pm { method public void dump(android.util.Printer, String); method public int getForegroundServiceType(); field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int FLAG_ALLOW_SHARED_ISOLATED_PROCESS = 16; // 0x10 field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4 field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 6453ab0b89649..4ade8a8b87b65 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -78,6 +78,20 @@ public class ServiceInfo extends ComponentInfo */ public static final int FLAG_USE_APP_ZYGOTE = 0x0008; + /** + * Bit in {@link #flags}: If set, and this is an {@link android.R.attr#isolatedProcess} + * service, the service is allowed to be bound in a shared isolated process with other + * isolated services. Note that these other isolated services can also belong to other + * apps from different vendors. + * + * Shared isolated processes are created when using the + * {@link android.content.Context#BIND_SHARED_ISOLATED_PROCESS) during service binding. + * + * Note that when this flag is used, the {@link android.R.attr#process} attribute is + * ignored when the process is bound into a shared isolated process by a client. + */ + public static final int FLAG_ALLOW_SHARED_ISOLATED_PROCESS = 0x0010; + /** * Bit in {@link #flags} indicating if the service is visible to ephemeral applications. * @hide diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index d4644c59fa529..44f85dad95210 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2963,6 +2963,18 @@ Context.createAttributionContext() using the first attribution tag contained here. --> + +