Merge "Add support for spawning multiple service processes"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a1919f7805
@@ -1997,7 +1997,8 @@ class ContextImpl extends Context {
|
||||
|
||||
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
|
||||
String instanceName, Handler handler, Executor executor, UserHandle user) {
|
||||
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
|
||||
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
|
||||
// ActivityManagerService.LocalService.startAndBindSupplementalProcessService
|
||||
IServiceConnection sd;
|
||||
if (conn == null) {
|
||||
throw new IllegalArgumentException("connection is null");
|
||||
@@ -2023,10 +2024,10 @@ class ContextImpl extends Context {
|
||||
flags |= BIND_WAIVE_PRIORITY;
|
||||
}
|
||||
service.prepareToLeaveProcess(this);
|
||||
int res = ActivityManager.getService().bindIsolatedService(
|
||||
mMainThread.getApplicationThread(), getActivityToken(), service,
|
||||
service.resolveTypeIfNeeded(getContentResolver()),
|
||||
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
|
||||
int res = ActivityManager.getService().bindServiceInstance(
|
||||
mMainThread.getApplicationThread(), getActivityToken(), service,
|
||||
service.resolveTypeIfNeeded(getContentResolver()),
|
||||
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
|
||||
if (res < 0) {
|
||||
throw new SecurityException(
|
||||
"Not allowed to bind to service " + service);
|
||||
|
||||
@@ -169,7 +169,7 @@ interface IActivityManager {
|
||||
int bindService(in IApplicationThread caller, in IBinder token, in Intent service,
|
||||
in String resolvedType, in IServiceConnection connection, int flags,
|
||||
in String callingPackage, int userId);
|
||||
int bindIsolatedService(in IApplicationThread caller, in IBinder token, in Intent service,
|
||||
int bindServiceInstance(in IApplicationThread caller, in IBinder token, in Intent service,
|
||||
in String resolvedType, in IServiceConnection connection, int flags,
|
||||
in String instanceName, in String callingPackage, int userId);
|
||||
void updateServiceGroup(in IServiceConnection connection, int group, int importance);
|
||||
|
||||
@@ -39,6 +39,7 @@ package com.android.server.am {
|
||||
|
||||
public interface ActivityManagerLocal {
|
||||
method public boolean canStartForegroundService(int, int, @NonNull String);
|
||||
method public boolean startAndBindSupplementalProcessService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int) throws android.os.TransactionTooLargeException;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2721,7 +2721,8 @@ public final class ActiveServices {
|
||||
|
||||
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
|
||||
String resolvedType, final IServiceConnection connection, int flags,
|
||||
String instanceName, String callingPackage, final int userId)
|
||||
String instanceName, boolean isSupplementalProcessService, String callingPackage,
|
||||
final int userId)
|
||||
throws TransactionTooLargeException {
|
||||
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
|
||||
+ " type=" + resolvedType + " conn=" + connection.asBinder()
|
||||
@@ -2805,10 +2806,9 @@ public final class ActiveServices {
|
||||
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
|
||||
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
|
||||
|
||||
ServiceLookupResult res =
|
||||
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
|
||||
callingPid, callingUid, userId, true,
|
||||
callerFg, isBindExternal, allowInstant);
|
||||
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
|
||||
isSupplementalProcessService, resolvedType, callingPackage, callingPid, callingUid,
|
||||
userId, true, callerFg, isBindExternal, allowInstant);
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -3228,6 +3228,20 @@ public final class ActiveServices {
|
||||
int callingPid, int callingUid, int userId,
|
||||
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
|
||||
boolean allowInstant) {
|
||||
return retrieveServiceLocked(service, instanceName, false, resolvedType, callingPackage,
|
||||
callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
|
||||
allowInstant);
|
||||
}
|
||||
|
||||
private ServiceLookupResult retrieveServiceLocked(Intent service,
|
||||
String instanceName, boolean isSupplementalProcessService, String resolvedType,
|
||||
String callingPackage, int callingPid, int callingUid, int userId,
|
||||
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
|
||||
boolean allowInstant) {
|
||||
if (isSupplementalProcessService && instanceName == null) {
|
||||
throw new IllegalArgumentException("No instanceName provided for supplemental process");
|
||||
}
|
||||
|
||||
ServiceRecord r = null;
|
||||
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
|
||||
+ " type=" + resolvedType + " callingUid=" + callingUid);
|
||||
@@ -3249,7 +3263,6 @@ public final class ActiveServices {
|
||||
if (instanceName == null) {
|
||||
comp = service.getComponent();
|
||||
} else {
|
||||
// This is for isolated services
|
||||
final ComponentName realComp = service.getComponent();
|
||||
if (realComp == null) {
|
||||
throw new IllegalArgumentException("Can't use custom instance name '" + instanceName
|
||||
@@ -3304,12 +3317,19 @@ public final class ActiveServices {
|
||||
return null;
|
||||
}
|
||||
if (instanceName != null
|
||||
&& (sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
|
||||
&& (sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0
|
||||
&& !isSupplementalProcessService) {
|
||||
throw new IllegalArgumentException("Can't use instance name '" + instanceName
|
||||
+ "' with non-isolated service '" + sInfo.name + "'");
|
||||
+ "' with non-isolated non-supplemental service '" + sInfo.name + "'");
|
||||
}
|
||||
ComponentName className = new ComponentName(
|
||||
sInfo.applicationInfo.packageName, sInfo.name);
|
||||
if (isSupplementalProcessService
|
||||
&& (sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
|
||||
throw new IllegalArgumentException("Service cannot be both supplemental and "
|
||||
+ "isolated");
|
||||
}
|
||||
|
||||
ComponentName className = new ComponentName(sInfo.applicationInfo.packageName,
|
||||
sInfo.name);
|
||||
ComponentName name = comp != null ? comp : className;
|
||||
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid,
|
||||
name.getPackageName(), sInfo.applicationInfo.uid)) {
|
||||
@@ -3392,7 +3412,8 @@ public final class ActiveServices {
|
||||
= new Intent.FilterComparison(service.cloneFilter());
|
||||
final ServiceRestarter res = new ServiceRestarter();
|
||||
r = new ServiceRecord(mAm, className, name, definingPackageName,
|
||||
definingUid, filter, sInfo, callingFromFg, res);
|
||||
definingUid, filter, sInfo, callingFromFg, res,
|
||||
isSupplementalProcessService);
|
||||
res.setService(r);
|
||||
smap.mServicesByInstanceName.put(name, r);
|
||||
smap.mServicesByIntent.put(filter, r);
|
||||
|
||||
@@ -18,6 +18,9 @@ package com.android.server.am;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.TransactionTooLargeException;
|
||||
|
||||
/**
|
||||
* Interface for in-process calls into
|
||||
@@ -58,4 +61,24 @@ public interface ActivityManagerLocal {
|
||||
* @hide
|
||||
*/
|
||||
void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs);
|
||||
|
||||
/**
|
||||
* Starts a supplemental process service and binds to it. You can through the arguments here
|
||||
* have the system bring up multiple concurrent processes hosting their own instance of that
|
||||
* service. The <var>userAppUid</var> you provide here identifies the different instances - each
|
||||
* unique uid is attributed to a supplemental process.
|
||||
*
|
||||
* @param service Identifies the supplemental process service to connect to. The Intent must
|
||||
* specify an explicit component name. This value cannot be null.
|
||||
* @param conn Receives information as the service is started and stopped.
|
||||
* This must be a valid ServiceConnection object; it must not be null.
|
||||
* @param userAppUid Uid of the app for which the supplemental process needs to be spawned.
|
||||
* @return {@code true} if the system is in the process of bringing up a
|
||||
* service that your client has permission to bind to; {@code false}
|
||||
* if the system couldn't find the service or if your client doesn't
|
||||
* have permission to bind to it.
|
||||
*/
|
||||
boolean startAndBindSupplementalProcessService(@NonNull Intent service,
|
||||
@NonNull ServiceConnection conn, int userAppUid) throws TransactionTooLargeException;
|
||||
|
||||
}
|
||||
|
||||
@@ -218,6 +218,7 @@ import android.content.IIntentSender;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.LocusId;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ActivityPresentationInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -12315,13 +12316,25 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
public int bindService(IApplicationThread caller, IBinder token, Intent service,
|
||||
String resolvedType, IServiceConnection connection, int flags,
|
||||
String callingPackage, int userId) throws TransactionTooLargeException {
|
||||
return bindIsolatedService(caller, token, service, resolvedType, connection, flags,
|
||||
return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
|
||||
null, callingPackage, userId);
|
||||
}
|
||||
|
||||
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
|
||||
/**
|
||||
* Binds to a service with a given instanceName, creating it if it does not already exist.
|
||||
* If the instanceName field is not supplied, binding to the service occurs as usual.
|
||||
*/
|
||||
public int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
|
||||
String resolvedType, IServiceConnection connection, int flags, String instanceName,
|
||||
String callingPackage, int userId) throws TransactionTooLargeException {
|
||||
return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
|
||||
instanceName, false, callingPackage, userId);
|
||||
}
|
||||
|
||||
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
|
||||
String resolvedType, IServiceConnection connection, int flags, String instanceName,
|
||||
boolean isSupplementalProcessService, String callingPackage, int userId)
|
||||
throws TransactionTooLargeException {
|
||||
enforceNotIsolatedCaller("bindService");
|
||||
|
||||
// Refuse possible leaked file descriptors
|
||||
@@ -12333,6 +12346,10 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
throw new IllegalArgumentException("callingPackage cannot be null");
|
||||
}
|
||||
|
||||
if (isSupplementalProcessService && instanceName == null) {
|
||||
throw new IllegalArgumentException("No instance name provided for isolated process");
|
||||
}
|
||||
|
||||
// Ensure that instanceName, which is caller provided, does not contain
|
||||
// unusual characters.
|
||||
if (instanceName != null) {
|
||||
@@ -12346,8 +12363,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
return mServices.bindServiceLocked(caller, token, service,
|
||||
resolvedType, connection, flags, instanceName, callingPackage, userId);
|
||||
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
|
||||
flags, instanceName, isSupplementalProcessService, callingPackage, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15879,6 +15896,34 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
processName, abiOverride, uid, crashHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startAndBindSupplementalProcessService(Intent service,
|
||||
ServiceConnection conn, int userAppUid) throws TransactionTooLargeException {
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("intent is null");
|
||||
}
|
||||
if (conn == null) {
|
||||
throw new IllegalArgumentException("connection is null");
|
||||
}
|
||||
if (service.getComponent() == null) {
|
||||
throw new IllegalArgumentException("service must specify explicit component");
|
||||
}
|
||||
if (!UserHandle.isApp(userAppUid)) {
|
||||
throw new IllegalArgumentException("uid is not within application range");
|
||||
}
|
||||
|
||||
Handler handler = mContext.getMainThreadHandler();
|
||||
int flags = Context.BIND_AUTO_CREATE;
|
||||
|
||||
final IServiceConnection sd = mContext.getServiceDispatcher(conn, handler, flags);
|
||||
service.prepareToLeaveProcess(mContext);
|
||||
return ActivityManagerService.this.bindServiceInstance(
|
||||
mContext.getIApplicationThread(), mContext.getActivityToken(), service,
|
||||
service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
|
||||
Integer.toString(userAppUid), /*isSupplementalProcessService*/ true,
|
||||
mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserRemoved(@UserIdInt int userId) {
|
||||
// Clean up any ActivityTaskManager state (by telling it the user is stopped)
|
||||
|
||||
@@ -570,6 +570,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
ComponentName instanceName, String definingPackageName, int definingUid,
|
||||
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
|
||||
Runnable restarter) {
|
||||
this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg,
|
||||
restarter, false);
|
||||
}
|
||||
|
||||
ServiceRecord(ActivityManagerService ams, ComponentName name,
|
||||
ComponentName instanceName, String definingPackageName, int definingUid,
|
||||
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
|
||||
Runnable restarter, boolean isSupplementalProcessService) {
|
||||
this.ams = ams;
|
||||
this.name = name;
|
||||
this.instanceName = instanceName;
|
||||
@@ -580,7 +588,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
serviceInfo = sInfo;
|
||||
appInfo = sInfo.applicationInfo;
|
||||
packageName = sInfo.applicationInfo.packageName;
|
||||
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
|
||||
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
|
||||
|| isSupplementalProcessService) {
|
||||
processName = sInfo.processName + ":" + instanceName.getClassName();
|
||||
} else {
|
||||
processName = sInfo.processName;
|
||||
|
||||
Reference in New Issue
Block a user