Merge "All FGS exemptions should be propagated via service bindings." into sc-dev

This commit is contained in:
Hui Yu
2021-05-24 20:18:38 +00:00
committed by Android (Google) Code Review
4 changed files with 96 additions and 181 deletions

View File

@@ -21,38 +21,40 @@ import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SER
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER;
import static android.os.PowerExemptionManager.REASON_FGS_BINDING;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_TOP;
import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH;
import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
import static android.os.PowerWhitelistManager.reasonCodeToString;
import static android.os.PowerExemptionManager.REASON_UID_VISIBLE;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerExemptionManager.getReasonCodeFromProcState;
import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.INVALID_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
@@ -118,8 +120,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -135,6 +136,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -3614,8 +3616,9 @@ public final class ActiveServices {
+ " for fg-service launch");
}
mAm.tempAllowlistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
"fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
"fg-service-launch",
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
r.mRecentCallingUid);
}
@@ -5740,6 +5743,66 @@ public final class ActiveServices {
int ret = shouldAllowFgsStartForegroundLocked(allowWhileInUse, callingPid, callingUid,
callingPackage, r);
String bindFromPackage = null;
if (ret == REASON_DENIED) {
// If the callingUid is not allowed to start FGS, check if the callingUid has any
// service that is bound by a clientUid, the clientUid can propagate its BG-FGS-start
// capability down to the callingUid.
final ArraySet<Integer> checkedClientUids = new ArraySet<>();
final Pair<Integer, String> isAllowed = mAm.mProcessList.searchEachLruProcessesLOSP(
false, pr -> {
if (pr.uid == callingUid) {
final ProcessServiceRecord psr = pr.mServices;
final int serviceCount = psr.mServices.size();
for (int svc = 0; svc < serviceCount; svc++) {
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
psr.mServices.valueAt(svc).getConnections();
final int size = conns.size();
for (int conni = 0; conni < size; conni++) {
final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
for (int con = 0; con < crs.size(); con++) {
final ConnectionRecord cr = crs.get(con);
final ProcessRecord clientPr = cr.binding.client;
// Persistent process does not propagate BG-FGS-start capability
// down to service over binding.
if (clientPr.mState.getCurProcState()
<= PROCESS_STATE_PERSISTENT_UI) {
continue;
}
final int clientPid = clientPr.mPid;
final int clientUid = clientPr.uid;
// An UID can bind to itself, do not check on itself again.
// Also skip already checked clientUid.
if (clientUid == callingUid
|| checkedClientUids.contains(clientUid)) {
continue;
}
final String clientPackageName = cr.clientPackageName;
final @ReasonCode int allowWhileInUse2 =
shouldAllowFgsWhileInUsePermissionLocked(clientPackageName,
clientPid, clientUid, null /* serviceRecord */,
false /* allowBackgroundActivityStarts */);
final @ReasonCode int allowStartFgs =
shouldAllowFgsStartForegroundLocked(allowWhileInUse2,
clientPid, clientUid, clientPackageName, null /* targetService */);
if (allowStartFgs != REASON_DENIED) {
return new Pair<>(allowStartFgs, clientPackageName);
} else {
checkedClientUids.add(clientUid);
}
}
}
}
}
return null;
});
if (isAllowed != null) {
ret = REASON_FGS_BINDING;
bindFromPackage = isAllowed.second;
}
}
final int uidState = mAm.getUidStateLocked(callingUid);
int callerTargetSdkVersion = INVALID_UID;
try {
@@ -5765,6 +5828,7 @@ public final class ActiveServices {
+ "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ "; callerTargetSdkVersion:" + callerTargetSdkVersion
+ "; startForegroundCount:" + r.mStartForegroundCount
+ "; bindFromPackage:" + bindFromPackage
+ "]";
if (!debugInfo.equals(r.mInfoAllowStartForeground)) {
r.mLoggedInfoAllowStartForeground = false;
@@ -5790,9 +5854,7 @@ public final class ActiveServices {
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
if (app.uid == callingUid) {
final ProcessStateRecord state = app.mState;
if (state.getAllowedStartFgs() != REASON_DENIED) {
return state.getAllowedStartFgs();
} else if (state.isAllowedStartFgsState()) {
if (state.isAllowedStartFgsState()) {
return getReasonCodeFromProcState(state.getAllowStartFgsState());
} else if (state.areBackgroundFgsStartsAllowedByToken()) {
return REASON_FGS_BINDING;
@@ -5891,6 +5953,7 @@ public final class ActiveServices {
}
if (ret == REASON_DENIED) {
if (mAm.mConstants.mFgsAllowOptOut
&& targetService != null
&& targetService.appInfo.hasRequestForegroundServiceExemption()) {
ret = REASON_OPT_OUT_REQUESTED;
}

View File

@@ -42,7 +42,6 @@ import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -1574,8 +1573,7 @@ public class OomAdjuster {
state.setAdjTarget(null);
state.setEmpty(false);
state.setCached(false);
state.setAllowStartFgsState(PROCESS_STATE_NONEXISTENT);
state.resetAllowStartFgs();
state.resetAllowStartFgsState();
app.mOptRecord.setShouldNotFreeze(false);
final int appUid = app.info.uid;
@@ -1630,7 +1628,6 @@ public class OomAdjuster {
state.setCurAdj(state.getMaxAdj());
state.setCompletedAdjSeq(state.getAdjSeq());
state.bumpAllowStartFgsState(state.getCurProcState());
state.setAllowStartFgs();
// if curAdj is less than prevAppAdj, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
}
@@ -2028,12 +2025,6 @@ public class OomAdjuster {
final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
// pass client's mAllowStartFgs to the app if client is not persistent process.
if (cstate.getAllowedStartFgs() != REASON_DENIED
&& cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
state.setAllowStartFgs(cstate.getAllowedStartFgs());
}
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) {
continue;
@@ -2524,7 +2515,6 @@ public class OomAdjuster {
state.updateLastInvisibleTime(hasVisibleActivities);
state.setHasForegroundActivities(foregroundActivities);
state.setCompletedAdjSeq(mAdjSeq);
state.setAllowStartFgs();
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState

View File

@@ -89,7 +89,7 @@ final class ProcessServiceRecord {
/**
* All ServiceRecord running in this process.
*/
private final ArraySet<ServiceRecord> mServices = new ArraySet<>();
final ArraySet<ServiceRecord> mServices = new ArraySet<>();
/**
* Services that are currently executing code (need to remain foreground).

View File

@@ -16,28 +16,9 @@
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_CAPABILITY_NONE;
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.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
import static android.os.PowerWhitelistManager.ReasonCode;
import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
import static android.os.PowerWhitelistManager.reasonCodeToString;
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.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ProcessRecord.TAG;
@@ -47,7 +28,6 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.os.Binder;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -56,7 +36,6 @@ import com.android.internal.annotations.CompositeRWLock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;
import java.io.PrintWriter;
/**
@@ -326,20 +305,6 @@ final class ProcessStateRecord {
@GuardedBy("mService")
private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
/**
* Does the process has permission to start FGS from background.
*/
@GuardedBy("mService")
private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;
/**
* 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.
*/
@GuardedBy("mService")
private @ReasonCode int mAllowStartFgs = REASON_DENIED;
/**
* Whether or not this process has been in forced-app-standby state.
*/
@@ -435,7 +400,6 @@ final class ProcessStateRecord {
mApp = app;
mService = app.mService;
mProcLock = mService.mProcLock;
setAllowStartFgsByPermission();
}
void init(long now) {
@@ -1152,9 +1116,8 @@ final class ProcessStateRecord {
}
@GuardedBy("mService")
void resetAllowStartFgs() {
void resetAllowStartFgsState() {
mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
mAllowStartFgs = mAllowStartFgsByPermission;
}
@GuardedBy("mService")
@@ -1164,11 +1127,6 @@ final class ProcessStateRecord {
}
}
@GuardedBy("mService")
void setAllowStartFgsState(int allowStartFgsState) {
mAllowStartFgsState = allowStartFgsState;
}
@GuardedBy("mService")
int getAllowStartFgsState() {
return mAllowStartFgsState;
@@ -1179,98 +1137,6 @@ final class ProcessStateRecord {
return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
}
@GuardedBy("mService")
void setAllowStartFgsByPermission() {
int ret = REASON_DENIED;
boolean isSystem = false;
final int uid = UserHandle.getAppId(mApp.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 = REASON_SYSTEM_UID;
}
if (ret == REASON_DENIED) {
if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
} else if (ActivityManager.checkComponentPermission(
START_FOREGROUND_SERVICES_FROM_BACKGROUND,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
ret = REASON_BACKGROUND_FGS_PERMISSION;
} else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
}
}
mAllowStartFgs = mAllowStartFgsByPermission = ret;
}
// TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
@GuardedBy("mService")
void setAllowStartFgs() {
if (mAllowStartFgs != REASON_DENIED) {
return;
}
if (mAllowStartFgs == REASON_DENIED) {
if (isAllowedStartFgsState()) {
mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
}
}
if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a device owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
mAllowStartFgs = REASON_DEVICE_OWNER;
}
}
}
if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a profile owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
mAllowStartFgs = REASON_PROFILE_OWNER;
}
}
}
if (mAllowStartFgs == REASON_DENIED) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
ActivityManagerService.FgsTempAllowListItem item =
mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
if (item != null) {
if (item == ActivityManagerService.FAKE_TEMP_ALLOW_LIST_ITEM) {
mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
} else {
mAllowStartFgs = item.mReasonCode;
}
}
}
}
@GuardedBy("mService")
void setAllowStartFgs(@ReasonCode int allowStartFgs) {
mAllowStartFgs = allowStartFgs;
}
@GuardedBy("mService")
@ReasonCode int getAllowedStartFgs() {
return mAllowStartFgs;
}
@GuardedBy("mService")
void setForcedAppStandby(boolean standby) {
mForcedAppStandby = standby;
@@ -1334,10 +1200,6 @@ final class ProcessStateRecord {
pw.println();
pw.print(prefix); pw.print("allowStartFgsState=");
pw.println(mAllowStartFgsState);
if (mAllowStartFgs != REASON_DENIED) {
pw.print(prefix); pw.print("allowStartFgs=");
pw.println(reasonCodeToString(mAllowStartFgs));
}
if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());