Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -486,13 +486,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Whether normal application switches are allowed; a call to {@link #stopAppSwitches() * disables this. */ private boolean mAppSwitchesAllowed = true; private volatile boolean mAppSwitchesAllowed = true; /** * Last stop app switches time, apps finished before this time cannot start background activity * even if they are in grace period. */ private long mLastStopAppSwitchesTime; private volatile long mLastStopAppSwitchesTime; IActivityController mController = null; boolean mControllerIsAMonkey = false; Loading Loading @@ -698,6 +698,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { int OOM_ADJUSTMENT = 1; int LRU_UPDATE = 2; int PROCESS_CHANGE = 3; int START_SERVICE = 4; int caller() default NONE; } Loading Loading @@ -4744,6 +4745,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } /** A uid is considered to be foreground if it has a visible non-toast window. */ @HotPath(caller = HotPath.START_SERVICE) boolean hasActiveVisibleWindow(int uid) { if (mVisibleActivityProcessTracker.hasVisibleActivity(uid)) { return true; Loading services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +4 −2 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ public interface BackgroundActivityStartCallback { * Note that if the start was allowed due to a mechanism other than tokens (eg. permission), * this won't be called. * * This will be called holding the WM lock, don't do anything costly here. * This will be called holding the WM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); Loading @@ -40,7 +41,8 @@ public interface BackgroundActivityStartCallback { * #ACTION_CLOSE_SYSTEM_DIALOGS}, presumably to start activities, based on the originating * tokens {@code tokens} currently associated with potential activity starts. * * This will be called holding the AM and WM lock, don't do anything costly here. * This will be called holding the AM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid); } services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java 0 → 100644 +264 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.wm; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.SystemClock; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.Arrays; import java.util.function.IntPredicate; /** * A per-process controller to decide whether the process can start activity or foreground service * (especially from background). All methods of this class must be thread safe. The caller does not * need to hold WM lock, e.g. lock contention of WM lock shouldn't happen when starting service. */ class BackgroundLaunchProcessController { private static final String TAG = TAG_WITH_CLASS_NAME ? "BackgroundLaunchProcessController" : TAG_ATM; /** It is {@link ActivityTaskManagerService#hasActiveVisibleWindow(int)}. */ private final IntPredicate mUidHasActiveVisibleWindowPredicate; private final @Nullable BackgroundActivityStartCallback mBackgroundActivityStartCallback; /** * A set of tokens that currently contribute to this process being temporarily allowed * to start activities even if it's not in the foreground. The values of this map are optional * (can be null) and are used to trace back the grant to the notification token mechanism. */ @GuardedBy("this") private @Nullable ArrayMap<Binder, IBinder> mBackgroundActivityStartTokens; /** Set of UIDs of clients currently bound to this process. */ @GuardedBy("this") private @Nullable IntArray mBoundClientUids; BackgroundLaunchProcessController(@NonNull IntPredicate uidHasActiveVisibleWindowPredicate, @Nullable BackgroundActivityStartCallback callback) { mUidHasActiveVisibleWindowPredicate = uidHasActiveVisibleWindowPredicate; mBackgroundActivityStartCallback = callback; } boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, boolean appSwitchAllowed, boolean isCheckingForFgsStart, boolean hasVisibleActivities, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastActivityFinishTime) { // If app switching is not allowed, we ignore all the start activity grace period // exception so apps cannot start itself in onPause() after pressing home button. if (appSwitchAllowed) { // Allow if any activity in the caller has either started or finished very recently, and // it must be started or finished after last stop app switches time. final long now = SystemClock.uptimeMillis(); if (now - lastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS || now - lastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { // If activity is started and finished before stop app switch time, we should not // let app to be able to start background activity even it's in grace period. if (lastActivityLaunchTime > lastStopAppSwitchesTime || lastActivityFinishTime > lastStopAppSwitchesTime) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); } return true; } if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period but also within stop app switch window"); } } } // Allow if the proc is instrumenting with background activity starts privs. if (hasBackgroundActivityStartPrivileges) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process instrumenting with background " + "activity starts privileges"); } return true; } // Allow if the caller has an activity in any foreground task. if (appSwitchAllowed && hasVisibleActivities) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process has activity in foreground task"); } return true; } // Allow if the caller is bound by a UID that's currently foreground. if (isBoundByForegroundUid()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process bound by foreground uid"); } return true; } // Allow if the flag was explicitly set. if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process allowed by token"); } return true; } return false; } /** * If there are no tokens, we don't allow *by token*. If there are tokens and * isCheckingForFgsStart is false, we ask the callback if the start is allowed for these tokens, * otherwise if there is no callback we allow. */ private boolean isBackgroundStartAllowedByToken(int uid, String packageName, boolean isCheckingForFgsStart) { synchronized (this) { if (mBackgroundActivityStartTokens == null || mBackgroundActivityStartTokens.isEmpty()) { return false; } if (isCheckingForFgsStart) { // BG-FGS-start only checks if there is a token. return true; } if (mBackgroundActivityStartCallback == null) { // We have tokens but no callback to decide => allow. return true; } // The callback will decide. return mBackgroundActivityStartCallback.isActivityStartAllowed( mBackgroundActivityStartTokens.values(), uid, packageName); } } private boolean isBoundByForegroundUid() { synchronized (this) { if (mBoundClientUids != null) { for (int i = mBoundClientUids.size() - 1; i >= 0; i--) { if (mUidHasActiveVisibleWindowPredicate.test(mBoundClientUids.get(i))) { return true; } } } } return false; } void setBoundClientUids(ArraySet<Integer> boundClientUids) { synchronized (this) { if (boundClientUids == null || boundClientUids.isEmpty()) { mBoundClientUids = null; return; } if (mBoundClientUids == null) { mBoundClientUids = new IntArray(); } else { mBoundClientUids.clear(); } for (int i = boundClientUids.size() - 1; i >= 0; i--) { mBoundClientUids.add(boundClientUids.valueAt(i)); } } } /** * Allows background activity starts using token {@code entity}. Optionally, you can provide * {@code originatingToken} if you have one such originating token, this is useful for tracing * back the grant in the case of the notification token. * * If {@code entity} is already added, this method will update its {@code originatingToken}. */ void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { synchronized (this) { if (mBackgroundActivityStartTokens == null) { mBackgroundActivityStartTokens = new ArrayMap<>(); } mBackgroundActivityStartTokens.put(entity, originatingToken); } } /** * Removes token {@code entity} that allowed background activity starts added via {@link * #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}. */ void removeAllowBackgroundActivityStartsToken(Binder entity) { synchronized (this) { if (mBackgroundActivityStartTokens != null) { mBackgroundActivityStartTokens.remove(entity); } } } /** * Returns whether this process is allowed to close system dialogs via a background activity * start token that allows the close system dialogs operation (eg. notification). */ boolean canCloseSystemDialogsByToken(int uid) { if (mBackgroundActivityStartCallback == null) { return false; } synchronized (this) { if (mBackgroundActivityStartTokens == null || mBackgroundActivityStartTokens.isEmpty()) { return false; } return mBackgroundActivityStartCallback.canCloseSystemDialogs( mBackgroundActivityStartTokens.values(), uid); } } void dump(PrintWriter pw, String prefix) { synchronized (this) { if (mBackgroundActivityStartTokens != null && !mBackgroundActivityStartTokens.isEmpty()) { pw.print(prefix); pw.println("Background activity start tokens (token: originating token):"); for (int i = mBackgroundActivityStartTokens.size() - 1; i >= 0; i--) { pw.print(prefix); pw.print(" - "); pw.print(mBackgroundActivityStartTokens.keyAt(i)); pw.print(": "); pw.println(mBackgroundActivityStartTokens.valueAt(i)); } } if (mBoundClientUids != null && mBoundClientUids.size() > 0) { pw.print(prefix); pw.print("BoundClientUids:"); pw.println(Arrays.toString(mBoundClientUids.toArray())); } } } } services/core/java/com/android/server/wm/WindowProcessController.java +28 −165 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -486,13 +486,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Whether normal application switches are allowed; a call to {@link #stopAppSwitches() * disables this. */ private boolean mAppSwitchesAllowed = true; private volatile boolean mAppSwitchesAllowed = true; /** * Last stop app switches time, apps finished before this time cannot start background activity * even if they are in grace period. */ private long mLastStopAppSwitchesTime; private volatile long mLastStopAppSwitchesTime; IActivityController mController = null; boolean mControllerIsAMonkey = false; Loading Loading @@ -698,6 +698,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { int OOM_ADJUSTMENT = 1; int LRU_UPDATE = 2; int PROCESS_CHANGE = 3; int START_SERVICE = 4; int caller() default NONE; } Loading Loading @@ -4744,6 +4745,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } /** A uid is considered to be foreground if it has a visible non-toast window. */ @HotPath(caller = HotPath.START_SERVICE) boolean hasActiveVisibleWindow(int uid) { if (mVisibleActivityProcessTracker.hasVisibleActivity(uid)) { return true; Loading
services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java +4 −2 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ public interface BackgroundActivityStartCallback { * Note that if the start was allowed due to a mechanism other than tokens (eg. permission), * this won't be called. * * This will be called holding the WM lock, don't do anything costly here. * This will be called holding the WM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName); Loading @@ -40,7 +41,8 @@ public interface BackgroundActivityStartCallback { * #ACTION_CLOSE_SYSTEM_DIALOGS}, presumably to start activities, based on the originating * tokens {@code tokens} currently associated with potential activity starts. * * This will be called holding the AM and WM lock, don't do anything costly here. * This will be called holding the AM and local lock, don't do anything costly or invoke AM/WM * methods here directly. */ boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid); }
services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java 0 → 100644 +264 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.wm; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.SystemClock; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.Arrays; import java.util.function.IntPredicate; /** * A per-process controller to decide whether the process can start activity or foreground service * (especially from background). All methods of this class must be thread safe. The caller does not * need to hold WM lock, e.g. lock contention of WM lock shouldn't happen when starting service. */ class BackgroundLaunchProcessController { private static final String TAG = TAG_WITH_CLASS_NAME ? "BackgroundLaunchProcessController" : TAG_ATM; /** It is {@link ActivityTaskManagerService#hasActiveVisibleWindow(int)}. */ private final IntPredicate mUidHasActiveVisibleWindowPredicate; private final @Nullable BackgroundActivityStartCallback mBackgroundActivityStartCallback; /** * A set of tokens that currently contribute to this process being temporarily allowed * to start activities even if it's not in the foreground. The values of this map are optional * (can be null) and are used to trace back the grant to the notification token mechanism. */ @GuardedBy("this") private @Nullable ArrayMap<Binder, IBinder> mBackgroundActivityStartTokens; /** Set of UIDs of clients currently bound to this process. */ @GuardedBy("this") private @Nullable IntArray mBoundClientUids; BackgroundLaunchProcessController(@NonNull IntPredicate uidHasActiveVisibleWindowPredicate, @Nullable BackgroundActivityStartCallback callback) { mUidHasActiveVisibleWindowPredicate = uidHasActiveVisibleWindowPredicate; mBackgroundActivityStartCallback = callback; } boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, boolean appSwitchAllowed, boolean isCheckingForFgsStart, boolean hasVisibleActivities, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastActivityFinishTime) { // If app switching is not allowed, we ignore all the start activity grace period // exception so apps cannot start itself in onPause() after pressing home button. if (appSwitchAllowed) { // Allow if any activity in the caller has either started or finished very recently, and // it must be started or finished after last stop app switches time. final long now = SystemClock.uptimeMillis(); if (now - lastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS || now - lastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { // If activity is started and finished before stop app switch time, we should not // let app to be able to start background activity even it's in grace period. if (lastActivityLaunchTime > lastStopAppSwitchesTime || lastActivityFinishTime > lastStopAppSwitchesTime) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); } return true; } if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period but also within stop app switch window"); } } } // Allow if the proc is instrumenting with background activity starts privs. if (hasBackgroundActivityStartPrivileges) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process instrumenting with background " + "activity starts privileges"); } return true; } // Allow if the caller has an activity in any foreground task. if (appSwitchAllowed && hasVisibleActivities) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process has activity in foreground task"); } return true; } // Allow if the caller is bound by a UID that's currently foreground. if (isBoundByForegroundUid()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process bound by foreground uid"); } return true; } // Allow if the flag was explicitly set. if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process allowed by token"); } return true; } return false; } /** * If there are no tokens, we don't allow *by token*. If there are tokens and * isCheckingForFgsStart is false, we ask the callback if the start is allowed for these tokens, * otherwise if there is no callback we allow. */ private boolean isBackgroundStartAllowedByToken(int uid, String packageName, boolean isCheckingForFgsStart) { synchronized (this) { if (mBackgroundActivityStartTokens == null || mBackgroundActivityStartTokens.isEmpty()) { return false; } if (isCheckingForFgsStart) { // BG-FGS-start only checks if there is a token. return true; } if (mBackgroundActivityStartCallback == null) { // We have tokens but no callback to decide => allow. return true; } // The callback will decide. return mBackgroundActivityStartCallback.isActivityStartAllowed( mBackgroundActivityStartTokens.values(), uid, packageName); } } private boolean isBoundByForegroundUid() { synchronized (this) { if (mBoundClientUids != null) { for (int i = mBoundClientUids.size() - 1; i >= 0; i--) { if (mUidHasActiveVisibleWindowPredicate.test(mBoundClientUids.get(i))) { return true; } } } } return false; } void setBoundClientUids(ArraySet<Integer> boundClientUids) { synchronized (this) { if (boundClientUids == null || boundClientUids.isEmpty()) { mBoundClientUids = null; return; } if (mBoundClientUids == null) { mBoundClientUids = new IntArray(); } else { mBoundClientUids.clear(); } for (int i = boundClientUids.size() - 1; i >= 0; i--) { mBoundClientUids.add(boundClientUids.valueAt(i)); } } } /** * Allows background activity starts using token {@code entity}. Optionally, you can provide * {@code originatingToken} if you have one such originating token, this is useful for tracing * back the grant in the case of the notification token. * * If {@code entity} is already added, this method will update its {@code originatingToken}. */ void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) { synchronized (this) { if (mBackgroundActivityStartTokens == null) { mBackgroundActivityStartTokens = new ArrayMap<>(); } mBackgroundActivityStartTokens.put(entity, originatingToken); } } /** * Removes token {@code entity} that allowed background activity starts added via {@link * #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}. */ void removeAllowBackgroundActivityStartsToken(Binder entity) { synchronized (this) { if (mBackgroundActivityStartTokens != null) { mBackgroundActivityStartTokens.remove(entity); } } } /** * Returns whether this process is allowed to close system dialogs via a background activity * start token that allows the close system dialogs operation (eg. notification). */ boolean canCloseSystemDialogsByToken(int uid) { if (mBackgroundActivityStartCallback == null) { return false; } synchronized (this) { if (mBackgroundActivityStartTokens == null || mBackgroundActivityStartTokens.isEmpty()) { return false; } return mBackgroundActivityStartCallback.canCloseSystemDialogs( mBackgroundActivityStartTokens.values(), uid); } } void dump(PrintWriter pw, String prefix) { synchronized (this) { if (mBackgroundActivityStartTokens != null && !mBackgroundActivityStartTokens.isEmpty()) { pw.print(prefix); pw.println("Background activity start tokens (token: originating token):"); for (int i = mBackgroundActivityStartTokens.size() - 1; i >= 0; i--) { pw.print(prefix); pw.print(" - "); pw.print(mBackgroundActivityStartTokens.keyAt(i)); pw.print(": "); pw.println(mBackgroundActivityStartTokens.valueAt(i)); } } if (mBoundClientUids != null && mBoundClientUids.size() > 0) { pw.print(prefix); pw.print("BoundClientUids:"); pw.println(Arrays.toString(mBoundClientUids.toArray())); } } } }
services/core/java/com/android/server/wm/WindowProcessController.java +28 −165 File changed.Preview size limit exceeded, changes collapsed. Show changes