Merge "Added FGS logic change detection with WTF" into udc-qpr-dev

This commit is contained in:
Makoto Onuki
2023-07-17 20:13:19 +00:00
committed by Android (Google) Code Review
4 changed files with 196 additions and 60 deletions

View File

@@ -256,7 +256,7 @@ import java.util.function.Predicate;
public final class ActiveServices {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
private static final String TAG_MU = TAG + POSTFIX_MU;
private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;
private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
@@ -850,8 +850,7 @@ public final class ActiveServices {
// Service.startForeground()), at that point we will consult the BFSL check and the timeout
// and make the necessary decisions.
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
backgroundStartPrivileges, false /* isBindService */,
!fgRequired /* isStartService */);
backgroundStartPrivileges, false /* isBindService */);
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
@@ -894,7 +893,7 @@ public final class ActiveServices {
if (fgRequired) {
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
if (!r.isFgsAllowedStart() && isBgFgsRestrictionEnabled(r)) {
String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName;
@@ -1060,7 +1059,7 @@ public final class ActiveServices {
// Use that as a shortcut if possible to avoid having to recheck all the conditions.
final boolean whileInUseAllowsUiJobScheduling =
ActivityManagerService.doesReasonCodeAllowSchedulingUserInitiatedJobs(
r.mAllowWhileInUsePermissionInFgsReason);
r.getFgsAllowWIU());
r.updateAllowUiJobScheduling(whileInUseAllowsUiJobScheduling
|| mAm.canScheduleUserInitiatedJobs(callingUid, callingPid, callingPackage));
} else {
@@ -2178,12 +2177,12 @@ public final class ActiveServices {
// on a SHORT_SERVICE FGS.
// See if the app could start an FGS or not.
r.mAllowStartForeground = REASON_DENIED;
r.clearFgsAllowStart();
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
false /* isBindService */, false /* isStartService */);
if (r.mAllowStartForeground == REASON_DENIED) {
false /* isBindService */);
if (!r.isFgsAllowedStart()) {
Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: "
+ " BFSL DENIED.");
} else {
@@ -2191,13 +2190,13 @@ public final class ActiveServices {
Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: "
+ " BFSL Allowed: "
+ PowerExemptionManager.reasonCodeToString(
r.mAllowStartForeground));
r.getFgsAllowStart()));
}
}
final boolean fgsStartAllowed =
!isBgFgsRestrictionEnabledForService
|| (r.mAllowStartForeground != REASON_DENIED);
|| r.isFgsAllowedStart();
if (fgsStartAllowed) {
if (isNewTypeShortFgs) {
@@ -2246,7 +2245,7 @@ public final class ActiveServices {
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
false /* isBindService */, false /* isStartService */);
false /* isBindService */);
final String temp = "startForegroundDelayMs:" + delayMs;
if (r.mInfoAllowStartForeground != null) {
r.mInfoAllowStartForeground += "; " + temp;
@@ -2266,20 +2265,21 @@ public final class ActiveServices {
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
false /* isBindService */, false /* isStartService */);
false /* isBindService */);
}
// If the foreground service is not started from TOP process, do not allow it to
// have while-in-use location/camera/microphone access.
if (!r.mAllowWhileInUsePermissionInFgs) {
if (!r.isFgsAllowedWIU()) {
Slog.w(TAG,
"Foreground service started from background can not have "
+ "location/camera/microphone access: service "
+ r.shortInstanceName);
}
r.maybeLogFgsLogicChange();
if (!bypassBfslCheck) {
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED
if (!r.isFgsAllowedStart()
&& isBgFgsRestrictionEnabledForService) {
final String msg = "Service.startForeground() not allowed due to "
+ "mAllowStartForeground false: service "
@@ -2378,9 +2378,9 @@ public final class ActiveServices {
// The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could
// be deferred, make a copy of mAllowStartForeground and
// mAllowWhileInUsePermissionInFgs.
r.mAllowStartForegroundAtEntering = r.mAllowStartForeground;
r.mAllowStartForegroundAtEntering = r.getFgsAllowStart();
r.mAllowWhileInUsePermissionInFgsAtEntering =
r.mAllowWhileInUsePermissionInFgs;
r.isFgsAllowedWIU();
r.mStartForegroundCount++;
r.mFgsEnterTime = SystemClock.uptimeMillis();
if (!stopProcStatsOp) {
@@ -2558,7 +2558,7 @@ public final class ActiveServices {
policy.getForegroundServiceTypePolicyInfo(type, defaultToType);
final @ForegroundServicePolicyCheckCode int code = policy.checkForegroundServiceTypePolicy(
mAm.mContext, r.packageName, r.app.uid, r.app.getPid(),
r.mAllowWhileInUsePermissionInFgs, policyInfo);
r.isFgsAllowedWIU(), policyInfo);
RuntimeException exception = null;
switch (code) {
case FGS_TYPE_POLICY_CHECK_DEPRECATED: {
@@ -3744,8 +3744,7 @@ public final class ActiveServices {
}
}
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
BackgroundStartPrivileges.NONE, true /* isBindService */,
false /* isStartService */);
BackgroundStartPrivileges.NONE, true /* isBindService */);
if (s.app != null) {
ProcessServiceRecord servicePsr = s.app.mServices;
@@ -7443,54 +7442,80 @@ public final class ActiveServices {
* @param callingUid caller app's uid.
* @param intent intent to start/bind service.
* @param r the service to start.
* @param isStartService True if it's called from Context.startService().
* False if it's called from Context.startForegroundService() or
* Service.startForeground().
* @param isBindService True if it's called from bindService().
* @return true if allow, false otherwise.
*/
private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService,
boolean isStartService) {
// Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
if (!r.mAllowWhileInUsePermissionInFgs) {
// BGFGS start restrictions are disabled. We're allowing while-in-use permissions.
// Note REASON_OTHER since there's no other suitable reason.
r.mAllowWhileInUsePermissionInFgsReason = REASON_OTHER;
}
r.mAllowWhileInUsePermissionInFgs = true;
BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
@ReasonCode int allowWIU;
@ReasonCode int allowStart;
// If called from bindService(), do not update the actual fields, but instead
// keep it in a separate set of fields.
if (isBindService) {
allowWIU = r.mAllowWIUInBindService;
allowStart = r.mAllowStartInBindService;
} else {
allowWIU = r.mAllowWhileInUsePermissionInFgsReasonNoBinding;
allowStart = r.mAllowStartForegroundNoBinding;
}
if (!r.mAllowWhileInUsePermissionInFgs
|| (r.mAllowStartForeground == REASON_DENIED)) {
// Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
if (allowWIU == REASON_DENIED) {
// BGFGS start restrictions are disabled. We're allowing while-in-use permissions.
// Note REASON_OTHER since there's no other suitable reason.
allowWIU = REASON_OTHER;
}
}
if ((allowWIU == REASON_DENIED)
|| (allowStart == REASON_DENIED)) {
@ReasonCode final int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges);
// We store them to compare the old and new while-in-use logics to each other.
// (They're not used for any other purposes.)
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse;
if (allowWIU == REASON_DENIED) {
allowWIU = allowWhileInUse;
}
if (r.mAllowStartForeground == REASON_DENIED) {
r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked(
if (allowStart == REASON_DENIED) {
allowStart = shouldAllowFgsStartForegroundWithBindingCheckLocked(
allowWhileInUse, callingPackage, callingPid, callingUid, intent, r,
backgroundStartPrivileges, isBindService);
}
}
if (isBindService) {
r.mAllowWIUInBindService = allowWIU;
r.mAllowStartInBindService = allowStart;
} else {
r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU;
r.mAllowStartForegroundNoBinding = allowStart;
// Also do a binding client check, unless called from bindService().
if (r.mAllowWIUByBindings == REASON_DENIED) {
r.mAllowWIUByBindings =
shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid);
}
if (r.mAllowStartByBindings == REASON_DENIED) {
r.mAllowStartByBindings = r.mAllowWIUByBindings;
}
}
}
/**
* Reset various while-in-use and BFSL related information.
*/
void resetFgsRestrictionLocked(ServiceRecord r) {
r.mAllowWhileInUsePermissionInFgs = false;
r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
r.mAllowStartForeground = REASON_DENIED;
r.clearFgsAllowWIU();
r.clearFgsAllowStart();
r.mInfoAllowStartForeground = null;
r.mInfoTempFgsAllowListReason = null;
r.mLoggedInfoAllowStartForeground = false;
r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs);
r.updateAllowUiJobScheduling(r.isFgsAllowedWIU());
}
boolean canStartForegroundServiceLocked(int callingPid, int callingUid, String callingPackage) {
@@ -8062,10 +8087,10 @@ public final class ActiveServices {
*/
if (!r.mLoggedInfoAllowStartForeground) {
final String msg = "Background started FGS: "
+ ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
+ (r.isFgsAllowedStart() ? "Allowed " : "Disallowed ")
+ r.mInfoAllowStartForeground
+ (r.isShortFgs() ? " (Called on SHORT_SERVICE)" : "");
if (r.mAllowStartForeground != REASON_DENIED) {
if (r.isFgsAllowedStart()) {
if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
mAm.mConstants.mFgsStartAllowedLogSampleRate)) {
Slog.wtfQuiet(TAG, msg);
@@ -8105,8 +8130,8 @@ public final class ActiveServices {
allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgsAtEntering;
fgsStartReasonCode = r.mAllowStartForegroundAtEntering;
} else {
allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgs;
fgsStartReasonCode = r.mAllowStartForeground;
allowWhileInUsePermissionInFgs = r.isFgsAllowedWIU();
fgsStartReasonCode = r.getFgsAllowStart();
}
final int callerTargetSdkVersion = r.mRecentCallerApplicationInfo != null
? r.mRecentCallerApplicationInfo.targetSdkVersion : 0;
@@ -8295,8 +8320,7 @@ public final class ActiveServices {
r.mFgsEnterTime = SystemClock.uptimeMillis();
r.foregroundServiceType = options.mForegroundServiceTypes;
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
BackgroundStartPrivileges.NONE, false /* isBindService */,
false /* isStartService */);
BackgroundStartPrivileges.NONE, false /* isBindService */);
final ProcessServiceRecord psr = callerApp.mServices;
final boolean newService = psr.startService(r);
// updateOomAdj.

View File

@@ -479,8 +479,8 @@ public class ForegroundServiceTypeLoggerModule {
r.appInfo.uid,
r.shortInstanceName,
fgsState, // FGS State
r.mAllowWhileInUsePermissionInFgs, // allowWhileInUsePermissionInFgs
r.mAllowStartForeground, // fgsStartReasonCode
r.isFgsAllowedWIU(), // allowWhileInUsePermissionInFgs
r.getFgsAllowStart(), // fgsStartReasonCode
r.appInfo.targetSdkVersion,
r.mRecentCallingUid,
0, // callerTargetSdkVersion

View File

@@ -2222,7 +2222,7 @@ public class OomAdjuster {
if (s.isForeground) {
final int fgsType = s.foregroundServiceType;
if (s.mAllowWhileInUsePermissionInFgs) {
if (s.isFgsAllowedWIU()) {
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;

View File

@@ -21,9 +21,11 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.INVALID_UID;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.ActiveServices.TAG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -172,11 +174,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
private BackgroundStartPrivileges mBackgroundStartPrivilegesByStartMerged =
BackgroundStartPrivileges.NONE;
// allow while-in-use permissions in foreground service or not.
// Reason code for allow while-in-use permissions in foreground service.
// If it's not DENIED, while-in-use permissions are allowed.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@PowerExemptionManager.ReasonCode
int mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
int mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED;
// A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state.
boolean mAllowWhileInUsePermissionInFgsAtEntering;
@@ -205,15 +207,114 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// allow the service becomes foreground service? Service started from background may not be
// allowed to become a foreground service.
@PowerExemptionManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int mAllowStartForegroundNoBinding = REASON_DENIED;
// A copy of mAllowStartForeground's value when the service is entering FGS state.
@PowerExemptionManager.ReasonCode int mAllowStartForegroundAtEntering = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int mAllowStartForegroundAtEntering = REASON_DENIED;
// Debug info why mAllowStartForeground is allowed or denied.
String mInfoAllowStartForeground;
// Debug info if mAllowStartForeground is allowed because of a temp-allowlist.
ActivityManagerService.FgsTempAllowListItem mInfoTempFgsAllowListReason;
// Is the same mInfoAllowStartForeground string has been logged before? Used for dedup.
boolean mLoggedInfoAllowStartForeground;
@PowerExemptionManager.ReasonCode
int mAllowWIUInBindService = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int mAllowWIUByBindings = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int mAllowStartInBindService = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int mAllowStartByBindings = REASON_DENIED;
@PowerExemptionManager.ReasonCode
int getFgsAllowWIU() {
return mAllowWhileInUsePermissionInFgsReasonNoBinding != REASON_DENIED
? mAllowWhileInUsePermissionInFgsReasonNoBinding
: mAllowWIUInBindService;
}
boolean isFgsAllowedWIU() {
return getFgsAllowWIU() != REASON_DENIED;
}
@PowerExemptionManager.ReasonCode
int getFgsAllowStart() {
return mAllowStartForegroundNoBinding != REASON_DENIED
? mAllowStartForegroundNoBinding
: mAllowStartInBindService;
}
boolean isFgsAllowedStart() {
return getFgsAllowStart() != REASON_DENIED;
}
void clearFgsAllowWIU() {
mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED;
mAllowWIUInBindService = REASON_DENIED;
mAllowWIUByBindings = REASON_DENIED;
}
void clearFgsAllowStart() {
mAllowStartForegroundNoBinding = REASON_DENIED;
mAllowStartInBindService = REASON_DENIED;
mAllowStartByBindings = REASON_DENIED;
}
@PowerExemptionManager.ReasonCode
int reasonOr(@PowerExemptionManager.ReasonCode int first,
@PowerExemptionManager.ReasonCode int second) {
return first != REASON_DENIED ? first : second;
}
boolean allowedChanged(@PowerExemptionManager.ReasonCode int first,
@PowerExemptionManager.ReasonCode int second) {
return (first == REASON_DENIED) != (second == REASON_DENIED);
}
String changeMessage(@PowerExemptionManager.ReasonCode int first,
@PowerExemptionManager.ReasonCode int second) {
return reasonOr(first, second) == REASON_DENIED ? "DENIED"
: ("ALLOWED ("
+ reasonCodeToString(first)
+ "+"
+ reasonCodeToString(second)
+ ")");
}
void maybeLogFgsLogicChange() {
final int origWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding,
mAllowWIUInBindService);
final int newWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding,
mAllowWIUByBindings);
final int origStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartInBindService);
final int newStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartByBindings);
final boolean wiuChanged = allowedChanged(origWiu, newWiu);
final boolean startChanged = allowedChanged(origStart, newStart);
if (!wiuChanged && !startChanged) {
return;
}
final String message = "FGS logic changed:"
+ (wiuChanged ? " [WIU changed]" : "")
+ (startChanged ? " [BFSL changed]" : "")
+ " OW:" // Orig-WIU
+ changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding,
mAllowWIUInBindService)
+ " NW:" // New-WIU
+ changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding, mAllowWIUByBindings)
+ " OS:" // Orig-start
+ changeMessage(mAllowStartForegroundNoBinding, mAllowStartInBindService)
+ " NS:" // New-start
+ changeMessage(mAllowStartForegroundNoBinding, mAllowStartByBindings);
Slog.wtf(TAG_SERVICE, message);
}
// The number of times Service.startForeground() is called, after this service record is
// created. (i.e. due to "bound" or "start".) It never decreases, even when stopForeground()
// is called.
@@ -502,7 +603,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
ProtoUtils.toDuration(proto, ServiceRecordProto.RESTART_TIME, restartTime, now);
proto.write(ServiceRecordProto.CREATED_FROM_FG, createdFromFg);
proto.write(ServiceRecordProto.ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS,
mAllowWhileInUsePermissionInFgs);
isFgsAllowedWIU());
if (startRequested || delayedStop || lastStartId != 0) {
long startToken = proto.start(ServiceRecordProto.START);
@@ -618,7 +719,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.println(mBackgroundStartPrivilegesByStartMerged);
}
pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowWhileInUsePermissionInFgsReason));
pw.println(PowerExemptionManager.reasonCodeToString(
mAllowWhileInUsePermissionInFgsReasonNoBinding));
pw.print(prefix); pw.print("mAllowWIUInBindService=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUInBindService));
pw.print(prefix); pw.print("mAllowWIUByBindings=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUByBindings));
pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling);
pw.print(prefix); pw.print("recentCallingPackage=");
@@ -626,7 +733,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.print(prefix); pw.print("recentCallingUid=");
pw.println(mRecentCallingUid);
pw.print(prefix); pw.print("allowStartForeground=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForeground));
pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForegroundNoBinding));
pw.print(prefix); pw.print("mAllowStartInBindService=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartInBindService));
pw.print(prefix); pw.print("mAllowStartByBindings=");
pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartByBindings));
pw.print(prefix); pw.print("startForegroundCount=");
pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("infoAllowStartForeground=");