The ability to start FGS can be passed down by service binding.

1. Add field mAllowStartFgs in ProcessRecord to indicate this app can
start FGS.
2. mAllowStartFgs is true if the process has
  * any of these permissions: START_ACTIVITIES_FROM_BACKGROUND,
START_FOREGROUND_SERVICES_FROM_BACKGROUND, SYSTEM_ALERT_WINDOW
  * the process's uid is ROOT_UID, SYSTEM_UID, NFC_UID, SHELL_UID.
  * the process's proc state is higher or equals to
PROCESS_STATE_BOUND_FOREGROUND_SERVICE.
  * the process's uid is DeviceOwner, or allowlisted by
DeviceIdleController.
3. The mAllowStartFgs ability can be passed to another process by
service binding. Except if the binder is PROCESS_STATE_PERSISTENT, this
ability does not pass down.

Bug: 171305836
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsBindingFlagNone

Change-Id: I20d977ce7ae65316cdec2cd0ef9cf9bafec2adbd
This commit is contained in:
Hui Yu
2020-12-10 15:14:16 -08:00
parent 3d8a47bdbc
commit 631f90a7b8
3 changed files with 113 additions and 10 deletions

View File

@@ -19,7 +19,6 @@ package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Process.NFC_UID;
@@ -168,6 +167,7 @@ public final class ActiveServices {
public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
@@ -187,7 +187,8 @@ public final class ActiveServices {
FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE
FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE,
FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -5244,10 +5245,14 @@ public final class ActiveServices {
if (ret == FGS_FEATURE_DENIED) {
for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
if (pr.uid == callingUid
&& pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
break;
if (pr.uid == callingUid) {
if (pr.mAllowStartFgs) {
ret = FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD;
break;
} else if (pr.isAllowedStartFgsState()) {
ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
break;
}
}
}
}
@@ -5286,7 +5291,7 @@ public final class ActiveServices {
}
if (ret == FGS_FEATURE_DENIED) {
if (mAm.isWhitelistedForFgsStartLocked(r.appInfo.uid)) {
if (mAm.isWhitelistedForFgsStartLocked(callingUid)) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
@@ -5354,6 +5359,8 @@ public final class ActiveServices {
return "ALLOWED_BY_FGS_BINDING";
case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE:
return "ALLOWED_BY_DEVICE_DEMO_MODE";
case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD:
return "ALLOWED_BY_PROCESS_RECORD";
default:
return "";
}

View File

@@ -1329,7 +1329,7 @@ public final class OomAdjuster {
app.setCached(false);
app.shouldNotFreeze = false;
app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
app.resetAllowStartFgs();
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -1351,7 +1351,6 @@ public final class OomAdjuster {
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
app.curCapability = PROCESS_CAPABILITY_ALL;
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT);
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
@@ -1382,6 +1381,8 @@ public final class OomAdjuster {
app.setCurRawProcState(app.getCurProcState());
app.curAdj = app.maxAdj;
app.completedAdjSeq = app.adjSeq;
app.bumpAllowStartFgsState(app.getCurProcState());
app.setAllowStartFgs();
// if curAdj is less than prevAppAdj, then this process was promoted
return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
}
@@ -1773,6 +1774,11 @@ public final class OomAdjuster {
int clientAdj = client.getCurRawAdj();
int clientProcState = client.getCurRawProcState();
// pass client's mAllowStartFgs to the app if client is not persistent process.
if (client.mAllowStartFgs && client.maxAdj >= ProcessList.FOREGROUND_APP_ADJ) {
app.mAllowStartFgs = true;
}
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
continue;
@@ -2236,7 +2242,7 @@ public final class OomAdjuster {
app.setCurRawProcState(procState);
app.setHasForegroundActivities(foregroundActivities);
app.completedAdjSeq = mAdjSeq;
app.setAllowStartFgs();
// if curAdj or curProcState improved, then this process was promoted
return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState
|| app.curCapability != prevCapability ;

View File

@@ -16,7 +16,16 @@
package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
@@ -361,6 +370,17 @@ class ProcessRecord implements WindowProcessListener {
private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
// The list of permissions that can start FGS from background.
private static String[] ALLOW_BG_START_FGS_PERMISSIONS =
{START_ACTIVITIES_FROM_BACKGROUND, START_FOREGROUND_SERVICES_FROM_BACKGROUND,
SYSTEM_ALERT_WINDOW};
// Does the process has permission to start FGS from background.
boolean mAllowStartFgsByPermission;
// Can this process start FGS from background?
// If this process has the ability to start FGS from background, this ability can be passed to
// another process through service binding.
boolean mAllowStartFgs;
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -476,6 +496,9 @@ class ProcessRecord implements WindowProcessListener {
pw.println();
pw.print(prefix); pw.print("allowStartFgsState=");
pw.println(mAllowStartFgsState);
if (mAllowStartFgs) {
pw.print(prefix); pw.print("allowStartFgs="); pw.println(mAllowStartFgs);
}
if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
@@ -672,6 +695,7 @@ class ProcessRecord implements WindowProcessListener {
mWindowProcessController = new WindowProcessController(
mService.mActivityTaskManager, info, processName, uid, userId, this, this);
pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
setAllowStartFgsByPermission();
}
public void setPid(int _pid) {
@@ -1983,12 +2007,78 @@ class ProcessRecord implements WindowProcessListener {
return mDialogController;
}
void resetAllowStartFgs() {
mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
mAllowStartFgs = mAllowStartFgsByPermission;
}
void bumpAllowStartFgsState(int newProcState) {
if (newProcState < mAllowStartFgsState) {
mAllowStartFgsState = newProcState;
}
}
void setAllowStartFgsByPermission() {
boolean ret = false;
if (!ret) {
boolean isSystem = false;
final int uid = UserHandle.getAppId(info.uid);
switch (uid) {
case ROOT_UID:
case SYSTEM_UID:
case NFC_UID:
case SHELL_UID:
isSystem = true;
break;
default:
isSystem = false;
break;
}
if (isSystem) {
ret = true;
}
}
if (!ret) {
for (int i = 0; i < ALLOW_BG_START_FGS_PERMISSIONS.length; ++i) {
if (ActivityManager.checkComponentPermission(ALLOW_BG_START_FGS_PERMISSIONS[i],
info.uid, -1, true)
== PERMISSION_GRANTED) {
ret = true;
break;
}
}
}
mAllowStartFgs = mAllowStartFgsByPermission = ret;
}
boolean isAllowedStartFgsState() {
return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
}
void setAllowStartFgs() {
if (mAllowStartFgs) {
return;
}
if (!mAllowStartFgs) {
mAllowStartFgs = isAllowedStartFgsState();
}
if (!mAllowStartFgs) {
// Is the calling UID a device owner app?
if (mService.mInternal != null) {
mAllowStartFgs = mService.mInternal.isDeviceOwner(info.uid);
}
}
if (!mAllowStartFgs) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
mAllowStartFgs = mService.isWhitelistedForFgsStartLocked(info.uid);
}
}
/** A controller to generate error dialogs in {@link ProcessRecord} */
class ErrorDialogController {
/** dialogs being displayed due to crash */