summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martijn Coenen <maco@google.com> 2022-12-12 11:11:27 +0100
committer Martijn Coenen <maco@google.com> 2023-01-11 20:22:04 +0000
commit78c258ce98475d85a37f68a104f7e3c97ede3245 (patch)
treec957182bf8bc00f5bb44b63873e32f82e9646360
parentd5c4fe4bee162cfcd410528170bb0bf16c6849e1 (diff)
Support attributing a service binding to a different process.
By default, the process that initiates a service binding is the process that will be used for attribution and computing the OOM priority of the process hosting the service. In cases like the SDK sandbox, the system binds to a service on behalf of another application, and we'd like to OOM priority to be a function of the priority of that other application. Since we need some way to lookup the corresponding ProcessRecord, pass in the process name of the SDK sandbox, and store the corresponding ProcessRecord in AppBindRecord. This will allow the OomAdjuster to determine its policy based on the attributed ProcessRecord in AppBindRecord. Bug: 253399592 API-Coverage-Bug: 265180182 Test: SdkSandbox TEST_MAPPING Change-Id: Iab4555975aec52bbc3c42ba339b01c1ffbff36d4
-rw-r--r--services/api/current.txt3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerLocal.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java42
-rw-r--r--services/core/java/com/android/server/am/AppBindRecord.java7
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java2
7 files changed, 68 insertions, 14 deletions
diff --git a/services/api/current.txt b/services/api/current.txt
index b173726411f6..25a9b10bd887 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,7 +38,8 @@ package com.android.server {
package com.android.server.am {
public interface ActivityManagerLocal {
- method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
+ method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.IBinder, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
+ method @Deprecated public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
method public boolean canStartForegroundService(int, int, @NonNull String);
method public void killSdkSandboxClientAppProcess(@NonNull android.os.IBinder);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bcea40e5a9db..ece72543bbc8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3181,7 +3181,8 @@ public final class ActiveServices {
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String sdkSandboxClientAppPackage, String callingPackage, final int userId)
+ String sdkSandboxClientAppPackage, IApplicationThread sdkSandboxClientApplicationThread,
+ String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -3271,6 +3272,10 @@ public final class ActiveServices {
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
final boolean inSharedIsolatedProcess = (flags & Context.BIND_SHARED_ISOLATED_PROCESS) != 0;
+ ProcessRecord attributedApp = null;
+ if (sdkSandboxClientAppUid > 0) {
+ attributedApp = mAm.getRecordForAppLOSP(sdkSandboxClientApplicationThread);
+ }
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
@@ -3283,7 +3288,7 @@ public final class ActiveServices {
return -1;
}
ServiceRecord s = res.record;
- final AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
+ final AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp, attributedApp);
final ProcessServiceRecord clientPsr = b.client.mServices;
if (clientPsr.numberOfConnections() >= mAm.mConstants.mMaxServiceConnectionsPerProcess) {
Slog.w(TAG, "bindService exceeded max service connection number per process, "
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index 5175a31c16b5..fa0972a6862a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -76,6 +76,8 @@ public interface ActivityManagerLocal {
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
* @param clientAppUid Uid of the app for which the sdk sandbox process needs to be spawned.
+ * @param clientApplicationThread ApplicationThread object of the app for which the sdk sandboox
+ * is spawned.
* @param clientAppPackage Package of the app for which the sdk sandbox process needs to
* be spawned. This package must belong to the clientAppUid.
* @param processName Unique identifier for the service instance. Each unique name here will
@@ -91,6 +93,19 @@ public interface ActivityManagerLocal {
*/
@SuppressLint("RethrowRemoteException")
boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
+ int clientAppUid, @NonNull IBinder clientApplicationThread,
+ @NonNull String clientAppPackage, @NonNull String processName,
+ @Context.BindServiceFlags int flags)
+ throws RemoteException;
+
+ /**
+ * @deprecated Please use
+ * {@link #bindSdkSandboxService(Intent, ServiceConnection, int, IBinder, String, String, int)}
+ *
+ * This API can't be deleted yet because it can be used by early AdService module versions.
+ */
+ @SuppressLint("RethrowRemoteException")
+ boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
int clientAppUid, @NonNull String clientAppPackage, @NonNull String processName,
@Context.BindServiceFlags int flags)
throws RemoteException;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 28aed2e2ad4d..260d7a7e7976 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13090,13 +13090,15 @@ 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, INVALID_UID, null, callingPackage, userId);
+ instanceName, false, INVALID_UID, null, null, callingPackage, userId);
}
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String sdkSandboxClientAppPackage, String callingPackage, int userId)
+ String sdkSandboxClientAppPackage,
+ IApplicationThread sdkSandboxClientApplicationThread,
+ String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
@@ -13135,7 +13137,8 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
- sdkSandboxClientAppPackage, callingPackage, userId);
+ sdkSandboxClientAppPackage, sdkSandboxClientApplicationThread,
+ callingPackage, userId);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -16922,7 +16925,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
- int clientAppUid, String clientAppPackage, String processName, int flags)
+ int clientAppUid, IBinder clientApplicationThread, String clientAppPackage,
+ String processName, int flags)
throws RemoteException {
if (service == null) {
throw new IllegalArgumentException("intent is null");
@@ -16947,14 +16951,40 @@ public class ActivityManagerService extends IActivityManager.Stub
}
Handler handler = mContext.getMainThreadHandler();
-
+ IApplicationThread clientApplicationThreadVerified = null;
+ if (clientApplicationThread != null) {
+ // Make sure this is a valid application process
+ synchronized (this) {
+ final ProcessRecord rec = getRecordForAppLOSP(clientApplicationThread);
+ if (rec == null) {
+ // This could happen if the calling process has disappeared; no need for the
+ // sandbox to be even started in this case.
+ Slog.i(TAG, "clientApplicationThread process not found.");
+ return false;
+ }
+ if (rec.info.uid != clientAppUid) {
+ throw new IllegalArgumentException("clientApplicationThread does not match "
+ + " client uid");
+ }
+ clientApplicationThreadVerified = rec.getThread();
+ }
+ }
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,
processName, /*isSdkSandboxService*/ true, clientAppUid, clientAppPackage,
- mContext.getOpPackageName(), UserHandle.getUserId(clientAppUid)) != 0;
+ clientApplicationThreadVerified, mContext.getOpPackageName(),
+ UserHandle.getUserId(clientAppUid)) != 0;
+ }
+
+ @Override
+ public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
+ int clientAppUid, String clientAppPackage, String processName, int flags)
+ throws RemoteException {
+ return bindSdkSandboxService(service, conn, clientAppUid,
+ null /* clientApplicationThread */, clientAppPackage, processName, flags);
}
@Override
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 28756a4e4191..f7b3d3ac7060 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -28,13 +28,15 @@ final class AppBindRecord {
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
final ProcessRecord client; // Who has started/bound the service.
-
+ final ProcessRecord attributedClient; // The binding was done by the system on behalf
+ // of 'attributedClient'
final ArraySet<ConnectionRecord> connections = new ArraySet<>();
// All ConnectionRecord for this client.
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "service=" + service);
pw.println(prefix + "client=" + client);
+ pw.println(prefix + "attributedClient=" + attributedClient);
dumpInIntentBind(pw, prefix);
}
@@ -50,10 +52,11 @@ final class AppBindRecord {
}
AppBindRecord(ServiceRecord _service, IntentBindRecord _intent,
- ProcessRecord _client) {
+ ProcessRecord _client, ProcessRecord _attributedClient) {
service = _service;
intent = _intent;
client = _client;
+ attributedClient = _attributedClient;
}
public String toString() {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8c242743fe0b..def51b0258f1 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1063,7 +1063,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
public AppBindRecord retrieveAppBindingLocked(Intent intent,
- ProcessRecord app) {
+ ProcessRecord app, ProcessRecord attributedApp) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
@@ -1074,7 +1074,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
if (a != null) {
return a;
}
- a = new AppBindRecord(this, i, app);
+ a = new AppBindRecord(this, i, app, attributedApp);
i.apps.put(app, a);
return a;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 9234431accb9..c40017a18af0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -2452,7 +2452,7 @@ public class MockingOomAdjusterTests {
if (record == null) {
record = makeServiceRecord(service);
}
- AppBindRecord binding = new AppBindRecord(record, null, client);
+ AppBindRecord binding = new AppBindRecord(record, null, client, null);
ConnectionRecord cr = spy(new ConnectionRecord(binding,
mock(ActivityServiceConnectionsHolder.class),
mock(IServiceConnection.class), bindFlags,