Introduced ActivityServiceConnectionsHolder (18/n)
Class for managing the connections to services on the AM side that
activities on the WM side bind with for things like oom score adjustment.
Bug: 80414790
Test: Existing tests pass.
Change-Id: I4ab5140dd7f888f448ce19107bda92c01066a3dc
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 461d39d..8e64b50 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1466,9 +1466,9 @@
+ ") when binding service " + service);
}
- ActivityRecord activity = null;
+ ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
if (token != null) {
- activity = ActivityRecord.isInStackLocked(token);
+ activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
@@ -1644,10 +1644,7 @@
clist.add(c);
b.connections.add(c);
if (activity != null) {
- if (activity.connections == null) {
- activity.connections = new HashSet<ConnectionRecord>();
- }
- activity.connections.add(c);
+ activity.addConnection(c);
}
b.client.connections.add(c);
c.startAssociationIfNeeded();
@@ -2861,8 +2858,8 @@
smap.ensureNotStartingBackgroundLocked(r);
}
- void removeConnectionLocked(
- ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
+ void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
+ ActivityServiceConnectionsHolder skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
@@ -2876,9 +2873,7 @@
b.connections.remove(c);
c.stopAssociation();
if (c.activity != null && c.activity != skipAct) {
- if (c.activity.connections != null) {
- c.activity.connections.remove(c);
- }
+ c.activity.removeConnection(c);
}
if (b.client != skipApp) {
b.client.connections.remove(c);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f49c50a..5f0a89b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10609,9 +10609,13 @@
currApp.importanceReasonImportance =
ActivityManager.RunningAppProcessInfo.procStateToImportance(
app.adjSourceProcState);
- } else if (app.adjSource instanceof ActivityRecord) {
- ActivityRecord r = (ActivityRecord)app.adjSource;
- if (r.app != null) currApp.importanceReasonPid = r.app.getPid();
+ } else if (app.adjSource instanceof ActivityServiceConnectionsHolder) {
+ ActivityServiceConnectionsHolder r =
+ (ActivityServiceConnectionsHolder) app.adjSource;
+ final int pid = r.getActivityPid();
+ if (pid != -1) {
+ currApp.importanceReasonPid = pid;
+ }
}
if (app.adjTarget instanceof ComponentName) {
currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
@@ -17786,10 +17790,10 @@
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
app.treatLikeActivity = true;
}
- final ActivityRecord a = cr.activity;
+ final ActivityServiceConnectionsHolder a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && (a.visible
- || a.isState(ActivityState.RESUMED, ActivityState.PAUSING))) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
+ && a.isActivityVisible()) {
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
@@ -20904,6 +20908,16 @@
return res;
}
}
+
+ @Override
+ public void disconnectActivityFromServices(Object connectionHolder) {
+ synchronized(ActivityManagerService.this) {
+ final ActivityServiceConnectionsHolder c =
+ (ActivityServiceConnectionsHolder) connectionHolder;
+ c.forEachConnection(cr -> mServices.removeConnectionLocked(
+ (ConnectionRecord) cr, null, c));
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 77cfb12..5e1d9ac 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -288,7 +288,7 @@
ActivityOptions pendingOptions; // most recently given options
ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
- HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
+ ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
UriPermissionOwner uriPermissions; // current special URI access perms.
WindowProcessController app; // if non-null, hosting application
private ActivityState mState; // current state we are in
@@ -563,8 +563,8 @@
pw.print(" configChangeFlags=");
pw.println(Integer.toHexString(configChangeFlags));
}
- if (connections != null) {
- pw.print(prefix); pw.print("connections="); pw.println(connections);
+ if (mServiceConnectionsHolder != null) {
+ pw.print(prefix); pw.print("connections="); pw.println(mServiceConnectionsHolder);
}
if (info != null) {
pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
diff --git a/services/core/java/com/android/server/am/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/am/ActivityServiceConnectionsHolder.java
new file mode 100644
index 0000000..b1ced29
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityServiceConnectionsHolder.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+/**
+ * Class for tracking the connections to services on the AM side that activities on the
+ * WM side (in the future) bind with for things like oom score adjustment. Would normally be one
+ * instance of this per activity for tracking all services connected to that activity. AM will
+ * sometimes query this to bump the OOM score for the processes with services connected to visible
+ * activities.
+ */
+public class ActivityServiceConnectionsHolder<T> {
+
+ private final ActivityTaskManagerService mService;
+
+ /** The activity the owns this service connection object. */
+ private final ActivityRecord mActivity;
+
+ /**
+ * The service connection object bounded with the owning activity. They represent
+ * ConnectionRecord on the AM side, however we don't need to know their object representation
+ * on the WM side since we don't perform operations on the object. Mainly here for communication
+ * and booking with the AM side.
+ */
+ private HashSet<T> mConnections;
+
+ ActivityServiceConnectionsHolder(ActivityTaskManagerService service, ActivityRecord activity) {
+ mService = service;
+ mActivity = activity;
+ }
+
+ /** Adds a connection record that the activity has bound to a specific service. */
+ public void addConnection(T c) {
+ synchronized (mService.mGlobalLock) {
+ if (mConnections == null) {
+ mConnections = new HashSet<>();
+ }
+ mConnections.add(c);
+ }
+ }
+
+ /** Removed a connection record between the activity and a specific service. */
+ public void removeConnection(T c) {
+ synchronized (mService.mGlobalLock) {
+ if (mConnections == null) {
+ return;
+ }
+ mConnections.remove(c);
+ }
+ }
+
+ public boolean isActivityVisible() {
+ synchronized (mService.mGlobalLock) {
+ return mActivity.visible || mActivity.isState(RESUMED, PAUSING);
+ }
+ }
+
+ public int getActivityPid() {
+ synchronized (mService.mGlobalLock) {
+ return mActivity.hasProcess() ? mActivity.app.getPid() : -1;
+ }
+ }
+
+ public void forEachConnection(Consumer<T> consumer) {
+ synchronized (mService.mGlobalLock) {
+ if (mConnections == null || mConnections.isEmpty()) {
+ return;
+ }
+ final Iterator<T> it = mConnections.iterator();
+ while (it.hasNext()) {
+ T c = it.next();
+ consumer.accept(c);
+ }
+ }
+ }
+
+ /** Removes the connection between the activity and all services that were connected to it. */
+ void disconnectActivityFromServices() {
+ if (mConnections == null || mConnections.isEmpty()) {
+ return;
+ }
+ mService.mH.post(() -> mService.mAmInternal.disconnectActivityFromServices(this));
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mService.mGlobalLock) {
+ pw.println(prefix + "activity=" + mActivity);
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9f59bd8..7de5824 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4237,15 +4237,11 @@
* Perform clean-up of service connections in an activity record.
*/
private void cleanUpActivityServicesLocked(ActivityRecord r) {
- // Throw away any services that have been bound by this activity.
- if (r.connections != null) {
- Iterator<ConnectionRecord> it = r.connections.iterator();
- while (it.hasNext()) {
- ConnectionRecord c = it.next();
- mService.mAm.mServices.removeConnectionLocked(c, null, r);
- }
- r.connections = null;
+ if (r.mServiceConnectionsHolder == null) {
+ return;
}
+ // Throw away any services that have been bound by this activity.
+ r.mServiceConnectionsHolder.disconnectActivityFromServices();
}
final void scheduleDestroyActivities(WindowProcessController owner, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 36261b5..b4f062d 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -5781,5 +5781,21 @@
resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
}
}
+
+ @Override
+ public ActivityServiceConnectionsHolder getServiceConnectionsHolder(IBinder token) {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return null;
+ }
+ if (r.mServiceConnectionsHolder == null) {
+ r.mServiceConnectionsHolder = new ActivityServiceConnectionsHolder(
+ ActivityTaskManagerService.this, r);
+ }
+
+ return r.mServiceConnectionsHolder;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index fa8e6c4..1242ed6 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -35,7 +35,7 @@
*/
final class ConnectionRecord {
final AppBindRecord binding; // The application/service binding.
- final ActivityRecord activity; // If non-null, the owning activity.
+ final ActivityServiceConnectionsHolder<ConnectionRecord> activity; // If non-null, the owning activity.
final IServiceConnection conn; // The client connection.
final int flags; // Binding options.
final int clientLabel; // String resource labeling this client.
@@ -85,13 +85,14 @@
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "binding=" + binding);
if (activity != null) {
- pw.println(prefix + "activity=" + activity);
+ activity.dump(pw, prefix);
}
pw.println(prefix + "conn=" + conn.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
}
- ConnectionRecord(AppBindRecord _binding, ActivityRecord _activity,
+ ConnectionRecord(AppBindRecord _binding,
+ ActivityServiceConnectionsHolder<ConnectionRecord> _activity,
IServiceConnection _conn, int _flags,
int _clientLabel, PendingIntent _clientIntent,
int _clientUid, String _clientProcessName) {