From fbf67aac21f5d082b6b584f5c2afce26ec7f23c7 Mon Sep 17 00:00:00 2001 From: Hui Yu Date: Tue, 18 May 2021 16:47:34 -0700 Subject: [PATCH] All FGS exemptions should be propagated via service bindings. Previously, the BG-FGS-start capability can be passed down over service binding, this was implemented in OomAdjuster, due to performance reason, only an subset of FGS exemptions are passed down. This new implementation move it out of OomAdjuster and can pass all FGS exemptions. Instead of in OomAdjuster it can passed down over infinite number of levels of chain binding, the new implementation will be passed down one level. First we call shouldAllowFgsStartForegroundLocked() on the callingUid that starts the FGS, if the return is DENIED, we check if callingUid has any service that is bound by another UID(clientUid), we call shouldAllowFgsStartForegroundLocked() on clientUid. To check if a BG-FGS-start is allowed by any clientUid over service binding, looking for ""Background started FGS: " string in logcat, if the "clientCallingPackage" field is non-null, the reason BG-FGS-start is because of a clientUid and clientCallingPackage is clientUid's packageName. Bug: 188086703 Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsBindingFlagNone Change-Id: Ia692201909cc5095f4aa25ba5a1588510054fb80 --- .../com/android/server/am/ActiveServices.java | 123 +++++++++++---- .../com/android/server/am/OomAdjuster.java | 12 +- .../server/am/ProcessServiceRecord.java | 2 +- .../android/server/am/ProcessStateRecord.java | 140 +----------------- 4 files changed, 96 insertions(+), 181 deletions(-) diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 0f3aa6531e354..562f8f4498337 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -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 checkedClientUids = new ArraySet<>(); + final Pair 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> conns = + psr.mServices.valueAt(svc).getConnections(); + final int size = conns.size(); + for (int conni = 0; conni < size; conni++) { + final ArrayList 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; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 4ad99095a8c68..aa64c65ef7360 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -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 diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java index 5c3bf605f71a0..8f77b87f5308f 100644 --- a/services/core/java/com/android/server/am/ProcessServiceRecord.java +++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java @@ -89,7 +89,7 @@ final class ProcessServiceRecord { /** * All ServiceRecord running in this process. */ - private final ArraySet mServices = new ArraySet<>(); + final ArraySet mServices = new ArraySet<>(); /** * Services that are currently executing code (need to remain foreground). diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index 801e3824d7b02..d83e13cb2e412 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -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 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());