Merge changes I4fdfbe80,Ie2bb56c5,I6ee0e839 into tm-qpr-dev

* changes:
  Merge "Log BAL and full screen intent to statsd." into tm-qpr-dev
  Merge "Update BAL Check to return Allow Reason" into tm-qpr-dev
  Merge "Add ownership for BackgroundActivityStartController" into tm-qpr-dev
This commit is contained in:
Yu-Ting Tseng
2023-03-14 21:32:18 +00:00
committed by Android (Google) Code Review
10 changed files with 661 additions and 351 deletions

View File

@@ -98,6 +98,8 @@ public class ActivityStartController {
/** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */ /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */
private boolean mInExecution = false; private boolean mInExecution = false;
private final BackgroundActivityStartController mBalController;
/** /**
* TODO(b/64750076): Capture information necessary for dump and * TODO(b/64750076): Capture information necessary for dump and
* {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
@@ -120,6 +122,7 @@ public class ActivityStartController {
mFactory.setController(this); mFactory.setController(this);
mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock, mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock,
service.mH); service.mH);
mBalController = new BackgroundActivityStartController(mService, mSupervisor);
} }
/** /**
@@ -670,4 +673,8 @@ public class ActivityStartController {
pw.println("(nothing)"); pw.println("(nothing)");
} }
} }
BackgroundActivityStartController getBackgroundActivityLaunchController() {
return mBalController;
}
} }

View File

@@ -16,7 +16,6 @@
package com.android.server.wm; package com.android.server.wm;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.Activity.RESULT_CANCELED; import static android.app.Activity.RESULT_CANCELED;
import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_CANCELED;
@@ -52,7 +51,6 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.launchModeToString; import static android.content.pm.ActivityInfo.launchModeToString;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID; import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_NONE;
@@ -63,7 +61,6 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
@@ -74,11 +71,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 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.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT; import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
@@ -99,7 +96,6 @@ import android.app.WaitResult;
import android.app.WindowConfiguration; import android.app.WindowConfiguration;
import android.compat.annotation.ChangeId; import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince; import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.IIntentSender; import android.content.IIntentSender;
import android.content.Intent; import android.content.Intent;
import android.content.IntentSender; import android.content.IntentSender;
@@ -115,15 +111,12 @@ import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.Trace; import android.os.Trace;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Pools.SynchronizedPool; import android.util.Pools.SynchronizedPool;
import android.util.Slog; import android.util.Slog;
import android.window.RemoteTransition; import android.window.RemoteTransition;
@@ -139,6 +132,7 @@ import com.android.server.power.ShutdownCheckPoints;
import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants; import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.BackgroundActivityStartController.BalCode;
import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult; import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
@@ -180,9 +174,10 @@ class ActivityStarter {
private int mCallingUid; private int mCallingUid;
private ActivityOptions mOptions; private ActivityOptions mOptions;
// If it is true, background activity can only be started in an existing task that contains // If it is BAL_BLOCK, background activity can only be started in an existing task that contains
// an activity with same uid, or if activity starts are enabled in developer options. // an activity with same uid, or if activity starts are enabled in developer options.
private boolean mRestrictedBgActivity; @BalCode
private int mBalCode;
private int mLaunchMode; private int mLaunchMode;
private boolean mLaunchTaskBehind; private boolean mLaunchTaskBehind;
@@ -264,8 +259,6 @@ class ActivityStarter {
/** /**
* Generates an {@link ActivityStarter} that is ready to handle a new start request. * Generates an {@link ActivityStarter} that is ready to handle a new start request.
* @param controller The {@link ActivityStartController} which the starter who will own
* this instance.
* @return an {@link ActivityStarter} * @return an {@link ActivityStarter}
*/ */
ActivityStarter obtain(); ActivityStarter obtain();
@@ -600,7 +593,7 @@ class ActivityStarter {
mIntent = starter.mIntent; mIntent = starter.mIntent;
mCallingUid = starter.mCallingUid; mCallingUid = starter.mCallingUid;
mOptions = starter.mOptions; mOptions = starter.mOptions;
mRestrictedBgActivity = starter.mRestrictedBgActivity; mBalCode = starter.mBalCode;
mLaunchTaskBehind = starter.mLaunchTaskBehind; mLaunchTaskBehind = starter.mLaunchTaskBehind;
mLaunchFlags = starter.mLaunchFlags; mLaunchFlags = starter.mLaunchFlags;
@@ -1031,15 +1024,25 @@ class ActivityStarter {
ActivityOptions checkedOptions = options != null ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
boolean restrictedBgActivity = false; @BalCode int balCode = BAL_ALLOW_DEFAULT;
if (!abort) { if (!abort) {
try { try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
"shouldAbortBackgroundActivityStart"); "shouldAbortBackgroundActivityStart");
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, BackgroundActivityStartController balController =
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, mController.getBackgroundActivityLaunchController();
request.originatingPendingIntent, request.allowBackgroundActivityStart, balCode =
intent, checkedOptions); balController.checkBackgroundActivityStart(
callingUid,
callingPid,
callingPackage,
realCallingUid,
realCallingPid,
callerApp,
request.originatingPendingIntent,
request.allowBackgroundActivityStart,
intent,
checkedOptions);
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
} }
@@ -1217,13 +1220,13 @@ class ActivityStarter {
WindowProcessController homeProcess = mService.mHomeProcess; WindowProcessController homeProcess = mService.mHomeProcess;
boolean isHomeProcess = homeProcess != null boolean isHomeProcess = homeProcess != null
&& aInfo.applicationInfo.uid == homeProcess.mUid; && aInfo.applicationInfo.uid == homeProcess.mUid;
if (!restrictedBgActivity && !isHomeProcess) { if (balCode != BAL_BLOCK && !isHomeProcess) {
mService.resumeAppSwitches(); mService.resumeAppSwitches();
} }
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
inTask, inTaskFragment, restrictedBgActivity, intentGrants); inTask, inTaskFragment, balCode, intentGrants);
if (request.outActivity != null) { if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord; request.outActivity[0] = mLastStartActivityRecord;
@@ -1273,282 +1276,6 @@ class ActivityStarter {
mController.onExecutionStarted(); mController.onExecutionStarted();
} }
private boolean isHomeApp(int uid, @Nullable String packageName) {
if (mService.mHomeProcess != null) {
// Fast check
return uid == mService.mHomeProcess.mUid;
}
if (packageName == null) {
return false;
}
ComponentName activity =
mService.getPackageManagerInternalLocked().getDefaultHomeActivity(
UserHandle.getUserId(uid));
return activity != null && packageName.equals(activity.getPackageName());
}
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
final boolean useCallingUidState =
originatingPendingIntent == null || checkedOptions == null
|| !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
if (useCallingUidState) {
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Activity start allowed for important callingUid (" + callingUid + ")");
}
return false;
}
// Always allow home application to start activities.
if (isHomeApp(callingUid, callingPackage)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Activity start allowed for home app callingUid (" + callingUid + ")");
}
return false;
}
// IME should always be allowed to start activity, like IME settings.
final WindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow();
if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
}
return false;
}
}
// This is used to block background activity launch even if the app is still
// visible to user after user clicking home button.
final int appSwitchState = mService.getBalAppSwitchesState();
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
|| callingUidProcState == ActivityManager.PROCESS_STATE_TOP
|| callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
final boolean isCallingUidPersistentSystemProcess =
callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
// Normal apps with visible app window will be allowed to start activity if app switching
// is allowed, or apps like live wallpaper with non app visible window will be allowed.
final boolean appSwitchAllowedOrFg =
appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
final boolean allowCallingUidStartActivity =
((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
&& callingUidHasAnyVisibleWindow)
|| isCallingUidPersistentSystemProcess;
if (useCallingUidState && allowCallingUidStartActivity) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
+ ", isCallingUidPersistentSystemProcess = "
+ isCallingUidPersistentSystemProcess);
}
return false;
}
// take realCallingUid into consideration
final int realCallingUidProcState = (callingUid == realCallingUid)
? callingUidProcState
: mService.mActiveUids.getUidState(realCallingUid);
final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
? callingUidHasAnyVisibleWindow
: mService.hasActiveVisibleWindow(realCallingUid);
final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
? isCallingUidForeground
: realCallingUidHasAnyVisibleWindow
|| realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
final int realCallingAppId = UserHandle.getAppId(realCallingUid);
final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
? isCallingUidPersistentSystemProcess
: (realCallingAppId == Process.SYSTEM_UID)
|| realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
// In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
// visible window.
if (Process.isSdkSandboxUid(realCallingUid)) {
int realCallingSdkSandboxUidToAppUid = Process.getAppUidForSdkSandboxUid(
UserHandle.getAppId(realCallingUid));
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: uid in SDK sandbox ("
+ realCallingUid + ") has visible (non-toast) window.");
}
return false;
}
}
// Legacy behavior allows to use caller foreground state to bypass BAL restriction.
final boolean balAllowedByPiSender =
PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
if (balAllowedByPiSender && realCallingUid != callingUid) {
final boolean useCallerPermission =
PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
if (useCallerPermission && ActivityManager.checkComponentPermission(
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
realCallingUid, -1, true)
== PackageManager.PERMISSION_GRANTED) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
+ ") has BAL permission.");
}
return false;
}
// don't abort if the realCallingUid has a visible window
// TODO(b/171459802): We should check appSwitchAllowed also
if (realCallingUidHasAnyVisibleWindow) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
+ ") has visible (non-toast) window");
}
return false;
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
+ ") is persistent system process AND intent sender allowed "
+ "(allowBackgroundActivityStart = true)");
}
return false;
}
// don't abort if the realCallingUid is an associated companion app
if (mService.isAssociatedCompanionApp(UserHandle.getUserId(realCallingUid),
realCallingUid)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
+ ") is companion app");
}
return false;
}
}
if (useCallingUidState) {
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (mService.checkPermission(
START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PERMISSION_GRANTED) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
+ "permission granted for uid "
+ callingUid);
}
return false;
}
// don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
+ ") is recents");
}
return false;
}
// don't abort if the callingUid is the device owner
if (mService.isDeviceOwner(callingUid)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
+ ") is device owner");
}
return false;
}
// don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId,
callingUid)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
+ ") is companion app");
}
return false;
}
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
if (mService.hasSystemAlertWindowPermission(callingUid,
callingPid, callingPackage)) {
Slog.w(TAG, "Background activity start for " + callingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
return false;
}
}
// If we don't have callerApp at this point, no caller was provided to startActivity().
// That's the case for PendingIntent-based starts, since the creator's process might not be
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
// caller if caller allows, so that we can make the decision based on its state.
int callerAppUid = callingUid;
if (callerApp == null && balAllowedByPiSender) {
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
callerAppUid = realCallingUid;
}
// don't abort if the callerApp or other processes of that uid are allowed in any way
if (callerApp != null && useCallingUidState) {
// first check the original calling process
if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
+ callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
}
return false;
}
// only if that one wasn't allowed, check the other ones
final ArraySet<WindowProcessController> uidProcesses =
mService.mProcessMap.getProcesses(callerAppUid);
if (uidProcesses != null) {
for (int i = uidProcesses.size() - 1; i >= 0; i--) {
final WindowProcessController proc = uidProcesses.valueAt(i);
if (proc != callerApp
&& proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Background activity start allowed: process " + proc.getPid()
+ " from uid " + callerAppUid + " is allowed");
}
return false;
}
}
}
}
// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
+ "; appSwitchState: " + appSwitchState
+ "; isCallingUidForeground: " + isCallingUidForeground
+ "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
+ "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
"PROCESS_STATE_", callingUidProcState)
+ "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
+ "; realCallingUid: " + realCallingUid
+ "; isRealCallingUidForeground: " + isRealCallingUidForeground
+ "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow
+ "; realCallingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
"PROCESS_STATE_", realCallingUidProcState)
+ "; isRealCallingUidPersistentSystemProcess: "
+ isRealCallingUidPersistentSystemProcess
+ "; originatingPendingIntent: " + originatingPendingIntent
+ "; allowBackgroundActivityStart: " + allowBackgroundActivityStart
+ "; intent: " + intent
+ "; callerApp: " + callerApp
+ "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
+ "]");
// log aborted activity start to TRON
if (mService.isActivityStartsLoggingEnabled()) {
mSupervisor.getActivityMetricsLogger().logAbortedBgActivityStart(intent, callerApp,
callingUid, callingPackage, callingUidProcState, callingUidHasAnyVisibleWindow,
realCallingUid, realCallingUidProcState, realCallingUidHasAnyVisibleWindow,
(originatingPendingIntent != null));
}
return true;
}
/** /**
* Creates a launch intent for the given auxiliary resolution data. * Creates a launch intent for the given auxiliary resolution data.
*/ */
@@ -1649,7 +1376,7 @@ class ActivityStarter {
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask, int startFlags, boolean doResume, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean restrictedBgActivity, TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants) { NeededUriGrants intentGrants) {
int result = START_CANCELED; int result = START_CANCELED;
final Task startedActivityRootTask; final Task startedActivityRootTask;
@@ -1669,7 +1396,7 @@ class ActivityStarter {
try { try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity, startFlags, doResume, options, inTask, inTaskFragment, balCode,
intentGrants); intentGrants);
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -1816,10 +1543,10 @@ class ActivityStarter {
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask, int startFlags, boolean doResume, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean restrictedBgActivity, TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants) { NeededUriGrants intentGrants) {
setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord, setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
voiceSession, voiceInteractor, restrictedBgActivity); voiceSession, voiceInteractor, balCode);
computeLaunchingTaskFlags(); computeLaunchingTaskFlags();
mIntent.setFlags(mLaunchFlags); mIntent.setFlags(mLaunchFlags);
@@ -2055,7 +1782,8 @@ class ActivityStarter {
|| !targetTask.isUidPresent(mCallingUid) || !targetTask.isUidPresent(mCallingUid)
|| (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode())); || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));
if (mRestrictedBgActivity && blockBalInTask && handleBackgroundActivityAbort(r)) { if (mBalCode == BAL_BLOCK && blockBalInTask
&& handleBackgroundActivityAbort(r)) {
Slog.e(TAG, "Abort background activity starts from " + mCallingUid); Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
return START_ABORTED; return START_ABORTED;
} }
@@ -2452,7 +2180,7 @@ class ActivityStarter {
mIntent = null; mIntent = null;
mCallingUid = -1; mCallingUid = -1;
mOptions = null; mOptions = null;
mRestrictedBgActivity = false; mBalCode = BAL_ALLOW_DEFAULT;
mLaunchTaskBehind = false; mLaunchTaskBehind = false;
mLaunchFlags = 0; mLaunchFlags = 0;
@@ -2497,7 +2225,7 @@ class ActivityStarter {
private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask, private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean doResume, int startFlags, TaskFragment inTaskFragment, boolean doResume, int startFlags,
ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) { IVoiceInteractor voiceInteractor, @BalCode int balCode) {
reset(false /* clearRequest */); reset(false /* clearRequest */);
mStartActivity = r; mStartActivity = r;
@@ -2508,7 +2236,7 @@ class ActivityStarter {
mSourceRootTask = mSourceRecord != null ? mSourceRecord.getRootTask() : null; mSourceRootTask = mSourceRecord != null ? mSourceRecord.getRootTask() : null;
mVoiceSession = voiceSession; mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor; mVoiceInteractor = voiceInteractor;
mRestrictedBgActivity = restrictedBgActivity; mBalCode = balCode;
mLaunchParams.reset(); mLaunchParams.reset();
@@ -2645,7 +2373,7 @@ class ActivityStarter {
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) { if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) {
mAvoidMoveToFront = true; mAvoidMoveToFront = true;
mDoResume = false; mDoResume = false;
} }

View File

@@ -2182,10 +2182,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (appThread != null) { if (appThread != null) {
callerApp = getProcessController(appThread); callerApp = getProcessController(appThread);
} }
final ActivityStarter starter = getActivityStartController().obtainStarter( final BackgroundActivityStartController balController =
null /* intent */, "moveTaskToFront"); getActivityStartController().getBackgroundActivityLaunchController();
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1, if (balController.shouldAbortBackgroundActivityStart(
-1, callerApp, null, false, null, null)) { callingUid,
callingPid,
callingPackage,
-1,
-1,
callerApp,
null,
false,
null,
null)) {
if (!isBackgroundActivityStartsEnabled()) { if (!isBackgroundActivityStartsEnabled()) {
return; return;
} }

View File

@@ -119,10 +119,20 @@ class AppTaskImpl extends IAppTask.Stub {
if (appThread != null) { if (appThread != null) {
callerApp = mService.getProcessController(appThread); callerApp = mService.getProcessController(appThread);
} }
final ActivityStarter starter = mService.getActivityStartController().obtainStarter( final BackgroundActivityStartController balController =
null /* intent */, "moveToFront"); mService.getActivityStartController()
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, .getBackgroundActivityLaunchController();
callingPackage, -1, -1, callerApp, null, false, null, null)) { if (balController.shouldAbortBackgroundActivityStart(
callingUid,
callingPid,
callingPackage,
-1,
-1,
callerApp,
null,
false,
null,
null)) {
if (!mService.isBackgroundActivityStartsEnabled()) { if (!mService.isBackgroundActivityStartsEnabled()) {
return; return;
} }

View File

@@ -0,0 +1,483 @@
/*
* Copyright (C) 2022 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 android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
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.APP_SWITCH_ALLOW;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
import java.lang.annotation.Retention;
/**
* Helper class to check permissions for starting Activities.
*
* <p>This class collects all the logic to prevent malicious attempts to start activities.
*/
public class BackgroundActivityStartController {
private static final String TAG =
TAG_WITH_CLASS_NAME ? "BackgroundActivityStartController" : TAG_ATM;
private final ActivityTaskManagerService mService;
private final ActivityTaskSupervisor mSupervisor;
// TODO(b/263368846) Rename when ASM logic is moved in
@Retention(SOURCE)
@IntDef({BAL_BLOCK,
BAL_ALLOW_DEFAULT,
BAL_ALLOW_ALLOWLISTED_UID,
BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_VISIBLE_WINDOW,
BAL_ALLOW_PENDING_INTENT,
BAL_ALLOW_BAL_PERMISSION,
BAL_ALLOW_SAW_PERMISSION,
BAL_ALLOW_GRACE_PERIOD,
BAL_ALLOW_FOREGROUND,
BAL_ALLOW_SDK_SANDBOX
})
public @interface BalCode {}
static final int BAL_BLOCK = 0;
static final int BAL_ALLOW_DEFAULT = 1;
// Following codes are in order of precedence
/** Important UIDs which should be always allowed to launch activities */
static final int BAL_ALLOW_ALLOWLISTED_UID = 2;
/** Apps that fulfill a certain role that can can always launch new tasks */
static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3;
/** Apps which currently have a visible window */
static final int BAL_ALLOW_VISIBLE_WINDOW = 4;
/** Allowed due to the PendingIntent sender */
static final int BAL_ALLOW_PENDING_INTENT = 5;
/** App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges
* granted to it */
static final int BAL_ALLOW_BAL_PERMISSION = 6;
/** Process has SYSTEM_ALERT_WINDOW permission granted to it */
static final int BAL_ALLOW_SAW_PERMISSION = 7;
/** App is in grace period after an activity was started or finished */
static final int BAL_ALLOW_GRACE_PERIOD = 8;
/** App is in a foreground task or bound to a foreground service (but not itself visible) */
static final int BAL_ALLOW_FOREGROUND = 9;
/** Process belongs to a SDK sandbox */
static final int BAL_ALLOW_SDK_SANDBOX = 10;
BackgroundActivityStartController(
final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) {
mService = service;
mSupervisor = supervisor;
}
private boolean isHomeApp(int uid, @Nullable String packageName) {
if (mService.mHomeProcess != null) {
// Fast check
return uid == mService.mHomeProcess.mUid;
}
if (packageName == null) {
return false;
}
ComponentName activity =
mService.getPackageManagerInternalLocked()
.getDefaultHomeActivity(UserHandle.getUserId(uid));
return activity != null && packageName.equals(activity.getPackageName());
}
boolean shouldAbortBackgroundActivityStart(
int callingUid,
int callingPid,
final String callingPackage,
int realCallingUid,
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart,
Intent intent,
ActivityOptions checkedOptions) {
return checkBackgroundActivityStart(callingUid, callingPid, callingPackage,
realCallingUid, realCallingPid, callerApp, originatingPendingIntent,
allowBackgroundActivityStart, intent, checkedOptions) == BAL_BLOCK;
}
/**
* @return A code denoting which BAL rule allows an activity to be started,
* or {@link BAL_BLOCK} if the launch should be blocked
*/
@BalCode
int checkBackgroundActivityStart(
int callingUid,
int callingPid,
final String callingPackage,
int realCallingUid,
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart,
Intent intent,
ActivityOptions checkedOptions) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
final boolean useCallingUidState =
originatingPendingIntent == null
|| checkedOptions == null
|| !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
if (useCallingUidState) {
if (callingUid == Process.ROOT_UID
|| callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
callingUid, realCallingUid, intent, "Important callingUid");
}
// Always allow home application to start activities.
if (isHomeApp(callingUid, callingPackage)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ false, callingUid, realCallingUid, intent,
"Home app");
}
// IME should always be allowed to start activity, like IME settings.
final WindowState imeWindow =
mService.mRootWindowContainer.getCurrentInputMethodWindow();
if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ false, callingUid, realCallingUid, intent,
"Active ime");
}
}
// This is used to block background activity launch even if the app is still
// visible to user after user clicking home button.
final int appSwitchState = mService.getBalAppSwitchesState();
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
final boolean isCallingUidForeground =
callingUidHasAnyVisibleWindow
|| callingUidProcState == ActivityManager.PROCESS_STATE_TOP
|| callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
final boolean isCallingUidPersistentSystemProcess =
callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
// Normal apps with visible app window will be allowed to start activity if app switching
// is allowed, or apps like live wallpaper with non app visible window will be allowed.
final boolean appSwitchAllowedOrFg =
appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
final boolean allowCallingUidStartActivity =
((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
&& callingUidHasAnyVisibleWindow)
|| isCallingUidPersistentSystemProcess;
if (useCallingUidState && allowCallingUidStartActivity) {
return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW,
/*background*/ false, callingUid, realCallingUid, intent,
"callingUidHasAnyVisibleWindow = "
+ callingUid
+ ", isCallingUidPersistentSystemProcess = "
+ isCallingUidPersistentSystemProcess);
}
// take realCallingUid into consideration
final int realCallingUidProcState =
(callingUid == realCallingUid)
? callingUidProcState
: mService.mActiveUids.getUidState(realCallingUid);
final boolean realCallingUidHasAnyVisibleWindow =
(callingUid == realCallingUid)
? callingUidHasAnyVisibleWindow
: mService.hasActiveVisibleWindow(realCallingUid);
final boolean isRealCallingUidForeground =
(callingUid == realCallingUid)
? isCallingUidForeground
: realCallingUidHasAnyVisibleWindow
|| realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
final int realCallingAppId = UserHandle.getAppId(realCallingUid);
final boolean isRealCallingUidPersistentSystemProcess =
(callingUid == realCallingUid)
? isCallingUidPersistentSystemProcess
: (realCallingAppId == Process.SYSTEM_UID)
|| realCallingUidProcState
<= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
// In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
// visible window.
if (Process.isSdkSandboxUid(realCallingUid)) {
int realCallingSdkSandboxUidToAppUid =
Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
/*background*/ false, callingUid, realCallingUid, intent,
"uid in SDK sandbox has visible (non-toast) window");
}
}
// Legacy behavior allows to use caller foreground state to bypass BAL restriction.
final boolean balAllowedByPiSender =
PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
if (balAllowedByPiSender && realCallingUid != callingUid) {
final boolean useCallerPermission =
PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
if (useCallerPermission
&& ActivityManager.checkComponentPermission(
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
realCallingUid,
-1,
true)
== PackageManager.PERMISSION_GRANTED) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
/*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
}
// don't abort if the realCallingUid has a visible window
// TODO(b/171459802): We should check appSwitchAllowed also
if (realCallingUidHasAnyVisibleWindow) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
/*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has visible (non-toast) window. realCallingUid: "
+ realCallingUid);
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
/*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid is persistent system process AND intent "
+ "sender allowed (allowBackgroundActivityStart = true). "
+ "realCallingUid: " + realCallingUid);
}
// don't abort if the realCallingUid is an associated companion app
if (mService.isAssociatedCompanionApp(
UserHandle.getUserId(realCallingUid), realCallingUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
/*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid is a companion app. "
+ "realCallingUid: " + realCallingUid);
}
}
if (useCallingUidState) {
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
callingPid, callingUid) == PERMISSION_GRANTED) {
return logStartAllowedAndReturnCode(BAL_ALLOW_BAL_PERMISSION,
/*background*/ true, callingUid, realCallingUid, intent,
"START_ACTIVITIES_FROM_BACKGROUND permission granted");
}
// don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, callingUid, realCallingUid,
intent, "Recents Component");
}
// don't abort if the callingUid is the device owner
if (mService.isDeviceOwner(callingUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, callingUid, realCallingUid,
intent, "Device Owner");
}
// don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, callingUid, realCallingUid,
intent, "Companion App");
}
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
Slog.w(
TAG,
"Background activity start for "
+ callingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
/*background*/ true, callingUid, realCallingUid,
intent, "SYSTEM_ALERT_WINDOW permission is granted");
}
}
// If we don't have callerApp at this point, no caller was provided to startActivity().
// That's the case for PendingIntent-based starts, since the creator's process might not be
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
// caller if caller allows, so that we can make the decision based on its state.
int callerAppUid = callingUid;
if (callerApp == null && balAllowedByPiSender) {
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
callerAppUid = realCallingUid;
}
// don't abort if the callerApp or other processes of that uid are allowed in any way
if (callerApp != null && useCallingUidState) {
// first check the original calling process
@BalCode int balAllowedForCaller = callerApp
.areBackgroundActivityStartsAllowed(appSwitchState);
if (balAllowedForCaller != BAL_BLOCK) {
return logStartAllowedAndReturnCode(balAllowedForCaller,
/*background*/ true, callingUid, realCallingUid, intent,
"callerApp process (pid = " + callerApp.getPid()
+ ", uid = " + callerAppUid + ") is allowed");
}
// only if that one wasn't allowed, check the other ones
final ArraySet<WindowProcessController> uidProcesses =
mService.mProcessMap.getProcesses(callerAppUid);
if (uidProcesses != null) {
for (int i = uidProcesses.size() - 1; i >= 0; i--) {
final WindowProcessController proc = uidProcesses.valueAt(i);
int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
if (proc != callerApp
&& balAllowedForUid != BAL_BLOCK) {
return logStartAllowedAndReturnCode(balAllowedForUid,
/*background*/ true, callingUid, realCallingUid, intent,
"process" + proc.getPid()
+ " from uid " + callerAppUid + " is allowed");
}
}
}
}
// anything that has fallen through would currently be aborted
Slog.w(
TAG,
"Background activity start [callingPackage: "
+ callingPackage
+ "; callingUid: "
+ callingUid
+ "; appSwitchState: "
+ appSwitchState
+ "; isCallingUidForeground: "
+ isCallingUidForeground
+ "; callingUidHasAnyVisibleWindow: "
+ callingUidHasAnyVisibleWindow
+ "; callingUidProcState: "
+ DebugUtils.valueToString(
ActivityManager.class, "PROCESS_STATE_", callingUidProcState)
+ "; isCallingUidPersistentSystemProcess: "
+ isCallingUidPersistentSystemProcess
+ "; realCallingUid: "
+ realCallingUid
+ "; isRealCallingUidForeground: "
+ isRealCallingUidForeground
+ "; realCallingUidHasAnyVisibleWindow: "
+ realCallingUidHasAnyVisibleWindow
+ "; realCallingUidProcState: "
+ DebugUtils.valueToString(
ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState)
+ "; isRealCallingUidPersistentSystemProcess: "
+ isRealCallingUidPersistentSystemProcess
+ "; originatingPendingIntent: "
+ originatingPendingIntent
+ "; allowBackgroundActivityStart: "
+ allowBackgroundActivityStart
+ "; intent: "
+ intent
+ "; callerApp: "
+ callerApp
+ "; inVisibleTask: "
+ (callerApp != null && callerApp.hasActivityInVisibleTask())
+ "]");
// log aborted activity start to TRON
if (mService.isActivityStartsLoggingEnabled()) {
mSupervisor
.getActivityMetricsLogger()
.logAbortedBgActivityStart(
intent,
callerApp,
callingUid,
callingPackage,
callingUidProcState,
callingUidHasAnyVisibleWindow,
realCallingUid,
realCallingUidProcState,
realCallingUidHasAnyVisibleWindow,
(originatingPendingIntent != null));
}
return BAL_BLOCK;
}
static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
DEBUG_ACTIVITY_STARTS ? ("[Process(" + pid + ")]" + msg) : "");
}
static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
int callingUid, int realCallingUid, Intent intent, String msg) {
statsLogBalAllowed(code, callingUid, realCallingUid, intent);
if (DEBUG_ACTIVITY_STARTS) {
StringBuilder builder = new StringBuilder();
if (background) {
builder.append("Background ");
}
builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
builder.append("BAL Code: ");
builder.append(code);
Slog.d(TAG, builder.toString());
}
return code;
}
private static void statsLogBalAllowed(
@BalCode int code, int callingUid, int realCallingUid, Intent intent) {
if (code == BAL_ALLOW_PENDING_INTENT
&& (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) {
String activityName =
intent != null ? intent.getComponent().flattenToShortString() : "";
FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
activityName,
code,
callingUid,
realCallingUid);
}
if (code == BAL_ALLOW_BAL_PERMISSION || code == BAL_ALLOW_FOREGROUND
|| code == BAL_ALLOW_SAW_PERMISSION) {
// We don't need to know which activity in this case.
FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
/*activityName*/ "",
code,
callingUid,
realCallingUid);
}
}
}

View File

@@ -22,6 +22,10 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -71,7 +75,8 @@ class BackgroundLaunchProcessController {
mBackgroundActivityStartCallback = callback; mBackgroundActivityStartCallback = callback;
} }
boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, @BackgroundActivityStartController.BalCode
int areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
int appSwitchState, boolean isCheckingForFgsStart, int appSwitchState, boolean isCheckingForFgsStart,
boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges, boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastStopAppSwitchesTime, long lastActivityLaunchTime,
@@ -88,12 +93,10 @@ class BackgroundLaunchProcessController {
// let app to be able to start background activity even it's in grace period. // let app to be able to start background activity even it's in grace period.
if (lastActivityLaunchTime > lastStopAppSwitchesTime if (lastActivityLaunchTime > lastStopAppSwitchesTime
|| lastActivityFinishTime > lastStopAppSwitchesTime) { || lastActivityFinishTime > lastStopAppSwitchesTime) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: within " pid, "Activity start allowed: within "
+ ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
}
return true;
} }
if (DEBUG_ACTIVITY_STARTS) { if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[Process(" + pid + ")] Activity start within " Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
@@ -105,39 +108,31 @@ class BackgroundLaunchProcessController {
} }
// Allow if the proc is instrumenting with background activity starts privs. // Allow if the proc is instrumenting with background activity starts privs.
if (hasBackgroundActivityStartPrivileges) { if (hasBackgroundActivityStartPrivileges) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process instrumenting with background " pid, "Activity start allowed: process instrumenting with background "
+ "activity starts privileges"); + "activity starts privileges");
}
return true;
} }
// Allow if the caller has an activity in any foreground task. // Allow if the caller has an activity in any foreground task.
if (hasActivityInVisibleTask if (hasActivityInVisibleTask
&& (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process has activity in foreground task"); 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. // Allow if the caller is bound by a UID that's currently foreground.
if (isBoundByForegroundUid()) { if (isBoundByForegroundUid()) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process bound by foreground uid"); pid, "Activity start allowed: process bound by foreground uid");
}
return true;
} }
// Allow if the flag was explicitly set. // Allow if the flag was explicitly set.
if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process allowed by token"); pid, "Activity start allowed: process allowed by token");
}
return true;
} }
return false; return BAL_BLOCK;
} }
/** /**

View File

@@ -14,3 +14,6 @@ winsonc@google.com
tigerhuang@google.com tigerhuang@google.com
lihongyu@google.com lihongyu@google.com
mariiasand@google.com mariiasand@google.com
per-file BackgroundActivityStartController.java = set noparent
per-file BackgroundActivityStartController.java = brufino@google.com, ogunwale@google.com, louischang@google.com, lus@google.com, rickywai@google.com

View File

@@ -40,6 +40,7 @@ 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.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS; 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.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
import static com.android.server.wm.WindowManagerService.MY_PID; import static com.android.server.wm.WindowManagerService.MY_PID;
import android.Manifest; import android.Manifest;
@@ -544,15 +545,17 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@HotPath(caller = HotPath.START_SERVICE) @HotPath(caller = HotPath.START_SERVICE)
public boolean areBackgroundFgsStartsAllowed() { public boolean areBackgroundFgsStartsAllowed() {
return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesState(), return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesState(),
true /* isCheckingForFgsStart */); true /* isCheckingForFgsStart */) != BAL_BLOCK;
} }
boolean areBackgroundActivityStartsAllowed(int appSwitchState) { @BackgroundActivityStartController.BalCode
int areBackgroundActivityStartsAllowed(int appSwitchState) {
return areBackgroundActivityStartsAllowed(appSwitchState, return areBackgroundActivityStartsAllowed(appSwitchState,
false /* isCheckingForFgsStart */); false /* isCheckingForFgsStart */);
} }
private boolean areBackgroundActivityStartsAllowed(int appSwitchState, @BackgroundActivityStartController.BalCode
private int areBackgroundActivityStartsAllowed(int appSwitchState,
boolean isCheckingForFgsStart) { boolean isCheckingForFgsStart) {
return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName, return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(), appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(),

View File

@@ -16,7 +16,9 @@
package com.android.server.wm; package com.android.server.wm;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.Activity.RESULT_CANCELED; import static android.app.Activity.RESULT_CANCELED;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_CANCELED;
@@ -42,6 +44,7 @@ import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBE
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID; import static android.os.Process.SYSTEM_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
@@ -49,6 +52,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -73,6 +77,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.notNull;
@@ -103,6 +108,8 @@ import android.window.TaskFragmentOrganizerToken;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker; import com.android.server.wm.utils.MockTracker;
@@ -110,6 +117,8 @@ import com.android.server.wm.utils.MockTracker;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@@ -150,6 +159,9 @@ public class ActivityStarterTests extends WindowTestsBase {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mController = mock(ActivityStartController.class); mController = mock(ActivityStartController.class);
BackgroundActivityStartController balController =
new BackgroundActivityStartController(mAtm, mSupervisor);
doReturn(balController).when(mController).getBackgroundActivityLaunchController();
mActivityMetricsLogger = mock(ActivityMetricsLogger.class); mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
clearInvocations(mActivityMetricsLogger); clearInvocations(mActivityMetricsLogger);
} }
@@ -211,10 +223,13 @@ public class ActivityStarterTests extends WindowTestsBase {
int expectedResult) { int expectedResult) {
final ActivityTaskManagerService service = mAtm; final ActivityTaskManagerService service = mAtm;
final IPackageManager packageManager = mock(IPackageManager.class); final IPackageManager packageManager = mock(IPackageManager.class);
final ActivityStartController controller = mock(ActivityStartController.class);
final ActivityStarter starter = new ActivityStarter(controller, service, final ActivityStarter starter =
service.mTaskSupervisor, mock(ActivityStartInterceptor.class)); new ActivityStarter(
mController,
service,
service.mTaskSupervisor,
mock(ActivityStartInterceptor.class));
prepareStarter(launchFlags); prepareStarter(launchFlags);
final IApplicationThread caller = mock(IApplicationThread.class); final IApplicationThread caller = mock(IApplicationThread.class);
final WindowProcessListener listener = mock(WindowProcessListener.class); final WindowProcessListener listener = mock(WindowProcessListener.class);
@@ -723,6 +738,63 @@ public class ActivityStarterTests extends WindowTestsBase {
isCallingUidDeviceOwner, false /* isPinnedSingleInstance */); isCallingUidDeviceOwner, false /* isPinnedSingleInstance */);
} }
/**
* This test ensures proper logging for BAL_ALLOW_PERMISSION.
*/
@Test
public void testBackgroundActivityStartsAllowed_logging() {
doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
MockitoSession mockingSession = mockitoSession()
.mockStatic(ActivityTaskManagerService.class)
.mockStatic(FrameworkStatsLog.class)
.strictness(Strictness.LENIENT)
.startMocking();
doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
eq(START_ACTIVITIES_FROM_BACKGROUND),
anyInt(), anyInt()));
runAndVerifyBackgroundActivityStartsSubtest(
"allowed_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
false, true, false, false, false);
verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
"", // activity name
BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION,
UNIMPORTANT_UID,
UNIMPORTANT_UID2));
mockingSession.finishMocking();
}
/**
* This test ensures proper logging for BAL_ALLOW_PENDING_INTENT.
*/
@Test
public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() {
doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
MockitoSession mockingSession = mockitoSession()
.mockStatic(ActivityTaskManagerService.class)
.mockStatic(FrameworkStatsLog.class)
.mockStatic(PendingIntentRecord.class)
.strictness(Strictness.LENIENT)
.startMocking();
doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
eq(START_ACTIVITIES_FROM_BACKGROUND),
anyInt(), anyInt()));
doReturn(true).when(
() -> PendingIntentRecord.isPendingIntentBalAllowedByCaller(anyObject()));
runAndVerifyBackgroundActivityStartsSubtest(
"allowed_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP,
false, true, false, false, false);
verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME,
BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT,
UNIMPORTANT_UID,
Process.SYSTEM_UID));
mockingSession.finishMocking();
}
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
@@ -1491,7 +1563,7 @@ public class ActivityStarterTests extends WindowTestsBase {
TaskFragment inTaskFragment) { TaskFragment inTaskFragment) {
starter.startActivityInner(target, source, null /* voiceSession */, starter.startActivityInner(target, source, null /* voiceSession */,
null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */, null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */,
options, inTask, inTaskFragment, false /* restrictedBgActivity */, options, inTask, inTaskFragment,
null /* intentGrants */); BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */);
} }
} }

View File

@@ -188,7 +188,7 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase {
/* options */null, /* options */null,
/* inTask */null, /* inTask */null,
/* inTaskFragment */ null, /* inTaskFragment */ null,
/* restrictedBgActivity */false, /* balCode */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT,
/* intentGrants */null); /* intentGrants */null);
assertEquals(result, START_ABORTED); assertEquals(result, START_ABORTED);