Skip to content

Commit e39d903

Browse files
Hui YuBayerischeMotorenWerke
authored andcommitted
BG-FGS-start while-in-use permission restriction improvement.
[This is a resbumit, previous fix ag/I0aca484e5a0dd051bbeac379d30b0fb4ecfa2da0 was reverted because the incorrect resetFgsRestrictionLocked() call] Foreground service started from background shall not have while-in-use access like location/camera/microphone. Previously we set mAllowWhileInUsePermissionInFgs only at service start by startService() or bindService() command. But after service start, the Service.startForeground() call may be some time later and at that time the caller may not be in the foreground any more. This CL will add further restriction on that. 1. If the first Service.startForeground() call is more than 10 seconds (can be configured by DeviceConfig key "fgs_start_foreground_timeout") after the Context.startService() call, check the service's app proc state and set mAllowWhileInUsePermissionInFgs again. 2. At Service.stopForeground() call, mAllowWhileInUsePermissionInFgs should be reset to false so FGS while-in-use permission is not allowed. 3. After Context.startForegroundService()(or Context.startService()) -> Service.startForeground() -> Service.stopForeground(), the second or more times Service.startForeground() is called, check the service's app proc state and set mAllowWhileInUsePermissionInFgs again. This CL is the backport of ag/Idc88f274c7a323d175d65bb47eca041772ae9bb7 from S branch. Bug: 183147114 Bug: 183204439 Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testStartForegroundTimeout Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testSecondStartForeground Change-Id: Ie8712b8efe85aa8a6769b811c85a29c4013e58b9 Merged-In: Idc88f274c7a323d175d65bb47eca041772ae9bb7 (cherry picked from commit d5abccf) Merged-In:Ie8712b8efe85aa8a6769b811c85a29c4013e58b9
1 parent 1321616 commit e39d903

3 files changed

Lines changed: 112 additions & 21 deletions

File tree

services/core/java/com/android/server/am/ActiveServices.java

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -734,11 +734,8 @@ ComponentName startServiceLocked(IApplicationThread caller, Intent service, Stri
734734
}
735735
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
736736

737-
if (!r.mAllowWhileInUsePermissionInFgs) {
738-
r.mAllowWhileInUsePermissionInFgs =
739-
shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
740-
callingUid, service, r, allowBackgroundActivityStarts);
741-
}
737+
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, r,
738+
allowBackgroundActivityStarts);
742739

743740
return cmp;
744741
}
@@ -1411,14 +1408,6 @@ private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
14111408
+ String.format("0x%08X", manifestType)
14121409
+ " in service element of manifest file");
14131410
}
1414-
// If the foreground service is not started from TOP process, do not allow it to
1415-
// have while-in-use location/camera/microphone access.
1416-
if (!r.mAllowWhileInUsePermissionInFgs) {
1417-
Slog.w(TAG,
1418-
"Foreground service started from background can not have "
1419-
+ "location/camera/microphone access: service "
1420-
+ r.shortInstanceName);
1421-
}
14221411
}
14231412
boolean alreadyStartedOp = false;
14241413
boolean stopProcStatsOp = false;
@@ -1466,6 +1455,56 @@ && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
14661455
ignoreForeground = true;
14671456
}
14681457

1458+
if (!ignoreForeground) {
1459+
if (r.mStartForegroundCount == 0) {
1460+
/*
1461+
If the service was started with startService(), not
1462+
startForegroundService(), and if startForeground() isn't called within
1463+
mFgsStartForegroundTimeoutMs, then we check the state of the app
1464+
(who owns the service, which is the app that called startForeground())
1465+
again. If the app is in the foreground, or in any other cases where
1466+
FGS-starts are allowed, then we still allow the FGS to be started.
1467+
Otherwise, startForeground() would fail.
1468+
1469+
If the service was started with startForegroundService(), then the service
1470+
must call startForeground() within a timeout anyway, so we don't need this
1471+
check.
1472+
*/
1473+
if (!r.fgRequired) {
1474+
final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime;
1475+
if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
1476+
resetFgsRestrictionLocked(r);
1477+
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
1478+
r.appInfo.uid, r, false);
1479+
EventLog.writeEvent(0x534e4554, "183147114",
1480+
r.appInfo.uid,
1481+
"call setFgsRestrictionLocked again due to "
1482+
+ "startForegroundTimeout");
1483+
}
1484+
}
1485+
} else if (r.mStartForegroundCount >= 1) {
1486+
// The second or later time startForeground() is called after service is
1487+
// started. Check for app state again.
1488+
final long delayMs = SystemClock.elapsedRealtime() -
1489+
r.mLastSetFgsRestrictionTime;
1490+
if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
1491+
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
1492+
r.appInfo.uid, r, false);
1493+
EventLog.writeEvent(0x534e4554, "183147114", r.appInfo.uid,
1494+
"call setFgsRestrictionLocked for "
1495+
+ (r.mStartForegroundCount + 1) + "th startForeground");
1496+
}
1497+
}
1498+
// If the foreground service is not started from TOP process, do not allow it to
1499+
// have while-in-use location/camera/microphone access.
1500+
if (!r.mAllowWhileInUsePermissionInFgs) {
1501+
Slog.w(TAG,
1502+
"Foreground service started from background can not have "
1503+
+ "location/camera/microphone access: service "
1504+
+ r.shortInstanceName);
1505+
}
1506+
}
1507+
14691508
// Apps under strict background restrictions simply don't get to have foreground
14701509
// services, so now that we've enforced the startForegroundService() contract
14711510
// we only do the machinery of making the service foreground when the app
@@ -1501,6 +1540,7 @@ && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
15011540
active.mNumActive++;
15021541
}
15031542
r.isForeground = true;
1543+
r.mStartForegroundCount++;
15041544
if (!stopProcStatsOp) {
15051545
ServiceState stracker = r.getTracker();
15061546
if (stracker != null) {
@@ -1559,6 +1599,7 @@ && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
15591599
decActiveForegroundAppLocked(smap, r);
15601600
}
15611601
r.isForeground = false;
1602+
resetFgsRestrictionLocked(r);
15621603
ServiceState stracker = r.getTracker();
15631604
if (stracker != null) {
15641605
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2118,12 +2159,7 @@ public void run() {
21182159
}
21192160
}
21202161

2121-
if (!s.mAllowWhileInUsePermissionInFgs) {
2122-
s.mAllowWhileInUsePermissionInFgs =
2123-
shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
2124-
callingPid, callingUid,
2125-
service, s, false);
2126-
}
2162+
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, s, false);
21272163

21282164
if (s.app != null) {
21292165
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -3419,7 +3455,7 @@ private final void bringDownServiceLocked(ServiceRecord r) {
34193455
r.isForeground = false;
34203456
r.foregroundId = 0;
34213457
r.foregroundNoti = null;
3422-
r.mAllowWhileInUsePermissionInFgs = false;
3458+
resetFgsRestrictionLocked(r);
34233459

34243460
// Clear start entries.
34253461
r.clearDeliveredStartsLocked();
@@ -4900,7 +4936,7 @@ private void dumpService(String prefix, FileDescriptor fd, PrintWriter pw,
49004936
* @return true if allow, false otherwise.
49014937
*/
49024938
private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
4903-
int callingPid, int callingUid, Intent intent, ServiceRecord r,
4939+
int callingPid, int callingUid, ServiceRecord r,
49044940
boolean allowBackgroundActivityStarts) {
49054941
// Is the background FGS start restriction turned on?
49064942
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
@@ -4982,4 +5018,33 @@ private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage
49825018
}
49835019
return false;
49845020
}
5021+
5022+
boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
5023+
String callingPackage) {
5024+
return shouldAllowWhileInUsePermissionInFgsLocked(
5025+
callingPackage, callingPid, callingUid, null, false);
5026+
}
5027+
5028+
/**
5029+
* In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
5030+
* service or not. while-in-use permissions in FGS started from background might be restricted.
5031+
* @param callingPackage caller app's package name.
5032+
* @param callingUid caller app's uid.
5033+
* @param r the service to start.
5034+
* @return true if allow, false otherwise.
5035+
*/
5036+
private void setFgsRestrictionLocked(String callingPackage,
5037+
int callingPid, int callingUid, ServiceRecord r,
5038+
boolean allowBackgroundActivityStarts) {
5039+
r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
5040+
if (!r.mAllowWhileInUsePermissionInFgs) {
5041+
r.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked(
5042+
callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
5043+
}
5044+
}
5045+
5046+
private void resetFgsRestrictionLocked(ServiceRecord r) {
5047+
r.mAllowWhileInUsePermissionInFgs = false;
5048+
r.mLastSetFgsRestrictionTime = 0;
5049+
}
49855050
}

services/core/java/com/android/server/am/ActivityManagerConstants.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ final class ActivityManagerConstants extends ContentObserver {
8888
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
8989
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
9090
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
91+
static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
9192
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
9293

9394
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -121,6 +122,7 @@ final class ActivityManagerConstants extends ContentObserver {
121122
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
122123
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
123124
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
125+
private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
124126
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
125127

126128
// Flag stored in the DeviceConfig API.
@@ -273,6 +275,12 @@ final class ActivityManagerConstants extends ContentObserver {
273275
// this long.
274276
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
275277

278+
/**
279+
* When service started from background, before the timeout it can be promoted to FGS by calling
280+
* Service.startForeground().
281+
*/
282+
volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
283+
276284
// Indicates whether the activity starts logging is enabled.
277285
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
278286
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -421,6 +429,9 @@ public void onPropertiesChanged(Properties properties) {
421429
case KEY_MIN_ASSOC_LOG_DURATION:
422430
updateMinAssocLogDuration();
423431
break;
432+
case KEY_FGS_START_FOREGROUND_TIMEOUT:
433+
updateFgsStartForegroundTimeout();
434+
break;
424435
default:
425436
break;
426437
}
@@ -697,6 +708,13 @@ private void updateMinAssocLogDuration() {
697708
/* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
698709
}
699710

711+
private void updateFgsStartForegroundTimeout() {
712+
mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
713+
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
714+
KEY_FGS_START_FOREGROUND_TIMEOUT,
715+
DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
716+
}
717+
700718
void dump(PrintWriter pw) {
701719
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
702720
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -769,6 +787,8 @@ void dump(PrintWriter pw) {
769787
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
770788
pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
771789
pw.println(MIN_ASSOC_LOG_DURATION);
790+
pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
791+
pw.println(mFgsStartForegroundTimeoutMs);
772792

773793
pw.println();
774794
if (mOverrideMaxCachedProcesses >= 0) {

services/core/java/com/android/server/am/ServiceRecord.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
142142
// allow while-in-use permissions in foreground service or not.
143143
// while-in-use permissions in FGS started from background might be restricted.
144144
boolean mAllowWhileInUsePermissionInFgs;
145+
// The number of times Service.startForeground() is called;
146+
int mStartForegroundCount;
147+
// Last time mAllowWhileInUsePermissionInFgs is set.
148+
long mLastSetFgsRestrictionTime;
145149

146150
// the most recent package that start/bind this service.
147151
String mRecentCallingPackage;
@@ -406,6 +410,8 @@ void dump(PrintWriter pw, String prefix) {
406410
}
407411
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
408412
pw.println(mAllowWhileInUsePermissionInFgs);
413+
pw.print(prefix); pw.print("startForegroundCount=");
414+
pw.println(mStartForegroundCount);
409415
pw.print(prefix); pw.print("recentCallingPackage=");
410416
pw.println(mRecentCallingPackage);
411417
if (delayed) {

0 commit comments

Comments
 (0)