Loading core/java/android/app/ActivityManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -278,7 +278,7 @@ public abstract class ActivityManagerInternal { String resolvedType, boolean fgRequired, String callingPackage, @UserIdInt int userId, boolean allowBackgroundActivityStarts) throws TransactionTooLargeException; public abstract void disconnectActivityFromServices(Object connectionHolder, Object conns); public abstract void disconnectActivityFromServices(Object connectionHolder); public abstract void cleanUpServices(@UserIdInt int userId, ComponentName component, Intent baseIntent); public abstract ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, @UserIdInt int userId); Loading services/core/java/com/android/server/am/ActivityManagerService.java +5 −8 Original line number Diff line number Diff line Loading @@ -18924,19 +18924,16 @@ public class ActivityManagerService extends IActivityManager.Stub } // The arguments here are untyped because the base ActivityManagerInternal class // doesn't have compile-time visiblity into ActivityServiceConnectionHolder or // doesn't have compile-time visibility into ActivityServiceConnectionHolder or // ConnectionRecord. @Override public void disconnectActivityFromServices(Object connectionHolder, Object conns) { public void disconnectActivityFromServices(Object connectionHolder) { // 'connectionHolder' is an untyped ActivityServiceConnectionsHolder // 'conns' is an untyped HashSet<ConnectionRecord> final ActivityServiceConnectionsHolder holder = (ActivityServiceConnectionsHolder) connectionHolder; final HashSet<ConnectionRecord> toDisconnect = (HashSet<ConnectionRecord>) conns; synchronized (ActivityManagerService.this) { for (ConnectionRecord cr : toDisconnect) { mServices.removeConnectionLocked(cr, null, holder); } holder.forEachConnection(cr -> mServices.removeConnectionLocked( (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */)); } } services/core/java/com/android/server/wm/ActivityRecord.java +2 −0 Original line number Diff line number Diff line Loading @@ -3037,6 +3037,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Throw away any services that have been bound by this activity. mServiceConnectionsHolder.disconnectActivityFromServices(); // This activity record is removing, make sure not to disconnect twice. mServiceConnectionsHolder = null; } @Override Loading services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +45 −14 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package com.android.server.wm; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import android.util.ArraySet; import android.util.Slog; import java.io.PrintWriter; import java.util.HashSet; import java.util.Iterator; import java.util.function.Consumer; /** Loading @@ -30,6 +33,8 @@ import java.util.function.Consumer; * 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. * <p> * Public methods are called in AM lock, otherwise in WM lock. */ public class ActivityServiceConnectionsHolder<T> { Loading @@ -44,7 +49,10 @@ public class ActivityServiceConnectionsHolder<T> { * 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; private ArraySet<T> mConnections; /** Whether all connections of {@link #mActivity} are being removed. */ private volatile boolean mIsDisconnecting; ActivityServiceConnectionsHolder(ActivityTaskManagerService service, ActivityRecord activity) { mService = service; Loading @@ -54,8 +62,16 @@ public class ActivityServiceConnectionsHolder<T> { /** Adds a connection record that the activity has bound to a specific service. */ public void addConnection(T c) { synchronized (mService.mGlobalLock) { if (mIsDisconnecting) { // This is unlikely to happen because the caller should create a new holder. if (DEBUG_CLEANUP) { Slog.e(TAG_ATM, "Skip adding connection " + c + " to a disconnecting holder of " + mActivity); } return; } if (mConnections == null) { mConnections = new HashSet<>(); mConnections = new ArraySet<>(); } mConnections.add(c); } Loading @@ -67,6 +83,9 @@ public class ActivityServiceConnectionsHolder<T> { if (mConnections == null) { return; } if (DEBUG_CLEANUP && mIsDisconnecting) { Slog.v(TAG_ATM, "Remove pending disconnecting " + c + " of " + mActivity); } mConnections.remove(c); } } Loading @@ -88,26 +107,33 @@ public class ActivityServiceConnectionsHolder<T> { if (mConnections == null || mConnections.isEmpty()) { return; } final Iterator<T> it = mConnections.iterator(); while (it.hasNext()) { T c = it.next(); consumer.accept(c); for (int i = mConnections.size() - 1; i >= 0; i--) { consumer.accept(mConnections.valueAt(i)); } } } /** Removes the connection between the activity and all services that were connected to it. */ /** * Removes the connection between the activity and all services that were connected to it. In * general, this method is used to clean up if the activity didn't unbind services before it * is destroyed. */ void disconnectActivityFromServices() { if (mConnections == null || mConnections.isEmpty()) { if (mConnections == null || mConnections.isEmpty() || mIsDisconnecting) { return; } // Capture and null out mConnections, to guarantee that we process // Mark as disconnecting, to guarantee that we process // disconnect of these specific connections exactly once even if // we're racing with rapid activity lifecycle churn and this // method is invoked more than once on this object. final Object disc = mConnections; mConnections = null; mService.mH.post(() -> mService.mAmInternal.disconnectActivityFromServices(this, disc)); // It is possible that {@link #removeConnection} is called while the disconnect-runnable is // still in the message queue, so keep the reference of {@link #mConnections} to make sure // the connection list is up-to-date. mIsDisconnecting = true; mService.mH.post(() -> { mService.mAmInternal.disconnectActivityFromServices(this); mIsDisconnecting = false; }); } public void dump(PrintWriter pw, String prefix) { Loading @@ -116,4 +142,9 @@ public class ActivityServiceConnectionsHolder<T> { } } /** Used by {@link ActivityRecord#dump}. */ @Override public String toString() { return String.valueOf(mConnections); } } Loading
core/java/android/app/ActivityManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -278,7 +278,7 @@ public abstract class ActivityManagerInternal { String resolvedType, boolean fgRequired, String callingPackage, @UserIdInt int userId, boolean allowBackgroundActivityStarts) throws TransactionTooLargeException; public abstract void disconnectActivityFromServices(Object connectionHolder, Object conns); public abstract void disconnectActivityFromServices(Object connectionHolder); public abstract void cleanUpServices(@UserIdInt int userId, ComponentName component, Intent baseIntent); public abstract ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, @UserIdInt int userId); Loading
services/core/java/com/android/server/am/ActivityManagerService.java +5 −8 Original line number Diff line number Diff line Loading @@ -18924,19 +18924,16 @@ public class ActivityManagerService extends IActivityManager.Stub } // The arguments here are untyped because the base ActivityManagerInternal class // doesn't have compile-time visiblity into ActivityServiceConnectionHolder or // doesn't have compile-time visibility into ActivityServiceConnectionHolder or // ConnectionRecord. @Override public void disconnectActivityFromServices(Object connectionHolder, Object conns) { public void disconnectActivityFromServices(Object connectionHolder) { // 'connectionHolder' is an untyped ActivityServiceConnectionsHolder // 'conns' is an untyped HashSet<ConnectionRecord> final ActivityServiceConnectionsHolder holder = (ActivityServiceConnectionsHolder) connectionHolder; final HashSet<ConnectionRecord> toDisconnect = (HashSet<ConnectionRecord>) conns; synchronized (ActivityManagerService.this) { for (ConnectionRecord cr : toDisconnect) { mServices.removeConnectionLocked(cr, null, holder); } holder.forEachConnection(cr -> mServices.removeConnectionLocked( (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */)); } }
services/core/java/com/android/server/wm/ActivityRecord.java +2 −0 Original line number Diff line number Diff line Loading @@ -3037,6 +3037,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Throw away any services that have been bound by this activity. mServiceConnectionsHolder.disconnectActivityFromServices(); // This activity record is removing, make sure not to disconnect twice. mServiceConnectionsHolder = null; } @Override Loading
services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +45 −14 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package com.android.server.wm; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import android.util.ArraySet; import android.util.Slog; import java.io.PrintWriter; import java.util.HashSet; import java.util.Iterator; import java.util.function.Consumer; /** Loading @@ -30,6 +33,8 @@ import java.util.function.Consumer; * 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. * <p> * Public methods are called in AM lock, otherwise in WM lock. */ public class ActivityServiceConnectionsHolder<T> { Loading @@ -44,7 +49,10 @@ public class ActivityServiceConnectionsHolder<T> { * 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; private ArraySet<T> mConnections; /** Whether all connections of {@link #mActivity} are being removed. */ private volatile boolean mIsDisconnecting; ActivityServiceConnectionsHolder(ActivityTaskManagerService service, ActivityRecord activity) { mService = service; Loading @@ -54,8 +62,16 @@ public class ActivityServiceConnectionsHolder<T> { /** Adds a connection record that the activity has bound to a specific service. */ public void addConnection(T c) { synchronized (mService.mGlobalLock) { if (mIsDisconnecting) { // This is unlikely to happen because the caller should create a new holder. if (DEBUG_CLEANUP) { Slog.e(TAG_ATM, "Skip adding connection " + c + " to a disconnecting holder of " + mActivity); } return; } if (mConnections == null) { mConnections = new HashSet<>(); mConnections = new ArraySet<>(); } mConnections.add(c); } Loading @@ -67,6 +83,9 @@ public class ActivityServiceConnectionsHolder<T> { if (mConnections == null) { return; } if (DEBUG_CLEANUP && mIsDisconnecting) { Slog.v(TAG_ATM, "Remove pending disconnecting " + c + " of " + mActivity); } mConnections.remove(c); } } Loading @@ -88,26 +107,33 @@ public class ActivityServiceConnectionsHolder<T> { if (mConnections == null || mConnections.isEmpty()) { return; } final Iterator<T> it = mConnections.iterator(); while (it.hasNext()) { T c = it.next(); consumer.accept(c); for (int i = mConnections.size() - 1; i >= 0; i--) { consumer.accept(mConnections.valueAt(i)); } } } /** Removes the connection between the activity and all services that were connected to it. */ /** * Removes the connection between the activity and all services that were connected to it. In * general, this method is used to clean up if the activity didn't unbind services before it * is destroyed. */ void disconnectActivityFromServices() { if (mConnections == null || mConnections.isEmpty()) { if (mConnections == null || mConnections.isEmpty() || mIsDisconnecting) { return; } // Capture and null out mConnections, to guarantee that we process // Mark as disconnecting, to guarantee that we process // disconnect of these specific connections exactly once even if // we're racing with rapid activity lifecycle churn and this // method is invoked more than once on this object. final Object disc = mConnections; mConnections = null; mService.mH.post(() -> mService.mAmInternal.disconnectActivityFromServices(this, disc)); // It is possible that {@link #removeConnection} is called while the disconnect-runnable is // still in the message queue, so keep the reference of {@link #mConnections} to make sure // the connection list is up-to-date. mIsDisconnecting = true; mService.mH.post(() -> { mService.mAmInternal.disconnectActivityFromServices(this); mIsDisconnecting = false; }); } public void dump(PrintWriter pw, String prefix) { Loading @@ -116,4 +142,9 @@ public class ActivityServiceConnectionsHolder<T> { } } /** Used by {@link ActivityRecord#dump}. */ @Override public String toString() { return String.valueOf(mConnections); } }