Merge "Remove WM lock from the path of service operations" into sc-dev
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,11 @@ import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
import static com.android.server.am.ActivityManagerService.MY_PID;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
|
||||
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 static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
|
||||
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
|
||||
import static com.android.server.wm.Task.ActivityState.DESTROYED;
|
||||
@@ -61,8 +59,6 @@ import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -103,10 +99,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
final String mName;
|
||||
final int mUid;
|
||||
|
||||
// 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.
|
||||
private final ArrayMap<Binder, IBinder> mBackgroundActivityStartTokens = new ArrayMap<>();
|
||||
// The process of this application; 0 if none
|
||||
private volatile int mPid;
|
||||
// user of process.
|
||||
@@ -118,6 +110,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
final ArraySet<String> mPkgList = new ArraySet<>();
|
||||
private final WindowProcessListener mListener;
|
||||
private final ActivityTaskManagerService mAtm;
|
||||
private final BackgroundLaunchProcessController mBgLaunchController;
|
||||
// The actual proc... may be null only if 'persistent' is true (in which case we are in the
|
||||
// process of launching the app)
|
||||
private IApplicationThread mThread;
|
||||
@@ -169,8 +162,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
private volatile boolean mPerceptible;
|
||||
// Set to true when process was launched with a wrapper attached
|
||||
private volatile boolean mUsingWrapper;
|
||||
// Set of UIDs of clients currently bound to this process
|
||||
private volatile ArraySet<Integer> mBoundClientUids = new ArraySet<Integer>();
|
||||
|
||||
// Thread currently set for VR scheduling
|
||||
int mVrThreadTid;
|
||||
@@ -191,10 +182,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
// The most recent top-most activity that was resumed in the process for pre-Q app.
|
||||
private ActivityRecord mPreQTopResumedActivity = null;
|
||||
// The last time an activity was launched in the process
|
||||
private long mLastActivityLaunchTime;
|
||||
private volatile long mLastActivityLaunchTime;
|
||||
// The last time an activity was finished in the process while the process participated
|
||||
// in a visible task
|
||||
private long mLastActivityFinishTime;
|
||||
private volatile long mLastActivityFinishTime;
|
||||
|
||||
// Last configuration that was reported to the process.
|
||||
private final Configuration mLastReportedConfiguration = new Configuration();
|
||||
@@ -227,9 +218,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
|
||||
private boolean mRunningRemoteAnimation;
|
||||
|
||||
@Nullable
|
||||
private final BackgroundActivityStartCallback mBackgroundActivityStartCallback;
|
||||
|
||||
// The bits used for mActivityStateFlags.
|
||||
private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16;
|
||||
private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17;
|
||||
@@ -246,8 +234,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
*/
|
||||
private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
|
||||
|
||||
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
|
||||
String name, int uid, int userId, Object owner,
|
||||
public WindowProcessController(@NonNull ActivityTaskManagerService atm,
|
||||
@NonNull ApplicationInfo info, String name, int uid, int userId, Object owner,
|
||||
@NonNull WindowProcessListener listener) {
|
||||
mInfo = info;
|
||||
mName = name;
|
||||
@@ -256,7 +244,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
mOwner = owner;
|
||||
mListener = listener;
|
||||
mAtm = atm;
|
||||
mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
|
||||
mBgLaunchController = new BackgroundLaunchProcessController(
|
||||
atm::hasActiveVisibleWindow, atm.getBackgroundActivityStartCallback());
|
||||
|
||||
boolean isSysUiPackage = info.packageName.equals(
|
||||
mAtm.getSysUiServiceComponentLocked().getPackageName());
|
||||
@@ -489,162 +478,59 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
}
|
||||
|
||||
void setLastActivityFinishTimeIfNeeded(long finishTime) {
|
||||
if (finishTime <= mLastActivityFinishTime || !hasActivityInVisibleTask()) {
|
||||
if (finishTime <= mLastActivityFinishTime || !hasVisibleActivities()) {
|
||||
return;
|
||||
}
|
||||
mLastActivityFinishTime = finishTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
* @see BackgroundLaunchProcessController#addOrUpdateAllowBackgroundActivityStartsToken(Binder,
|
||||
* IBinder)
|
||||
*/
|
||||
public void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
|
||||
@Nullable IBinder originatingToken) {
|
||||
synchronized (mAtm.mGlobalLock) {
|
||||
mBackgroundActivityStartTokens.put(entity, originatingToken);
|
||||
}
|
||||
mBgLaunchController.addOrUpdateAllowBackgroundActivityStartsToken(entity, originatingToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes token {@code entity} that allowed background activity starts added via {@link
|
||||
* #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}.
|
||||
*/
|
||||
/** @see BackgroundLaunchProcessController#removeAllowBackgroundActivityStartsToken(Binder) */
|
||||
public void removeAllowBackgroundActivityStartsToken(Binder entity) {
|
||||
synchronized (mAtm.mGlobalLock) {
|
||||
mBackgroundActivityStartTokens.remove(entity);
|
||||
}
|
||||
mBgLaunchController.removeAllowBackgroundActivityStartsToken(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this WindowProcessController in the state of allowing background FGS start?
|
||||
*/
|
||||
@HotPath(caller = HotPath.START_SERVICE)
|
||||
public boolean areBackgroundFgsStartsAllowed() {
|
||||
synchronized (mAtm.mGlobalLock) {
|
||||
return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesAllowed(), true);
|
||||
}
|
||||
return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesAllowed(),
|
||||
true /* isCheckingForFgsStart */);
|
||||
}
|
||||
|
||||
boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
|
||||
return areBackgroundActivityStartsAllowed(appSwitchAllowed, false);
|
||||
return areBackgroundActivityStartsAllowed(appSwitchAllowed,
|
||||
false /* isCheckingForFgsStart */);
|
||||
}
|
||||
|
||||
boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed,
|
||||
private boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed,
|
||||
boolean isCheckingForFgsStart) {
|
||||
// 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 - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
|
||||
|| now - mLastActivityFinishTime < 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 (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime()
|
||||
|| mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) {
|
||||
if (DEBUG_ACTIVITY_STARTS) {
|
||||
Slog.d(TAG, "[WindowProcessController(" + mPid
|
||||
+ ")] Activity start allowed: within "
|
||||
+ ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (DEBUG_ACTIVITY_STARTS) {
|
||||
Slog.d(TAG, "[WindowProcessController(" + mPid + ")] 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 (mInstrumentingWithBackgroundActivityStartPrivileges) {
|
||||
if (DEBUG_ACTIVITY_STARTS) {
|
||||
Slog.d(TAG, "[WindowProcessController(" + mPid
|
||||
+ ")] 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 && hasActivityInVisibleTask()) {
|
||||
if (DEBUG_ACTIVITY_STARTS) {
|
||||
Slog.d(TAG, "[WindowProcessController(" + mPid
|
||||
+ ")] 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, "[WindowProcessController(" + mPid
|
||||
+ ")] Activity start allowed: process bound by foreground uid");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// allow if the flag was explicitly set
|
||||
if (isBackgroundStartAllowedByToken(isCheckingForFgsStart)) {
|
||||
if (DEBUG_ACTIVITY_STARTS) {
|
||||
Slog.d(TAG, "[WindowProcessController(" + mPid
|
||||
+ ")] 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(boolean isCheckingForFgsStart) {
|
||||
if (mBackgroundActivityStartTokens.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCheckingForFgsStart) {
|
||||
/// The checking is for BG-FGS-start.
|
||||
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(), mInfo.uid, mInfo.packageName);
|
||||
return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
|
||||
appSwitchAllowed, isCheckingForFgsStart, hasVisibleActivities(),
|
||||
mInstrumentingWithBackgroundActivityStartPrivileges,
|
||||
mAtm.getLastStopAppSwitchesTime(),
|
||||
mLastActivityLaunchTime, mLastActivityFinishTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
public boolean canCloseSystemDialogsByToken() {
|
||||
synchronized (mAtm.mGlobalLock) {
|
||||
return !mBackgroundActivityStartTokens.isEmpty()
|
||||
&& mBackgroundActivityStartCallback != null
|
||||
&& mBackgroundActivityStartCallback.canCloseSystemDialogs(
|
||||
mBackgroundActivityStartTokens.values(), mInfo.uid);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBoundByForegroundUid() {
|
||||
for (int i = mBoundClientUids.size() - 1; i >= 0; --i) {
|
||||
if (mAtm.hasActiveVisibleWindow(mBoundClientUids.valueAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
boolean canCloseSystemDialogsByToken() {
|
||||
return mBgLaunchController.canCloseSystemDialogsByToken(mUid);
|
||||
}
|
||||
|
||||
public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
|
||||
mBoundClientUids = boundClientUids;
|
||||
mBgLaunchController.setBoundClientUids(boundClientUids);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -793,20 +679,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
return displayArea;
|
||||
}
|
||||
|
||||
private boolean hasActivityInVisibleTask() {
|
||||
for (int i = mActivities.size() - 1; i >= 0; --i) {
|
||||
Task task = mActivities.get(i).getTask();
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
ActivityRecord topActivity = task.getTopNonFinishingActivity();
|
||||
if (topActivity != null && topActivity.mVisibleRequested) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the top resuming activity in process for pre-Q apps, only the top-most visible
|
||||
* activities are allowed to be resumed per process.
|
||||
@@ -1701,17 +1573,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
if (mVrThreadTid != 0) {
|
||||
pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
|
||||
}
|
||||
if (mBackgroundActivityStartTokens.size() > 0) {
|
||||
pw.print(prefix);
|
||||
pw.println("Background activity start tokens (token: originating token):");
|
||||
for (int i = 0; i < mBackgroundActivityStartTokens.size(); i++) {
|
||||
pw.print(prefix); pw.print(" - ");
|
||||
pw.print(mBackgroundActivityStartTokens.keyAt(i));
|
||||
pw.print(": ");
|
||||
pw.println(mBackgroundActivityStartTokens.valueAt(i));
|
||||
|
||||
}
|
||||
}
|
||||
mBgLaunchController.dump(pw, prefix);
|
||||
}
|
||||
pw.println(prefix + " Configuration=" + getConfiguration());
|
||||
pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
|
||||
|
||||
Reference in New Issue
Block a user