diff options
author | Hui Yu <huiyu@google.com> | 2022-02-09 06:29:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2022-02-09 06:29:23 +0000 |
commit | fc6fe37018843a55520459a21ed87fcdd02c8c41 (patch) | |
tree | 99b5c3cd77437482496b3e032a711e54b19171b8 | |
parent | e9a8a931b200a048a56ed4f787404fcdc5ddfba1 (diff) | |
parent | d5abccff3c61b81aeb67d6fda10d9a27d3e326bd (diff) | |
download | base-fc6fe37018843a55520459a21ed87fcdd02c8c41.tar.gz |
Merge "BG-FGS-start while-in-use permission restriction improvement." into rvc-dev
3 files changed, 112 insertions, 21 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index b8de4a759b60..c82a45feb682 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -734,11 +734,8 @@ public final class ActiveServices { } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); - if (!r.mAllowWhileInUsePermissionInFgs) { - r.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid, - callingUid, service, r, allowBackgroundActivityStarts); - } + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, r, + allowBackgroundActivityStarts); return cmp; } @@ -1400,14 +1397,6 @@ public final class ActiveServices { + String.format("0x%08X", manifestType) + " in service element of manifest file"); } - // 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) { - Slog.w(TAG, - "Foreground service started from background can not have " - + "location/camera/microphone access: service " - + r.shortInstanceName); - } } boolean alreadyStartedOp = false; boolean stopProcStatsOp = false; @@ -1455,6 +1444,56 @@ public final class ActiveServices { ignoreForeground = true; } + if (!ignoreForeground) { + if (r.mStartForegroundCount == 0) { + /* + If the service was started with startService(), not + startForegroundService(), and if startForeground() isn't called within + mFgsStartForegroundTimeoutMs, then we check the state of the app + (who owns the service, which is the app that called startForeground()) + again. If the app is in the foreground, or in any other cases where + FGS-starts are allowed, then we still allow the FGS to be started. + Otherwise, startForeground() would fail. + + If the service was started with startForegroundService(), then the service + must call startForeground() within a timeout anyway, so we don't need this + check. + */ + if (!r.fgRequired) { + final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime; + if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) { + resetFgsRestrictionLocked(r); + setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid, + r.appInfo.uid, r, false); + EventLog.writeEvent(0x534e4554, "183147114", + r.appInfo.uid, + "call setFgsRestrictionLocked again due to " + + "startForegroundTimeout"); + } + } + } else if (r.mStartForegroundCount >= 1) { + // The second or later time startForeground() is called after service is + // started. Check for app state again. + final long delayMs = SystemClock.elapsedRealtime() - + r.mLastSetFgsRestrictionTime; + if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) { + setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid, + r.appInfo.uid, r, false); + EventLog.writeEvent(0x534e4554, "183147114", r.appInfo.uid, + "call setFgsRestrictionLocked for " + + (r.mStartForegroundCount + 1) + "th startForeground"); + } + } + // 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) { + Slog.w(TAG, + "Foreground service started from background can not have " + + "location/camera/microphone access: service " + + r.shortInstanceName); + } + } + // Apps under strict background restrictions simply don't get to have foreground // services, so now that we've enforced the startForegroundService() contract // we only do the machinery of making the service foreground when the app @@ -1490,6 +1529,7 @@ public final class ActiveServices { active.mNumActive++; } r.isForeground = true; + r.mStartForegroundCount++; if (!stopProcStatsOp) { ServiceState stracker = r.getTracker(); if (stracker != null) { @@ -1548,6 +1588,7 @@ public final class ActiveServices { decActiveForegroundAppLocked(smap, r); } r.isForeground = false; + resetFgsRestrictionLocked(r); ServiceState stracker = r.getTracker(); if (stracker != null) { stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), @@ -2107,12 +2148,7 @@ public final class ActiveServices { } } - if (!s.mAllowWhileInUsePermissionInFgs) { - s.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, - callingPid, callingUid, - service, s, false); - } + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, s, false); if (s.app != null) { if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { @@ -3408,7 +3444,7 @@ public final class ActiveServices { r.isForeground = false; r.foregroundId = 0; r.foregroundNoti = null; - r.mAllowWhileInUsePermissionInFgs = false; + resetFgsRestrictionLocked(r); // Clear start entries. r.clearDeliveredStartsLocked(); @@ -4889,7 +4925,7 @@ public final class ActiveServices { * @return true if allow, false otherwise. */ private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage, - int callingPid, int callingUid, Intent intent, ServiceRecord r, + int callingPid, int callingUid, ServiceRecord r, boolean allowBackgroundActivityStarts) { // Is the background FGS start restriction turned on? if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { @@ -4960,4 +4996,33 @@ public final class ActiveServices { } return false; } + + boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid, + String callingPackage) { + return shouldAllowWhileInUsePermissionInFgsLocked( + callingPackage, callingPid, callingUid, null, false); + } + + /** + * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground + * service or not. while-in-use permissions in FGS started from background might be restricted. + * @param callingPackage caller app's package name. + * @param callingUid caller app's uid. + * @param r the service to start. + * @return true if allow, false otherwise. + */ + private void setFgsRestrictionLocked(String callingPackage, + int callingPid, int callingUid, ServiceRecord r, + boolean allowBackgroundActivityStarts) { + r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime(); + if (!r.mAllowWhileInUsePermissionInFgs) { + r.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked( + callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts); + } + } + + private void resetFgsRestrictionLocked(ServiceRecord r) { + r.mAllowWhileInUsePermissionInFgs = false; + r.mLastSetFgsRestrictionTime = 0; + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 135ac9a7846e..cc1bda76812c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -87,6 +87,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_PROCESS_START_ASYNC = "process_start_async"; static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time"; static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration"; + static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout"; static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; @@ -120,6 +121,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final boolean DEFAULT_PROCESS_START_ASYNC = true; private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000; private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000; + private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000; private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000; // Flag stored in the DeviceConfig API. @@ -272,6 +274,12 @@ final class ActivityManagerConstants extends ContentObserver { // this long. public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION; + /** + * When service started from background, before the timeout it can be promoted to FGS by calling + * Service.startForeground(). + */ + volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS; + // Indicates whether the activity starts logging is enabled. // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED volatile boolean mFlagActivityStartsLoggingEnabled; @@ -415,6 +423,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_MIN_ASSOC_LOG_DURATION: updateMinAssocLogDuration(); break; + case KEY_FGS_START_FOREGROUND_TIMEOUT: + updateFgsStartForegroundTimeout(); + break; default: break; } @@ -687,6 +698,13 @@ final class ActivityManagerConstants extends ContentObserver { /* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION); } + private void updateFgsStartForegroundTimeout() { + mFgsStartForegroundTimeoutMs = DeviceConfig.getLong( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_FGS_START_FOREGROUND_TIMEOUT, + DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS); + } + void dump(PrintWriter pw) { pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) " + Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":"); @@ -759,6 +777,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray())); pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("="); pw.println(MIN_ASSOC_LOG_DURATION); + pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("="); + pw.println(mFgsStartForegroundTimeoutMs); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 9c96e6e02566..5583c5129287 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -138,6 +138,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. boolean mAllowWhileInUsePermissionInFgs; + // The number of times Service.startForeground() is called; + int mStartForegroundCount; + // Last time mAllowWhileInUsePermissionInFgs is set. + long mLastSetFgsRestrictionTime; // the most recent package that start/bind this service. String mRecentCallingPackage; @@ -400,6 +404,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs="); pw.println(mAllowWhileInUsePermissionInFgs); + pw.print(prefix); pw.print("startForegroundCount="); + pw.println(mStartForegroundCount); pw.print(prefix); pw.print("recentCallingPackage="); pw.println(mRecentCallingPackage); if (delayed) { |