summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Makoto Onuki <omakoto@google.com> 2021-05-11 15:55:14 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-05-11 15:55:14 +0000
commit987f9040723f4c433c7084cb2d003c00774467c8 (patch)
tree4337ebd7d89eef1f30c530fe51cdc4f879baa42a
parent3ee3029e96912b267fb11e357fd9551631ceda2c (diff)
parent619c5a46d8e20e29c320c35a2b4dea45bca0bc5d (diff)
Merge "Implement requestForegroundServiceExemption, without enabling it" into sc-dev
-rw-r--r--apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java6
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java20
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java4
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java2
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java12
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java7
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java6
-rw-r--r--core/res/res/values/attrs_manifest.xml7
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java20
12 files changed, 96 insertions, 3 deletions
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 9dd1296d681c..42e953b72a69 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -344,6 +344,9 @@ public class PowerExemptionManager {
*/
public static final int REASON_MEDIA_SESSION_CALLBACK = 317;
+ /** @hide The app requests out-out. */
+ public static final int REASON_OPT_OUT_REQUESTED = 1000;
+
/**
* The list of BG-FGS-Launch and temp-allow-list reason code.
* @hide
@@ -411,6 +414,7 @@ public class PowerExemptionManager {
REASON_EVENT_MMS,
REASON_SHELL,
REASON_MEDIA_SESSION_CALLBACK,
+ REASON_OPT_OUT_REQUESTED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ReasonCode {}
@@ -709,6 +713,8 @@ public class PowerExemptionManager {
return "SHELL";
case REASON_MEDIA_SESSION_CALLBACK:
return "MEDIA_SESSION_CALLBACK";
+ case REASON_OPT_OUT_REQUESTED:
+ return "REASON_OPT_OUT_REQUESTED";
default:
return "(unknown:" + reasonCode + ")";
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index edceac3fed74..f4581079e7e8 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -50,6 +50,10 @@ package android {
field public static final String UNDEFINED = "android.permission-group.UNDEFINED";
}
+ public static final class R.attr {
+ field public static final int requestForegroundServiceExemption;
+ }
+
public static final class R.bool {
field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
@@ -806,6 +810,7 @@ package android.content.pm {
}
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method public boolean hasRequestForegroundServiceExemption();
method public boolean isPrivilegedApp();
method public boolean isSystemApp();
field public static final int PRIVATE_FLAG_PRIVILEGED = 8; // 0x8
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a3e0473e39cc..8b0e99236806 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -778,9 +778,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_EXT_PROFILEABLE = 1 << 0;
+ /**
+ * Value for {@link #privateFlagsExt}: whether this application has requested
+ * exemption from the foreground service restriction introduced in S
+ * (https://developer.android.com/about/versions/12/foreground-services).
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1 << 1;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
PRIVATE_FLAG_EXT_PROFILEABLE,
+ PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlagsExt {}
@@ -2445,6 +2454,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/**
+ * @return whether the app has requested exemption from the foreground service restrictions.
+ * This does not take any affect for now.
+ * @hide
+ */
+ @TestApi
+ public boolean hasRequestForegroundServiceExemption() {
+ return (privateFlagsExt
+ & ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION) != 0;
+ }
+
+ /**
* @hide
*/
@Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 980f10d5e688..75fa1c1b45d7 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -806,7 +806,9 @@ public class PackageInfoWithoutStateUtils {
public static int appInfoPrivateFlagsExt(ParsingPackageRead pkg) {
// @formatter:off
int privateFlagsExt =
- flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE);
+ flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
+ | flag(pkg.hasRequestForegroundServiceExemption(),
+ ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION);
// @formatter:on
return privateFlagsExt;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index cea50cbaf234..2413e6d99f5f 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -338,6 +338,8 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setTheme(int theme);
+ ParsingPackage setRequestForegroundServiceExemption(boolean requestForegroundServiceExemption);
+
ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
ParsingPackage setUse32BitAbi(boolean use32BitAbi);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 711488670f56..b0342aa95fc9 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -464,6 +464,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
CROSS_PROFILE,
ENABLED,
DISALLOW_PROFILING,
+ REQUEST_FOREGROUND_SERVICE_EXEMPTION,
})
public @interface Values {}
private static final long EXTERNAL_STORAGE = 1L;
@@ -512,6 +513,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private static final long CROSS_PROFILE = 1L << 43;
private static final long ENABLED = 1L << 44;
private static final long DISALLOW_PROFILING = 1L << 45;
+ private static final long REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1L << 46;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2199,6 +2201,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
+ public boolean hasRequestForegroundServiceExemption() {
+ return getBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2420,6 +2427,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
+ public ParsingPackageImpl setRequestForegroundServiceExemption(boolean value) {
+ return setBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION, value);
+ }
+
+ @Override
public ParsingPackageImpl setUiOptions(int value) {
uiOptions = value;
return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 1c2c59f7504c..35a2b9aeb338 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -906,10 +906,15 @@ public interface ParsingPackageRead extends Parcelable {
*/
@ApplicationInfo.NativeHeapZeroInitialized
int getNativeHeapZeroInitialized();
-
@Nullable
Boolean hasRequestRawExternalStorageAccess();
+ /**
+ * @see ApplicationInfo#hasRequestForegroundServiceExemption()
+ * @see R.styleable#AndroidManifest_requestForegroundServiceExemption
+ */
+ boolean hasRequestForegroundServiceExemption();
+
// TODO(b/135203078): Hide and enforce going through PackageInfoUtils
ApplicationInfo toAppInfoWithoutState();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 22d75ef93137..5d74e7452a0b 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2033,6 +2033,12 @@ public class ParsingPackageUtils {
.AndroidManifestApplication_requestRawExternalStorageAccess,
false));
}
+ if (sa.hasValue(
+ R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) {
+ pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable
+ .AndroidManifestApplication_requestForegroundServiceExemption,
+ false));
+ }
} finally {
sa.recycle();
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c5f4fd1a898a..638627422eff 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1954,6 +1954,13 @@
See the <a href="{@docRoot}about/versions/12/backup-restore">Changes in backup and restore</a>
document for the format of the XML file.-->
<attr name="dataExtractionRules" format="reference"/>
+
+ <!-- @hide Request exemption from the foreground service restrictions introduced in S
+ (https://developer.android.com/about/versions/12/foreground-services)
+ Note the framework <b>ignores</b> this attribute at this time. Once apps target S or above,
+ there's no way to be exempted (without using a privileged permission).
+ -->
+ <attr name="requestForegroundServiceExemption" format="boolean" />
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 500a9dae6554..f7a99309ec5a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3099,6 +3099,8 @@
<public name="durationBetweenRequestsMillis" />
<public name="showInInputMethodPicker" />
<public name="effectColor" />
+ <!-- @hide @TestApi -->
+ <public name="requestForegroundServiceExemption" />
</staging-public-group>
<staging-public-group type="drawable" first-id="0x010800b5">
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1bd53ae24730..aadb25c7ef7f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -24,6 +24,7 @@ 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_VISIBILITY_GRACE_PERIOD;
+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_TEMP_ALLOWED_WHILE_IN_USE;
@@ -5874,7 +5875,12 @@ public final class ActiveServices {
ret = REASON_OP_ACTIVATE_PLATFORM_VPN;
}
}
-
+ if (ret == REASON_DENIED) {
+ if (mAm.mConstants.mFgsAllowOptOut
+ && targetService.appInfo.hasRequestForegroundServiceExemption()) {
+ ret = REASON_OPT_OUT_REQUESTED;
+ }
+ }
return ret;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 09795855ac27..0fff8be70574 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -110,6 +110,7 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
static final String KEY_KILL_FAS_CACHED_IDLE = "kill_fas_cached_idle";
+ static final String KEY_FGS_ALLOW_OPT_OUT = "fgs_allow_opt_out";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -161,6 +162,7 @@ final class ActivityManagerConstants extends ContentObserver {
*/
private static final int
DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = 1;
+ private static final boolean DEFAULT_FGS_ALLOW_OPT_OUT = false;
// Flag stored in the DeviceConfig API.
/**
@@ -493,6 +495,12 @@ final class ActivityManagerConstants extends ContentObserver {
*/
volatile boolean mKillForceAppStandByAndCachedIdle = DEFAULT_KILL_FAS_CACHED_IDLE;
+ /**
+ * Whether to allow "opt-out" from the foreground service restrictions.
+ * (https://developer.android.com/about/versions/12/foreground-services)
+ */
+ volatile boolean mFgsAllowOptOut = DEFAULT_FGS_ALLOW_OPT_OUT;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -701,6 +709,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_KILL_FAS_CACHED_IDLE:
updateKillFasCachedIdle();
break;
+ case KEY_FGS_ALLOW_OPT_OUT:
+ updateFgsAllowOptOut();
+ break;
default:
break;
}
@@ -1040,6 +1051,13 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_KILL_FAS_CACHED_IDLE);
}
+ private void updateFgsAllowOptOut() {
+ mFgsAllowOptOut = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_ALLOW_OPT_OUT,
+ DEFAULT_FGS_ALLOW_OPT_OUT);
+ }
+
private void updateImperceptibleKillExemptions() {
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1260,6 +1278,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.print("="); pw.println(mFgsAtomSampleRate);
pw.print(" "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR);
pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
+ pw.print(" "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
+ pw.print("="); pw.println(mFgsAllowOptOut);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {