Merge "idmap2: move commands to Result<Unit>"
diff --git a/api/current.txt b/api/current.txt
index 60d99dc..8ff63c0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11676,7 +11676,6 @@
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
- field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
@@ -25699,14 +25698,14 @@
public static class MediaPlayer2.DrmEventCallback {
ctor public MediaPlayer2.DrmEventCallback();
method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
- method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
- method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+ method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
+ method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
}
public static final class MediaPlayer2.DrmInfo {
- method public java.util.Map<java.util.UUID,byte[]> getPssh();
- method public java.util.List<java.util.UUID> getSupportedSchemes();
+ method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh();
+ method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes();
}
public static final class MediaPlayer2.DrmPreparationInfo {
@@ -25714,13 +25713,13 @@
public static final class MediaPlayer2.DrmPreparationInfo.Builder {
ctor public MediaPlayer2.DrmPreparationInfo.Builder();
- method public android.media.MediaPlayer2.DrmPreparationInfo build();
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build();
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
}
public static class MediaPlayer2.EventCallback {
@@ -25751,7 +25750,7 @@
}
public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
- ctor public MediaPlayer2.NoDrmSchemeException(String);
+ ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String);
}
public static class MediaPlayer2.TrackInfo {
@@ -45299,7 +45298,7 @@
field public static final int PHONE_TYPE_GSM = 1; // 0x1
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
- field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+ field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
@@ -53033,7 +53032,7 @@
method public int describeContents();
method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String);
method @Nullable public android.os.Bundle getExtras();
- method @NonNull public android.content.LocusId getLocusId();
+ method @Nullable public android.content.LocusId getLocusId();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureContext> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8c78b21..8a201a1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -186,6 +186,7 @@
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
+ field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -1836,9 +1837,9 @@
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
field public static final int STATUS_FAILURE = 1; // 0x1
@@ -4281,11 +4282,14 @@
package android.net.apf {
- public class ApfCapabilities {
+ public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
method public static boolean getApfDrop8023Frames(android.content.Context);
method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
field public final int apfPacketFormat;
field public final int apfVersionSupported;
field public final int maximumApfProgramSize;
diff --git a/api/test-current.txt b/api/test-current.txt
index c2ee2c3..b86257c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -720,11 +721,11 @@
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+ method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+ method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
field public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis";
@@ -1306,11 +1307,14 @@
package android.net.apf {
- public class ApfCapabilities {
+ public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
method public static boolean getApfDrop8023Frames(android.content.Context);
method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
field public final int apfPacketFormat;
field public final int apfVersionSupported;
field public final int maximumApfProgramSize;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f6cfe48..e8d3293 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -340,4 +340,21 @@
* like persisting database etc.
*/
public abstract void prepareForPossibleShutdown();
+
+ /**
+ * Returns {@code true} if {@code uid} is running a foreground service of a specific
+ * {@code foregroundServiceType}.
+ */
+ public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
+
+ /**
+ * Registers the specified {@code processObserver} to be notified of future changes to
+ * process state.
+ */
+ public abstract void registerProcessObserver(IProcessObserver processObserver);
+
+ /**
+ * Unregisters the specified {@code processObserver}.
+ */
+ public abstract void unregisterProcessObserver(IProcessObserver processObserver);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a226062..7a0639e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3054,9 +3054,9 @@
}
@Override
- public String getContentCaptureServicePackageName() {
+ public String getSystemCaptionsServicePackageName() {
try {
- return mPM.getContentCaptureServicePackageName();
+ return mPM.getSystemCaptionsServicePackageName();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index b436aa2..7be3620 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -19,5 +19,6 @@
/** {@hide} */
oneway interface IProcessObserver {
void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+ void onForegroundServicesChanged(int pid, int uid, int serviceTypes);
void onProcessDied(int pid, int uid);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fd3529b..464e866 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -742,7 +742,7 @@
String getAppPredictionServicePackageName();
- String getContentCaptureServicePackageName();
+ String getSystemCaptionsServicePackageName();
String getIncidentReportApproverPackageName();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 99324ba..2f99879 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2589,14 +2589,6 @@
public static final String FEATURE_PC = "android.hardware.type.pc";
/**
- * Feature for {@link #getSystemAvailableFeatures} and
- * {@link #hasSystemFeature}: This is a foldable device. Properties such as
- * the display size may change in response to being folded.
- */
- @SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
-
- /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/
@@ -6863,9 +6855,9 @@
*
* @hide
*/
- public String getContentCaptureServicePackageName() {
+ public String getSystemCaptionsServicePackageName() {
throw new UnsupportedOperationException(
- "getContentCaptureServicePackageName not implemented in subclass");
+ "getSystemCaptionsServicePackageName not implemented in subclass");
}
/**
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 293c1e4..d54a6fe 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -76,10 +76,12 @@
/**
* Returns a list of all currently available rollbacks.
*
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
@NonNull
public List<RollbackInfo> getAvailableRollbacks() {
try {
@@ -104,10 +106,12 @@
* rolled back from.
*
* @return the recently committed rollbacks
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
try {
return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -190,10 +194,12 @@
* @param statusReceiver where to deliver the results. Intents sent to
* this receiver contain {@link #EXTRA_STATUS}
* and {@link #EXTRA_STATUS_MESSAGE}.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages,
@NonNull IntentSender statusReceiver) {
try {
@@ -210,12 +216,11 @@
* across device reboot, by simulating what happens on reboot without
* actually rebooting the device.
*
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
@TestApi
public void reloadPersistedData() {
try {
@@ -232,12 +237,11 @@
* recently committed rollbacks that contain the given package.
*
* @param packageName the name of the package to expire data for.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
@TestApi
public void expireRollbackForPackage(@NonNull String packageName) {
try {
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index f208724..7873fc0 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -29,15 +29,33 @@
* {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
*/
public class CaptivePortal implements Parcelable {
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the portal was dismissed
+ * and the network should be re-validated.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_DISMISSED = 0;
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the user did not login and
+ * does not want to use the captive portal network.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_UNWANTED = 1;
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the user does not wish to
+ * login but wants to use the captive portal network as-is.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_WANTED_AS_IS = 2;
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index e09fa8f..d6023d7 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,17 +19,20 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.internal.R;
/**
* APF program support capabilities.
*
+ * This class is immutable.
* @hide
*/
@SystemApi
@TestApi
-public class ApfCapabilities {
+public final class ApfCapabilities implements Parcelable {
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
* packet filtering using APF programs.
@@ -53,6 +56,37 @@
this.apfPacketFormat = apfPacketFormat;
}
+ private ApfCapabilities(Parcel in) {
+ apfVersionSupported = in.readInt();
+ maximumApfProgramSize = in.readInt();
+ apfPacketFormat = in.readInt();
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(apfVersionSupported);
+ dest.writeInt(maximumApfProgramSize);
+ dest.writeInt(apfPacketFormat);
+ }
+
+ public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
+ @Override
+ public ApfCapabilities createFromParcel(Parcel in) {
+ return new ApfCapabilities(in);
+ }
+
+ @Override
+ public ApfCapabilities[] newArray(int size) {
+ return new ApfCapabilities[size];
+ }
+ };
+
@Override
public String toString() {
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 6432c24..b82e517 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -935,12 +935,16 @@
}
/**
- * Returns the value associated with the given key, or null if
- * no mapping of the desired type exists for the given key or a null
+ * Returns the value associated with the given key, or {@code null} if
+ * no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return a Parcelable value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return a Parcelable value, or {@code null}
*/
@Nullable
public <T extends Parcelable> T getParcelable(@Nullable String key) {
@@ -958,12 +962,16 @@
}
/**
- * Returns the value associated with the given key, or null if
+ * Returns the value associated with the given key, or {@code null} if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return a Parcelable[] value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return a Parcelable[] value, or {@code null}
*/
@Nullable
public Parcelable[] getParcelableArray(@Nullable String key) {
@@ -981,12 +989,16 @@
}
/**
- * Returns the value associated with the given key, or null if
- * no mapping of the desired type exists for the given key or a null
+ * Returns the value associated with the given key, or {@code null} if
+ * no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return an ArrayList<T> value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return an ArrayList<T> value, or {@code null}
*/
@Nullable
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 1549c45..d505f02 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -25,6 +25,7 @@
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.util.Log;
/**
* Base class for a search indexable provider. Such provider offers data to be indexed either
@@ -112,19 +113,26 @@
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
- switch (mMatcher.match(uri)) {
- case MATCH_RES_CODE:
- return queryXmlResources(null);
- case MATCH_RAW_CODE:
- return queryRawData(null);
- case MATCH_NON_INDEXABLE_KEYS_CODE:
- return queryNonIndexableKeys(null);
- case MATCH_SITE_MAP_PAIRS_CODE:
- return querySiteMapPairs();
- case MATCH_SLICE_URI_PAIRS_CODE:
- return querySliceUriPairs();
- default:
- throw new UnsupportedOperationException("Unknown Uri " + uri);
+ try {
+ switch (mMatcher.match(uri)) {
+ case MATCH_RES_CODE:
+ return queryXmlResources(null);
+ case MATCH_RAW_CODE:
+ return queryRawData(null);
+ case MATCH_NON_INDEXABLE_KEYS_CODE:
+ return queryNonIndexableKeys(null);
+ case MATCH_SITE_MAP_PAIRS_CODE:
+ return querySiteMapPairs();
+ case MATCH_SLICE_URI_PAIRS_CODE:
+ return querySliceUriPairs();
+ default:
+ throw new UnsupportedOperationException("Unknown Uri " + uri);
+ }
+ } catch (UnsupportedOperationException e) {
+ throw e;
+ } catch (Exception e) {
+ Log.e(TAG, "Provider querying exception:", e);
+ return null;
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dd38373..b8174e6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12598,8 +12598,9 @@
/**
* Battery level [1-100] at which low power mode automatically turns on.
- * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
- * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
+ * If 0, it will not automatically turn on. For Q and newer, it will only automatically
+ * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE}
+ * setting is also set to
* {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
*
* @see #AUTOMATIC_POWER_SAVER_MODE
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index cc74e1a..8512a0b 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -292,9 +292,9 @@
return uid;
}
- /** The package that posted the notification.
- *<p>
- * Might be different from {@link #getPackageName()} if the app owning the notification has
+ /**
+ * The package that posted the notification.
+ * <p> Might be different from {@link #getPackageName()} if the app owning the notification has
* a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
*/
public @NonNull String getOpPkg() {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 83f14d1..100774c 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -536,7 +536,7 @@
* or playing back a file. The value should be one of the STREAM_ constants
* defined in {@link AudioManager}.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_STREAM = "streamType";
@@ -546,7 +546,7 @@
* speaking text or playing back a file. The value should be set
* using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
* @hide
*/
@@ -557,7 +557,7 @@
* {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
* spoken, a file has been played back or a silence duration has elapsed.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
* @see TextToSpeech#synthesizeToFile(String, HashMap, String)
*/
@@ -568,7 +568,7 @@
* volume used when speaking text. Volume is specified as a float ranging from 0 to 1
* where 0 is silence, and 1 is the maximum volume (the default behavior).
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_VOLUME = "volume";
@@ -578,7 +578,7 @@
* Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
* 0 to center (the default behavior), and +1 to hard-right.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_PAN = "pan";
@@ -589,7 +589,7 @@
* as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
* use network based synthesis.
*
- * @see TextToSpeech#speak(String, int, java.util.HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
* @see TextToSpeech#getFeatures(java.util.Locale)
*
@@ -607,7 +607,7 @@
* as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
* text on-device (without making network requests).
*
- * @see TextToSpeech#speak(String, int, java.util.HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
* @see TextToSpeech#getFeatures(java.util.Locale)
@@ -625,7 +625,7 @@
* output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect}
* objects with the synthesis (or earcon) output.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_SESSION_ID = "sessionId";
@@ -881,7 +881,7 @@
/**
* Adds a mapping between a string of text and a sound resource in a
* package. After a call to this method, subsequent calls to
- * {@link #speak(String, int, HashMap)} will play the specified sound resource
+ * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
* if it is available, or synthesize the text it is missing.
*
* @param text
@@ -915,7 +915,7 @@
/**
* Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
* and a sound resource in a package. After a call to this method, subsequent calls to
- * {@link #speak(String, int, HashMap)} will play the specified sound resource
+ * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
* if it is available, or synthesize the text it is missing.
*
* @param text
@@ -947,11 +947,10 @@
}
/**
- * Adds a mapping between a string of text and a sound file. Using this, it
- * is possible to add custom pronounciations for a string of text.
- * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
- * will play the specified sound resource if it is available, or synthesize the text it is
- * missing.
+ * Adds a mapping between a string of text and a sound file. Using this, it is possible to
+ * add custom pronounciations for a string of text. After a call to this method, subsequent
+ * calls to {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound
+ * resource if it is available, or synthesize the text it is missing.
*
* @param text
* The string of text. Example: <code>"south_south_east"</code>
@@ -970,8 +969,8 @@
/**
* Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
- * Using this, it is possible to add custom pronounciations for a string of text.
- * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+ * Using this, it is possible to add custom pronounciations for a string of text. After a call
+ * to this method, subsequent calls to {@link #speak(CharSequence, int, Bundle, String)}
* will play the specified sound resource if it is available, or synthesize the text it is
* missing.
*
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 019ebff..5a27e94 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -161,7 +161,7 @@
/**
* Gets the context id.
*/
- @NonNull
+ @Nullable
public LocusId getLocusId() {
return mId;
}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 7ad9223..f037407 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2305,4 +2305,8 @@
// Open: Settings > Special App Access > Do not disturb control for app
ZEN_ACCESS_DETAIL = 1692;
+
+ // OPEN: Settings > Face > Remove face
+ // OS: Q
+ DIALOG_FACE_REMOVE = 1693;
}
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index c08d7ca..4ef26dd 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -66,6 +66,10 @@
optional bool can_show_light = 8;
optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional sint32 importance = 10;
+ // The package the notification was posted for.
+ optional string package = 11;
+ // The package that posted the notification. It might not be the same as package.
+ optional string delegate_package = 12;
}
message ListenersDisablingEffectsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7417bf..efc6ad0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3929,6 +3929,10 @@
<permission android:name="android.permission.MANAGE_ROLLBACKS"
android:protectionLevel="signature|verifier" />
+ <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. -->
+ <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
<permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
android:protectionLevel="signature|verifier" />
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9298be6..5f43b48 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -41,6 +41,7 @@
namespace android {
class Bitmap;
+class AutoBackendTextureRelease;
namespace uirenderer {
@@ -135,6 +136,7 @@
friend class DispatchFrameCallbacks;
friend class RenderProxy;
friend class DummyVsyncSource;
+ friend class android::AutoBackendTextureRelease;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 077a8f7..65d95ad 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -24,13 +24,17 @@
#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include <GrAHardwareBufferUtils.h>
+#include <GrBackendSurface.h>
// Macro for including the SurfaceTexture name in log messages
#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+using namespace android::uirenderer::renderthread;
+
namespace android {
void ImageConsumer::onFreeBufferLocked(int slotIndex) {
+ // This callback may be invoked on any thread.
mImageSlots[slotIndex].clear();
}
@@ -46,55 +50,141 @@
mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
}
+/**
+ * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SKImage object using them is destroyed.
+ */
+class AutoBackendTextureRelease {
+public:
+ static void releaseProc(SkImage::ReleaseContext releaseContext);
+
+ AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer);
+
+ const GrBackendTexture& getTexture() const { return mBackendTexture; }
+
+ void ref() { mUsageCount++; }
+
+ void unref(bool releaseImage);
+
+ inline sk_sp<SkImage> getImage() { return mImage; }
+
+ void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
+ GrContext* context);
+
+private:
+ // The only way to invoke dtor is with unref, when mUsageCount is 0.
+ ~AutoBackendTextureRelease() {}
+
+ GrBackendTexture mBackendTexture;
+ GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+ GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+
+ // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
+ // are held by SkImages.
+ int mUsageCount = 1;
+
+ // mImage is the SkImage created from mBackendTexture.
+ sk_sp<SkImage> mImage;
+};
+
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) {
+ bool createProtectedImage =
+ 0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
+ GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
+ context,
+ reinterpret_cast<AHardwareBuffer*>(buffer),
+ buffer->getPixelFormat(),
+ false);
+ mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
+ context,
+ reinterpret_cast<AHardwareBuffer*>(buffer),
+ buffer->getWidth(),
+ buffer->getHeight(),
+ &mDeleteProc,
+ &mDeleteCtx,
+ createProtectedImage,
+ backendFormat,
+ false);
+}
+
+void AutoBackendTextureRelease::unref(bool releaseImage) {
+ if (!RenderThread::isCurrent()) {
+ // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
+ // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
+ // thread safe.
+ RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
+ return;
+ }
+
+ if (releaseImage) {
+ mImage.reset();
+ }
+
+ mUsageCount--;
+ if (mUsageCount <= 0) {
+ if (mBackendTexture.isValid()) {
+ mDeleteProc(mDeleteCtx);
+ mBackendTexture = {};
+ }
+ delete this;
+ }
+}
+
+void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) {
+ AutoBackendTextureRelease* textureRelease =
+ reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
+ textureRelease->unref(false);
+}
+
+void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer,
+ android_dataspace dataspace, GrContext* context) {
+ SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
+ graphicBuffer->getPixelFormat());
+ mImage = SkImage::MakeFromTexture(context,
+ mBackendTexture,
+ kTopLeft_GrSurfaceOrigin,
+ colorType,
+ kPremul_SkAlphaType,
+ uirenderer::DataSpaceToColorSpace(dataspace),
+ releaseProc,
+ this);
+ if (mImage.get()) {
+ // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+ ref();
+ }
+}
+
void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
android_dataspace dataspace, bool forceCreate,
GrContext* context) {
- if (!mImage.get() || dataspace != mDataspace || forceCreate) {
+ if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace
+ || forceCreate) {
if (!graphicBuffer.get()) {
clear();
return;
}
- if (!mBackendTexture.isValid()) {
- clear();
- bool createProtectedImage =
- 0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
- GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
- context,
- reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
- graphicBuffer->getPixelFormat(),
- false);
- mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
- context,
- reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
- graphicBuffer->getWidth(),
- graphicBuffer->getHeight(),
- &mDeleteProc,
- &mDeleteCtx,
- createProtectedImage,
- backendFormat,
- false);
+ if (!mTextureRelease) {
+ mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
}
+
mDataspace = dataspace;
- SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
- graphicBuffer->getPixelFormat());
- mImage = SkImage::MakeFromTexture(context,
- mBackendTexture,
- kTopLeft_GrSurfaceOrigin,
- colorType,
- kPremul_SkAlphaType,
- uirenderer::DataSpaceToColorSpace(dataspace));
+ mTextureRelease->makeImage(graphicBuffer, dataspace, context);
}
}
void ImageConsumer::ImageSlot::clear() {
- mImage.reset();
- if (mBackendTexture.isValid()) {
- mDeleteProc(mDeleteCtx);
- mBackendTexture = {};
+ if (mTextureRelease) {
+ // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
+ mTextureRelease->unref(true);
+ mTextureRelease = nullptr;
}
}
+sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() {
+ return mTextureRelease ? mTextureRelease->getImage() : nullptr;
+}
+
sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
uirenderer::RenderState& renderState) {
BufferItem item;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index eee0a0a..2fdece9 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -25,7 +25,6 @@
#include <cutils/compiler.h>
#include <gui/BufferItem.h>
#include <system/graphics.h>
-#include <GrBackendSurface.h>
namespace GrAHardwareBufferUtils {
typedef void* DeleteImageCtx;
@@ -38,6 +37,7 @@
class RenderState;
}
+class AutoBackendTextureRelease;
class SurfaceTexture;
/*
@@ -81,16 +81,14 @@
void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
bool forceCreate, GrContext* context);
+
void clear();
inline EGLSyncKHR& eglFence() { return mEglFence; }
- inline sk_sp<SkImage> getImage() { return mImage; }
+ sk_sp<SkImage> getImage();
private:
- // mImage is the SkImage created from mGraphicBuffer.
- sk_sp<SkImage> mImage;
-
// the dataspace associated with the current image
android_dataspace mDataspace;
@@ -100,11 +98,11 @@
*/
EGLSyncKHR mEglFence;
- GrBackendTexture mBackendTexture;
-
- GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-
- GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+ /**
+ * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage.
+ * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear".
+ */
+ AutoBackendTextureRelease* mTextureRelease = nullptr;
};
/**
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 050b2ec..01f1798 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -167,9 +167,9 @@
/**
* Broadcast intent action when the set of enabled location providers changes. To check the
- * status of a provider, use {@link #isProviderEnabled(String)}. Depending on API level, may
+ * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
* include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
- * whose state has changed. See {@link #EXTRA_PROVIDER_NAME} for the supported API level.
+ * whose state has changed.
*
* @see #EXTRA_PROVIDER_NAME
*/
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 5cd3621..fbe184b 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -3463,7 +3463,7 @@
* @param uuid of selected crypto scheme
* @return this
*/
- public Builder setUuid(@NonNull UUID uuid) {
+ public @NonNull Builder setUuid(@NonNull UUID uuid) {
this.mUUID = uuid;
return this;
}
@@ -3480,7 +3480,7 @@
* @param keySetId identifier of a persisted offline key
* @return this
*/
- public Builder setKeySetId(@Nullable byte[] keySetId) {
+ public @NonNull Builder setKeySetId(@Nullable byte[] keySetId) {
this.mKeySetId = keySetId;
return this;
}
@@ -3494,7 +3494,7 @@
* @param initData container-specific DRM initialization data
* @return this
*/
- public Builder setInitData(@Nullable byte[] initData) {
+ public @NonNull Builder setInitData(@Nullable byte[] initData) {
this.mInitData = initData;
return this;
}
@@ -3505,7 +3505,7 @@
* @param mimeType mime type to the content
* @return this
*/
- public Builder setMimeType(@Nullable String mimeType) {
+ public @NonNull Builder setMimeType(@Nullable String mimeType) {
this.mMimeType = mimeType;
return this;
}
@@ -3519,7 +3519,7 @@
* @param keyType type of the key request
* @return this
*/
- public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+ public @NonNull Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
this.mKeyType = keyType;
return this;
}
@@ -3531,7 +3531,8 @@
* @param optionalParameters optional parameters to be included in a key request
* @return this
*/
- public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) {
+ public @NonNull Builder setOptionalParameters(
+ @Nullable Map<String, String> optionalParameters) {
this.mOptionalParameters = optionalParameters;
return this;
}
@@ -3540,7 +3541,7 @@
* @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
* settings of this builder
*/
- public MediaPlayer2.DrmPreparationInfo build() {
+ public @NonNull MediaPlayer2.DrmPreparationInfo build() {
return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
mKeyType, mOptionalParameters);
}
@@ -3597,7 +3598,8 @@
* @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
* DRM initialization
*/
- public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+ public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
+ @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) {
return null;
}
@@ -3630,11 +3632,13 @@
* @param request a {@link MediaDrm.KeyRequest} prepared using the
* {@link DrmPreparationInfo} returned from
* {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
- * @return the response to {@code request} (from license server)
+ * @return the response to {@code request} (from license server); returning {@code null} or
+ * throwing an {@link RuntimeException} from this callback would trigger an
+ * {@link EventCallback#onError}.
*/
- public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
- @NonNull MediaDrm.KeyRequest request) {
- return null;
+ public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
+ @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) {
+ return new byte[0];
}
/**
@@ -4144,7 +4148,7 @@
/**
* Returns the PSSH info of the data source for each supported DRM scheme.
*/
- public Map<UUID, byte[]> getPssh() {
+ public @NonNull Map<UUID, byte[]> getPssh() {
return mMapPssh;
}
@@ -4153,7 +4157,7 @@
* It effectively identifies the subset of the source's DRM schemes which
* are supported by the device too.
*/
- public List<UUID> getSupportedSchemes() {
+ public @NonNull List<UUID> getSupportedSchemes() {
return Arrays.asList(mSupportedSchemes);
}
@@ -4276,7 +4280,7 @@
* Extends MediaDrm.MediaDrmException
*/
public static final class NoDrmSchemeException extends MediaDrmException {
- public NoDrmSchemeException(String detailMessage) {
+ public NoDrmSchemeException(@Nullable String detailMessage) {
super(detailMessage);
}
}
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 20d6391..6822ea5 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -32,6 +32,10 @@
* If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
* {@link #getCustomCommand()} shouldn't be {@code null}.
* <p>
+ * Refer to the
+ * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a>
+ * class for the list of valid commands.
+ * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a288d010..bda5743 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
import android.webkit.CookieManager;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -409,8 +410,7 @@
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
getResources().getDisplayMetrics());
private int mPagesLoaded;
- // the host of the page that this webview is currently loading. Can be null when undefined.
- private String mHostname;
+ private String mMainFrameUrl;
// If we haven't finished cleaning up the history, don't allow going back.
public boolean allowBack() {
@@ -436,7 +436,6 @@
}
final URL url = makeURL(urlString);
Log.d(TAG, "onPageStarted: " + sanitizeURL(url));
- mHostname = host(url);
// For internally generated pages, leave URL bar listing prior URL as this is the URL
// the page refers to.
if (!urlString.startsWith(INTERNAL_ASSETS)) {
@@ -480,17 +479,28 @@
return Integer.toString((int)dp) + "px";
}
+ // Check if webview is trying to load the main frame and record its url.
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ if (request.isForMainFrame()) {
+ mMainFrameUrl = request.getUrl().toString();
+ }
+ return false;
+ }
+
// A web page consisting of a large broken lock icon to indicate SSL failure.
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- final URL url = makeURL(error.getUrl());
- final String host = host(url);
+ final URL errorUrl = makeURL(error.getUrl());
+ final URL mainFrameUrl = makeURL(mMainFrameUrl);
Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
- sslErrorName(error), sanitizeURL(url), error.getCertificate()));
- if (url == null || !Objects.equals(host, mHostname)) {
- // Ignore ssl errors for resources coming from a different hostname than the page
- // that we are currently loading, and only cancel the request.
+ sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate()));
+ if (errorUrl == null
+ // Ignore SSL errors from resources by comparing the main frame url with SSL
+ // error url.
+ || !errorUrl.equals(mainFrameUrl)) {
+ Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl);
handler.cancel();
return;
}
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 591cf70..a69b412 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -93,6 +93,7 @@
<activity android:name=".UninstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
+ android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true">
<intent-filter android:priority="1">
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index 6c8e4c5..b11d28b 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -24,4 +24,9 @@
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+ <style name="Theme.AlertDialogActivity.NoActionBar">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bf97d77..d3dde92 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -185,8 +185,12 @@
<!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_no_battery_level">Active</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ab95910..2405666 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -32,6 +32,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.Utils;
import java.util.ArrayList;
import java.util.Collection;
@@ -830,6 +831,8 @@
boolean a2dpConnected = true; // A2DP is connected
boolean hfpConnected = true; // HFP is connected
boolean hearingAidConnected = true; // Hearing Aid is connected
+ int leftBattery = -1;
+ int rightBattery = -1;
synchronized (mProfileLock) {
for (LocalBluetoothProfile profile : getProfiles()) {
@@ -877,8 +880,23 @@
int stringRes = R.string.bluetooth_pairing;
//when profile is connected, information would be available
if (profileConnected) {
+ // Update Meta data for connected device
+ if (Boolean.parseBoolean(
+ mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
+ try {
+ leftBattery = Integer.parseInt(
+ mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
+ rightBattery = Integer.parseInt(mDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Parse error for unthethered battery level.");
+ }
+ }
+
// Set default string with battery level in device connected situation.
- if (batteryLevelPercentageString != null) {
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ stringRes = R.string.bluetooth_battery_level_untethered;
+ } else if (batteryLevelPercentageString != null) {
stringRes = R.string.bluetooth_battery_level;
}
@@ -887,22 +905,36 @@
// 2. Headset device active with in-calling state.
// 3. A2DP device active without in-calling state.
if (a2dpConnected || hfpConnected || hearingAidConnected) {
- final boolean isOnCall =
- com.android.settingslib.Utils.isAudioModeOngoingCall(mContext);
+ final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
|| (mIsActiveDeviceA2dp && !isOnCall)) {
- stringRes = (batteryLevelPercentageString != null)
- ? R.string.bluetooth_active_battery_level
- : R.string.bluetooth_active_no_battery_level;
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ stringRes = R.string.bluetooth_active_battery_level_untethered;
+ } else if (batteryLevelPercentageString != null) {
+ stringRes = R.string.bluetooth_active_battery_level;
+ } else {
+ stringRes = R.string.bluetooth_active_no_battery_level;
+ }
}
}
}
- return (stringRes != R.string.bluetooth_pairing
- || getBondState() == BluetoothDevice.BOND_BONDING)
- ? mContext.getString(stringRes, batteryLevelPercentageString)
- : null;
+ if (stringRes != R.string.bluetooth_pairing
+ || getBondState() == BluetoothDevice.BOND_BONDING) {
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ return mContext.getString(stringRes, Utils.formatPercentage(leftBattery),
+ Utils.formatPercentage(rightBattery));
+ } else {
+ return mContext.getString(stringRes, batteryLevelPercentageString);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) {
+ return leftBattery >= 0 && rightBattery >= 0;
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index bee1b3c..d28b00a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -276,6 +276,12 @@
return null;
}
ensureMetadataNotStale(context);
+ final ActivityInfo activityInfo = getActivityInfo(context);
+ if (activityInfo == null) {
+ Log.w(TAG, "Cannot find ActivityInfo for " + getDescription());
+ return null;
+ }
+
int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
// Set the icon
if (iconResId == 0) {
@@ -283,11 +289,11 @@
// ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
// level is too complex because we don't have a strong threading contract for this class
if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
- iconResId = getActivityInfo(context).icon;
+ iconResId = activityInfo.icon;
}
}
if (iconResId != 0) {
- return Icon.createWithResource(getActivityInfo(context).packageName, iconResId);
+ return Icon.createWithResource(activityInfo.packageName, iconResId);
} else {
return null;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4e5d38a..79b84b9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -41,14 +41,16 @@
@RunWith(RobolectricTestRunner.class)
public class CachedBluetoothDeviceTest {
- private final static String DEVICE_NAME = "TestName";
- private final static String DEVICE_ALIAS = "TestAlias";
- private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
- private final static String DEVICE_ALIAS_NEW = "TestAliasNew";
- private final static short RSSI_1 = 10;
- private final static short RSSI_2 = 11;
- private final static boolean JUSTDISCOVERED_1 = true;
- private final static boolean JUSTDISCOVERED_2 = false;
+ private static final String DEVICE_NAME = "TestName";
+ private static final String DEVICE_ALIAS = "TestAlias";
+ private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
+ private static final String DEVICE_ALIAS_NEW = "TestAliasNew";
+ private static final String TWS_BATTERY_LEFT = "15";
+ private static final String TWS_BATTERY_RIGHT = "25";
+ private static final short RSSI_1 = 10;
+ private static final short RSSI_2 = 11;
+ private static final boolean JUSTDISCOVERED_1 = true;
+ private static final boolean JUSTDISCOVERED_2 = false;
@Mock
private LocalBluetoothProfileManager mProfileManager;
@Mock
@@ -447,6 +449,41 @@
}
@Test
+ public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() {
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+ "true");
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT);
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+ "Active, L: 15% battery, R: 25% battery");
+ }
+
+ @Test
+ public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() {
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+ "true");
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT);
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+ "L: 15% battery, R: 25% battery");
+ }
+
+ @Test
public void getCarConnectionSummary_singleProfileConnectDisconnect() {
// Test without battery level
// Set PAN profile to be connected and test connection state summary
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d639e5e..f0399c5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -86,6 +86,7 @@
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
+ <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 0fed96e..27d2bcd 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -18,8 +18,6 @@
<declare-styleable name="KeyButtonView">
<!-- key code to send when pressed; if absent or 0, no key is sent -->
<attr name="keyCode" format="integer" />
- <!-- does this button generate longpress / repeat events? -->
- <attr name="keyRepeat" format="boolean" />
<!-- Should this button play sound effects, default true -->
<attr name="playSound" format="boolean" />
<attr name="android:contentDescription" />
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e0ed111..4a2731e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -61,6 +61,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import java.lang.annotation.Retention;
@@ -74,7 +75,8 @@
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
@Singleton
-public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
+public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener,
+ ConfigurationController.ConfigurationListener {
private static final String TAG = "BubbleController";
@@ -84,6 +86,7 @@
@IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
@interface DismissReason {}
+
static final int DISMISS_USER_GESTURE = 1;
static final int DISMISS_AGED = 2;
static final int DISMISS_TASK_FINISHED = 3;
@@ -151,6 +154,7 @@
public interface BubbleExpandListener {
/**
* Called when the expansion state of the bubble stack changes.
+ *
* @param isExpanding whether it's expanding or collapsing
* @param key the notification key associated with bubble being expanded
*/
@@ -179,13 +183,16 @@
@Inject
public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
- BubbleData data) {
- this(context, statusBarWindowController, data, null /* synchronizer */);
+ BubbleData data, ConfigurationController configurationController) {
+ this(context, statusBarWindowController, data, null /* synchronizer */,
+ configurationController);
}
public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
- BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) {
+ BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+ ConfigurationController configurationController) {
mContext = context;
+ configurationController.addCallback(this /* configurationListener */);
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -215,6 +222,20 @@
mSurfaceSynchronizer = synchronizer;
}
+ @Override
+ public void onUiModeChanged() {
+ if (mStackView != null) {
+ mStackView.onConfigChanged();
+ }
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ if (mStackView != null) {
+ mStackView.onConfigChanged();
+ }
+ }
+
/**
* Set a listener to be notified when some states of the bubbles change.
*/
@@ -295,7 +316,7 @@
/**
* Adds or updates a bubble associated with the provided notification entry.
*
- * @param notif the notification associated with this bubble.
+ * @param notif the notification associated with this bubble.
* @param updatePosition whether this update should promote the bubble to the top of the stack.
*/
public void updateBubble(NotificationEntry notif, boolean updatePosition) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 856b9d6..e8b346e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -354,6 +354,13 @@
}
}
+ /**
+ * Update bubble expanded view header when user toggles dark mode.
+ */
+ void updateHeaderColor() {
+ mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent));
+ }
+
private void updateHeaderView() {
mSettingsIcon.setContentDescription(getResources().getString(
R.string.bubbles_settings_button_description, mAppName));
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 1cc6b87..461e79c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -238,6 +238,13 @@
mBubbleContainer.bringToFront();
}
+ /**
+ * Handle config changes.
+ */
+ public void onConfigChanged() {
+ mExpandedBubble.expandedView.updateHeaderColor();
+ }
+
@Override
public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
getBoundsOnScreen(outRect);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d06feed..2db7306 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -61,7 +61,9 @@
@Override
public void onDestroy() {
- mPluginManager.removePluginListener(this);
+ if (mPluginManager != null) {
+ mPluginManager.removePluginListener(this);
+ }
super.onDestroy();
mDozeMachine = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 024404d..1e05983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -66,7 +66,6 @@
private int mTouchDownX;
private int mTouchDownY;
private boolean mIsVertical;
- private boolean mSupportsLongpress = true;
private AudioManager mAudioManager;
private boolean mGestureAborted;
private boolean mLongClicked;
@@ -83,7 +82,7 @@
// Just an old-fashioned ImageView
performLongClick();
mLongClicked = true;
- } else if (mSupportsLongpress) {
+ } else {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
mLongClicked = true;
@@ -104,7 +103,6 @@
mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
- mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
TypedValue value = new TypedValue();
@@ -166,7 +164,7 @@
super.onInitializeAccessibilityNodeInfo(info);
if (mCode != KEYCODE_UNKNOWN) {
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
- if (mSupportsLongpress || isLongClickable()) {
+ if (isLongClickable()) {
info.addAction(
new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 4e9d892..63b6673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,6 +44,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -66,6 +67,9 @@
private IActivityManager mActivityManager;
@Mock
private DozeParameters mDozeParameters;
+ @Mock
+ private ConfigurationController mConfigurationController;
+
private FrameLayout mStatusBarView;
@Captor
private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@@ -97,6 +101,7 @@
mStatusBarView = new FrameLayout(mContext);
mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
+
// Bubbles get added to status bar window view
mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
mActivityManager, mDozeParameters);
@@ -115,7 +120,7 @@
mBubbleData = new BubbleData();
mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
- mBubbleData);
+ mBubbleData, mConfigurationController);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -331,8 +336,9 @@
static class TestableBubbleController extends BubbleController {
// Let's assume surfaces can be synchronized immediately.
TestableBubbleController(Context context,
- StatusBarWindowController statusBarWindowController, BubbleData data) {
- super(context, statusBarWindowController, data, Runnable::run);
+ StatusBarWindowController statusBarWindowController, BubbleData data,
+ ConfigurationController configurationController) {
+ super(context, statusBarWindowController, data, Runnable::run, configurationController);
}
@Override
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index f106228..c5c4b5a 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7120,6 +7120,10 @@
// Open: Settings > Special App Access > Do not disturb control for app
ZEN_ACCESS_DETAIL = 1692;
+ // OPEN: Settings > Face > Remove face
+ // OS: Q
+ DIALOG_FACE_REMOVE = 1693;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a400cc3..3d918fc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -83,6 +83,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.StatsLog;
import android.util.TimeUtils;
@@ -195,6 +196,7 @@
private final Injector mInjector;
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
+ SparseIntArray mAlarmsPerUid = new SparseIntArray();
ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
ArrayList<InFlight> mInFlight = new ArrayList<>();
private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
@@ -393,6 +395,8 @@
@VisibleForTesting
static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
@VisibleForTesting
+ static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
+ @VisibleForTesting
static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
@VisibleForTesting
@@ -420,6 +424,7 @@
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+ private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr
/**
@@ -461,6 +466,8 @@
// Direct alarm listener callback timeout
public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+ public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+
public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
@@ -549,6 +556,15 @@
APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i],
Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i]));
}
+
+ MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID,
+ DEFAULT_MAX_ALARMS_PER_UID);
+ if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) {
+ Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than "
+ + DEFAULT_MAX_ALARMS_PER_UID);
+ MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+ }
+
updateAllowWhileIdleWhitelistDurationLocked();
}
}
@@ -590,6 +606,9 @@
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
pw.println();
+ pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
+ pw.println(MAX_ALARMS_PER_UID);
+
for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
@@ -671,12 +690,6 @@
final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
- Batch() {
- start = 0;
- end = Long.MAX_VALUE;
- flags = 0;
- }
-
Batch(Alarm seed) {
start = seed.whenElapsed;
end = clampPositive(seed.maxWhenElapsed);
@@ -728,11 +741,16 @@
return newStart;
}
+ /**
+ * Remove an alarm from this batch.
+ * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it
+ * does not update {@link #mAlarmsPerUid}
+ */
boolean remove(Alarm alarm) {
- return remove(a -> (a == alarm));
+ return remove(a -> (a == alarm), true);
}
- boolean remove(Predicate<Alarm> predicate) {
+ boolean remove(Predicate<Alarm> predicate, boolean reOrdering) {
boolean didRemove = false;
long newStart = 0; // recalculate endpoints as we go
long newEnd = Long.MAX_VALUE;
@@ -741,6 +759,9 @@
Alarm alarm = alarms.get(i);
if (predicate.test(alarm)) {
alarms.remove(i);
+ if (!reOrdering) {
+ decrementAlarmCount(alarm.uid);
+ }
didRemove = true;
if (alarm.alarmClock != null) {
mNextAlarmClockMayChange = true;
@@ -1734,6 +1755,15 @@
+ " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
+ " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
}
+ if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) {
+ final String errorMsg =
+ "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
+ + " reached for uid: " + UserHandle.formatUid(callingUid)
+ + ", callingPackage: " + callingPackage;
+ // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
+ Slog.wtf(TAG, errorMsg);
+ throw new UnsupportedOperationException(errorMsg);
+ }
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
alarmClock, callingUid, callingPackage);
@@ -1756,6 +1786,7 @@
} catch (RemoteException e) {
}
removeLocked(operation, directReceiver);
+ incrementAlarmCount(a.uid);
setImplLocked(a, false, doValidate);
}
@@ -2197,7 +2228,6 @@
? sdf.format(new Date(nowRTC - (nowELAPSED - time)))
: "-");
} while (i != mNextTickHistory);
- pw.println();
}
SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class);
@@ -2305,6 +2335,18 @@
if (!blocked) {
pw.println(" none");
}
+ pw.println();
+ pw.print(" Pending alarms per uid: [");
+ for (int i = 0; i < mAlarmsPerUid.size(); i++) {
+ if (i > 0) {
+ pw.print(", ");
+ }
+ UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i));
+ pw.print(":");
+ pw.print(mAlarmsPerUid.valueAt(i));
+ }
+ pw.println("]");
+ pw.println();
mAppWakeupHistory.dump(pw, " ", nowELAPSED);
@@ -3046,7 +3088,7 @@
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3098,7 +3140,7 @@
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3145,7 +3187,7 @@
final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3183,6 +3225,7 @@
}
}
+ // Only called for ephemeral apps
void removeForStoppedLocked(final int uid) {
if (uid == Process.SYSTEM_UID) {
Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
@@ -3200,7 +3243,7 @@
};
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3237,7 +3280,7 @@
(Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3407,8 +3450,7 @@
return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
}
- boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
- final long nowRTC) {
+ boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
boolean hasWakeup = false;
// batches are temporally sorted, so we need only pull from the
// start of the list until we either empty it or hit a batch
@@ -3984,7 +4026,7 @@
}
mLastTrigger = nowELAPSED;
- boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+ boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
@@ -4108,9 +4150,8 @@
case ALARM_EVENT: {
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
synchronized (mLock) {
- final long nowRTC = mInjector.getCurrentTimeMillis();
final long nowELAPSED = mInjector.getElapsedRealtime();
- triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+ triggerAlarmsLocked(triggerList, nowELAPSED);
updateNextAlarmClockLocked();
}
@@ -4719,7 +4760,7 @@
mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
}
-
+ decrementAlarmCount(alarm.uid);
final BroadcastStats bs = inflight.mBroadcastStats;
bs.count++;
if (bs.nesting == 0) {
@@ -4747,6 +4788,27 @@
}
}
+ private void incrementAlarmCount(int uid) {
+ final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+ if (uidIndex >= 0) {
+ mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1);
+ } else {
+ mAlarmsPerUid.put(uid, 1);
+ }
+ }
+
+ private void decrementAlarmCount(int uid) {
+ final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+ if (uidIndex >= 0) {
+ final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
+ if (newCount > 0) {
+ mAlarmsPerUid.setValueAt(uidIndex, newCount);
+ } else {
+ mAlarmsPerUid.removeAt(uidIndex);
+ }
+ }
+ }
+
private class ShellCmd extends ShellCommand {
IAlarmManager getBinderService() {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 3ab3c34..833faa6 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -115,7 +115,8 @@
*
* Test: atest com.android.server.DeviceIdleControllerTest
*
- * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz:
+ * Current idling state machine (as of Android Q). This can be visualized using Graphviz:
+ <pre>
digraph {
subgraph deep {
@@ -259,6 +260,7 @@
]
}
}
+ </pre>
*/
public class DeviceIdleController extends SystemService
implements AnyMotionDetector.DeviceIdleCallback {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 7fab2b96..6ef5b54 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -102,6 +102,7 @@
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
import com.android.server.location.GnssMeasurementsProvider;
import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssStatusListenerHelper;
@@ -195,6 +196,7 @@
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GnssMeasurementsProvider mGnssMeasurementsProvider;
+ private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
@GuardedBy("mLock")
private String mLocationControllerExtraPackage;
@@ -309,9 +311,13 @@
AppOpsManager.WATCH_FOREGROUND_CHANGES,
new AppOpsManager.OnOpChangedInternalListener() {
public void onOpChanged(int op, String packageName) {
- synchronized (mLock) {
- onAppOpChangedLocked();
- }
+ // onOpChanged invoked on ui thread, move to our thread to reduce risk of
+ // blocking ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onAppOpChangedLocked();
+ }
+ });
}
});
mPackageManager.addOnPermissionsChangeListener(
@@ -757,6 +763,8 @@
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
+ mGnssMeasurementCorrectionsProvider =
+ gnssProvider.getGnssMeasurementCorrectionsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
}
@@ -2921,22 +2929,28 @@
mContext.enforceCallingPermission(
android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject GNSS measurement corrections.");
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ if (!hasGnssPermissions(packageName)) {
Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
- } else {
- mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
+ return;
}
+ if (mGnssMeasurementCorrectionsProvider == null) {
+ Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider "
+ + "not available.");
+ return;
+ }
+ mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
+ measurementCorrections);
}
@Override
public int getGnssCapabilities(String packageName) {
mContext.enforceCallingPermission(
android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
+ if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) {
return -1;
}
- return mGnssMeasurementsProvider.getGnssCapabilities();
+ return mGnssMeasurementCorrectionsProvider.getCapabilities();
}
@Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d6fdbe3..26896f5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -625,6 +625,11 @@
r.callingPackage = callingPackage;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
+ if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
+ throw new IllegalArgumentException(
+ "PhoneStateListener cannot concurrently listen on multiple " +
+ "subscriptions. Previously registered on subId: " + r.subId);
+ }
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8225476..92b7c3c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1273,11 +1273,13 @@
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
+ static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
int changes;
int uid;
int pid;
int processState;
boolean foregroundActivities;
+ int foregroundServiceTypes;
}
static final class UidObserverRegistration {
@@ -3079,6 +3081,13 @@
observer.onForegroundActivitiesChanged(item.pid, item.uid,
item.foregroundActivities);
}
+ if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
+ + item.uid + ": " + item.foregroundServiceTypes);
+ observer.onForegroundServicesChanged(item.pid, item.uid,
+ item.foregroundServiceTypes);
+ }
}
} catch (RemoteException e) {
}
@@ -3093,6 +3102,47 @@
}
}
+ @GuardedBy("this")
+ ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
+ int i = mPendingProcessChanges.size()-1;
+ ActivityManagerService.ProcessChangeItem item = null;
+ while (i >= 0) {
+ item = mPendingProcessChanges.get(i);
+ if (item.pid == pid) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Re-using existing item: " + item);
+ break;
+ }
+ i--;
+ }
+
+ if (i < 0) {
+ // No existing item in pending changes; need a new one.
+ final int NA = mAvailProcessChanges.size();
+ if (NA > 0) {
+ item = mAvailProcessChanges.remove(NA-1);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Retrieving available item: " + item);
+ } else {
+ item = new ActivityManagerService.ProcessChangeItem();
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Allocating new item: " + item);
+ }
+ item.changes = 0;
+ item.pid = pid;
+ item.uid = uid;
+ if (mPendingProcessChanges.size() == 0) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "*** Enqueueing dispatch processes changed!");
+ mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+ .sendToTarget();
+ }
+ mPendingProcessChanges.add(item);
+ }
+
+ return item;
+ }
+
private void dispatchProcessDied(int pid, int uid) {
int i = mProcessObservers.beginBroadcast();
while (i > 0) {
@@ -16275,11 +16325,12 @@
@GuardedBy("this")
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
int fgServiceTypes, boolean oomAdj) {
+ proc.setHasForegroundServices(isForeground, fgServiceTypes);
+
final boolean hasFgServiceLocationType =
(fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
if (isForeground != proc.hasForegroundServices()
|| proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
- proc.setHasForegroundServices(isForeground, fgServiceTypes);
ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
proc.info.uid);
if (isForeground) {
@@ -16308,6 +16359,13 @@
updateOomAdjLocked();
}
}
+
+ if (proc.getForegroundServiceTypes() != fgServiceTypes) {
+ proc.setReportedForegroundServiceTypes(fgServiceTypes);
+ ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
+ item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
+ item.foregroundServiceTypes = fgServiceTypes;
+ }
}
// TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
@@ -18101,6 +18159,34 @@
public void prepareForPossibleShutdown() {
ActivityManagerService.this.prepareForPossibleShutdown();
}
+
+ @Override
+ public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
+ synchronized (ActivityManagerService.this) {
+ for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+ final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
+ if (pr.uid != uid) {
+ continue;
+ }
+
+ if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void registerProcessObserver(IProcessObserver processObserver) {
+ ActivityManagerService.this.registerProcessObserver(processObserver);
+ }
+
+ @Override
+ public void unregisterProcessObserver(IProcessObserver processObserver) {
+ ActivityManagerService.this.unregisterProcessObserver(processObserver);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 438538f..9216343 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -230,11 +230,8 @@
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseCompaction() {
- String useCompactionFlag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_USE_COMPACTION);
- mUseCompaction = TextUtils.isEmpty(useCompactionFlag)
- ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag);
+ mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
if (mUseCompaction && !mCompactionThread.isAlive()) {
mCompactionThread.start();
mCompactionHandler = new MemCompactionHandler();
@@ -243,28 +240,11 @@
@GuardedBy("mPhenotypeFlagLock")
private void updateCompactionActions() {
- String compactAction1Flag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_ACTION_1);
- String compactAction2Flag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_ACTION_2);
+ int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
- int compactAction1 = DEFAULT_COMPACT_ACTION_1;
- try {
- compactAction1 = TextUtils.isEmpty(compactAction1Flag)
- ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag);
- } catch (NumberFormatException e) {
- // Do nothing, leave default.
- }
-
- int compactAction2 = DEFAULT_COMPACT_ACTION_2;
- try {
- compactAction2 = TextUtils.isEmpty(compactAction2Flag)
- ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag);
- } catch (NumberFormatException e) {
- // Do nothing, leave default.
- }
+ int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
mCompactActionSome = compactActionIntToString(compactAction1);
mCompactActionFull = compactActionIntToString(compactAction2);
@@ -312,14 +292,8 @@
@GuardedBy("mPhenotypeFlagLock")
private void updateStatsdSampleRate() {
- String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_STATSD_SAMPLE_RATE);
- try {
- mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
- ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
- } catch (NumberFormatException e) {
- mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
- }
+ mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE);
mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
}
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 09df7e20..d8d6528 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -24,6 +24,7 @@
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
import android.app.IAssistDataReceiver;
import android.content.Context;
import android.graphics.Bitmap;
@@ -33,6 +34,7 @@
import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import java.io.PrintWriter;
@@ -50,6 +52,8 @@
public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
private IWindowManager mWindowManager;
+ @VisibleForTesting
+ public IActivityTaskManager mActivityTaskManager;
private Context mContext;
private AppOpsManager mAppOpsManager;
@@ -128,6 +132,7 @@
mCallbacks = callbacks;
mCallbacksLock = callbacksLock;
mWindowManager = windowManager;
+ mActivityTaskManager = ActivityTaskManager.getService();
mContext = context;
mAppOpsManager = appOpsManager;
mRequestStructureAppOps = requestStructureAppOps;
@@ -195,8 +200,7 @@
// Ensure that the current activity supports assist data
boolean isAssistDataAllowed = false;
try {
- isAssistDataAllowed =
- ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity();
+ isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowedOnCurrentActivity();
} catch (RemoteException e) {
// Should never happen
}
@@ -222,9 +226,9 @@
receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
boolean result = requestAutofillData
- ? ActivityTaskManager.getService().requestAutofillData(this,
+ ? mActivityTaskManager.requestAutofillData(this,
receiverExtras, topActivity, 0 /* flags */)
- : ActivityTaskManager.getService().requestAssistContextExtras(
+ : mActivityTaskManager.requestAssistContextExtras(
ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
/* focused= */ i == 0, /* newSessionId= */ i == 0);
if (result) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9056f76..aa03de1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -38,7 +38,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
-import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -1921,41 +1920,9 @@
if (changes != 0) {
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Changes in " + app + ": " + changes);
- int i = mService.mPendingProcessChanges.size()-1;
- ActivityManagerService.ProcessChangeItem item = null;
- while (i >= 0) {
- item = mService.mPendingProcessChanges.get(i);
- if (item.pid == app.pid) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Re-using existing item: " + item);
- break;
- }
- i--;
- }
- if (i < 0) {
- // No existing item in pending changes; need a new one.
- final int NA = mService.mAvailProcessChanges.size();
- if (NA > 0) {
- item = mService.mAvailProcessChanges.remove(NA-1);
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Retrieving available item: " + item);
- } else {
- item = new ActivityManagerService.ProcessChangeItem();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Allocating new item: " + item);
- }
- item.changes = 0;
- item.pid = app.pid;
- item.uid = app.info.uid;
- if (mService.mPendingProcessChanges.size() == 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "*** Enqueueing dispatch processes changed!");
- mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
- .sendToTarget();
- }
- mService.mPendingProcessChanges.add(item);
- }
- item.changes |= changes;
+ ActivityManagerService.ProcessChangeItem item =
+ mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
+ item.changes = changes;
item.foregroundActivities = app.repForegroundActivities;
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Item " + Integer.toHexString(System.identityHashCode(item))
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 51b1ae1..17b244c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -174,6 +174,7 @@
boolean hasStartedServices; // Are there any started services running in this process?
private boolean mHasForegroundServices; // Running any services that are foreground?
private int mFgServiceTypes; // Type of foreground service, if there is a foreground service.
+ private int mRepFgServiceTypes; // Last reported foreground service types.
private boolean mHasForegroundActivities; // Running any activities that are foreground?
boolean repForegroundActivities; // Last reported foreground activities.
boolean systemNoUi; // This is a system process, but not currently showing UI.
@@ -1079,6 +1080,18 @@
&& (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
}
+ int getForegroundServiceTypes() {
+ return mHasForegroundServices ? mFgServiceTypes : 0;
+ }
+
+ int getReportedForegroundServiceTypes() {
+ return mRepFgServiceTypes;
+ }
+
+ void setReportedForegroundServiceTypes(int foregroundServiceTypes) {
+ mRepFgServiceTypes = foregroundServiceTypes;
+ }
+
void setHasForegroundActivities(boolean hasForegroundActivities) {
mHasForegroundActivities = hasForegroundActivities;
mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index aca02bf..c820841 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -30,6 +30,9 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.TrafficStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -85,8 +88,14 @@
@GuardedBy("mLock")
private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
+ private static final int MSG_DATA_SAVER_TOGGLED = 0;
+ private static final int MSG_UID_RULES_CHANGES = 1;
+
+ private final Handler mHandler;
+
public ConnectivityController(JobSchedulerService service) {
super(service);
+ mHandler = new CcHandler(mContext.getMainLooper());
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -545,11 +554,39 @@
private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() {
@Override
+ public void onRestrictBackgroundChanged(boolean restrictBackground) {
+ if (DEBUG) {
+ Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground);
+ }
+ mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget();
+ }
+
+ @Override
public void onUidRulesChanged(int uid, int uidRules) {
if (DEBUG) {
Slog.v(TAG, "onUidRulesChanged: " + uid);
}
- updateTrackedJobs(uid, null);
+ mHandler.obtainMessage(MSG_UID_RULES_CHANGES, uid, 0).sendToTarget();
+ }
+ };
+
+ private class CcHandler extends Handler {
+ CcHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ switch (msg.what) {
+ case MSG_DATA_SAVER_TOGGLED:
+ updateTrackedJobs(-1, null);
+ break;
+ case MSG_UID_RULES_CHANGES:
+ updateTrackedJobs(msg.arg1, null);
+ break;
+ }
+ }
}
};
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c173d66..8249999 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -166,9 +166,15 @@
private static final int GPS_CAPABILITY_MSA = 0x0000004;
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
- private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
+
+ // The following three capability flags are removed in IGnssCallback.hal@2.0 and their values
+ // are marked reserved and not reused in 2.0 to avoid confusion with prior versions.
+ public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
- private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+ public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+
+ private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
+ private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
// The AGPS SUPL mode
private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -333,7 +339,7 @@
private boolean mStarted;
// capabilities of the GPS engine
- private int mEngineCapabilities;
+ private volatile int mEngineCapabilities;
// true if XTRA is supported
private boolean mSupportsXtra;
@@ -372,6 +378,7 @@
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusListenerHelper mGnssStatusListenerHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
+ private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
@@ -437,6 +444,10 @@
return mGnssMeasurementsProvider;
}
+ public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
+ return mGnssMeasurementCorrectionsProvider;
+ }
+
public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
return mGnssNavigationMessageProvider;
}
@@ -627,6 +638,8 @@
}
};
+ mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
+
mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
@Override
protected boolean isGpsEnabled() {
@@ -1258,6 +1271,10 @@
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
}
+ public int getGnssCapabilities() {
+ return mEngineCapabilities;
+ }
+
private boolean hasCapability(int capability) {
return ((mEngineCapabilities & capability) != 0);
}
@@ -1467,22 +1484,27 @@
}
@NativeEntryPoint
- private void setEngineCapabilities(final int capabilities) {
+ private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) {
// send to handler thread for fast native return, and in-order handling
- mHandler.post(
- () -> {
- mEngineCapabilities = capabilities;
+ mHandler.post(() -> {
+ mEngineCapabilities = capabilities;
- if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
- mNtpTimeHelper.enablePeriodicTimeInjection();
- requestUtcTime();
- }
+ if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+ mNtpTimeHelper.enablePeriodicTimeInjection();
+ requestUtcTime();
+ }
- mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities);
- mGnssNavigationMessageProvider.onCapabilitiesUpdated(
- hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
- restartRequests();
- });
+ mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags);
+ mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities,
+ hasSubHalCapabilityFlags);
+ restartRequests();
+ });
+ }
+
+ @NativeEntryPoint
+ private void setMeasurementCorrectionsCapabilities(final int capabilities) {
+ mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(
+ capabilities));
}
private void restartRequests() {
@@ -2122,7 +2144,23 @@
if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
+ if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
+ if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
s.append(")\n");
+ if (mGnssGeofenceProvider.isHardwareGeofenceSupported()) {
+ s.append(" hasSubHal=GEOFENCING\n");
+ }
+ if (mGnssMeasurementsProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=MEASUREMENTS\n");
+ }
+ if (mGnssNavigationMessageProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=NAV_MESSAGES\n");
+ }
+ if (mGnssMeasurementCorrectionsProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=MEASUREMENT_CORRECTIONS [");
+ s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
+ s.append("]\n");
+ }
s.append(mGnssMetrics.dumpGnssMetricsAsText());
s.append(" native internal state: ").append(native_get_internal_state());
s.append("\n");
diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
new file mode 100644
index 0000000..2162787
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.location.GnssMeasurementCorrections;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Manages GNSS measurement corrections.
+ *
+ * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal}
+ * and {@code IMeasurementCorrectionsCallback.hal).
+ *
+ * @hide
+ */
+public class GnssMeasurementCorrectionsProvider {
+ private static final String TAG = "GnssMeasurementCorrectionsProvider";
+
+ // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal.
+ private static final int CAPABILITY_LOS_SATS = 0x0000001;
+ private static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002;
+ private static final int CAPABILITY_REFLECTING_PLANE = 0x0000004;
+
+ private static final int INVALID_CAPABILITIES = 1 << 31;
+
+ private final Handler mHandler;
+ private final GnssMeasurementCorrectionsProviderNative mNative;
+ private volatile int mCapabilities = INVALID_CAPABILITIES;
+
+ GnssMeasurementCorrectionsProvider(Handler handler) {
+ this(handler, new GnssMeasurementCorrectionsProviderNative());
+ }
+
+ @VisibleForTesting
+ GnssMeasurementCorrectionsProvider(Handler handler,
+ GnssMeasurementCorrectionsProviderNative aNative) {
+ mHandler = handler;
+ mNative = aNative;
+ }
+
+ /**
+ * Returns {@code true} if the GNSS HAL implementation supports measurement corrections.
+ */
+ public boolean isAvailableInPlatform() {
+ return mNative.isMeasurementCorrectionsSupported();
+ }
+
+ /**
+ * Injects GNSS measurement corrections into the GNSS chipset.
+ *
+ * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
+ * measurement corrections to be injected into the GNSS chipset.
+ */
+ public void injectGnssMeasurementCorrections(
+ GnssMeasurementCorrections measurementCorrections) {
+ if (!isCapabilitiesReceived()) {
+ Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities "
+ + "not received yet.");
+ return;
+ }
+ mHandler.post(() -> {
+ if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
+ Log.e(TAG, "Failure in injecting GNSS corrections.");
+ }
+ });
+ }
+
+ /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */
+ void onCapabilitiesUpdated(int capabilities) {
+ if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities,
+ CAPABILITY_EXCESS_PATH_LENGTH)) {
+ mCapabilities = capabilities;
+ } else {
+ Log.e(TAG, "Failed to set capabilities. Received capabilities 0x"
+ + Integer.toHexString(capabilities) + " does not contain the mandatory "
+ + "LOS_SATS or the EXCESS_PATH_LENGTH capability.");
+ }
+ }
+
+ /**
+ * Returns the measurement corrections specific capabilities of the GNSS HAL implementation.
+ */
+ public int getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Returns the string representation of the GNSS measurement capabilities.
+ */
+ String toStringCapabilities() {
+ final int capabilities = getCapabilities();
+ StringBuilder s = new StringBuilder();
+ s.append("mCapabilities=0x").append(Integer.toHexString(capabilities));
+ s.append(" ( ");
+ if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) {
+ s.append("LOS_SATS ");
+ }
+ if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) {
+ s.append("EXCESS_PATH_LENGTH ");
+ }
+ if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) {
+ s.append("REFLECTING_PLANE ");
+ }
+ s.append(")");
+ return s.toString();
+ }
+
+ private boolean isCapabilitiesReceived() {
+ return mCapabilities != INVALID_CAPABILITIES;
+ }
+
+ private static boolean hasCapability(int halCapabilities, int capability) {
+ return (halCapabilities & capability) != 0;
+ }
+
+ @VisibleForTesting
+ static class GnssMeasurementCorrectionsProviderNative {
+ public boolean isMeasurementCorrectionsSupported() {
+ return native_is_measurement_corrections_supported();
+ }
+
+ public boolean injectGnssMeasurementCorrections(
+ GnssMeasurementCorrections measurementCorrections) {
+ return native_inject_gnss_measurement_corrections(measurementCorrections);
+ }
+ }
+
+ private static native boolean native_is_measurement_corrections_supported();
+
+ private static native boolean native_inject_gnss_measurement_corrections(
+ GnssMeasurementCorrections measurementCorrections);
+}
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 1fc7192..844735a 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -11,13 +11,12 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.location;
import android.content.Context;
-import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementsEvent;
import android.location.IGnssMeasurementsListener;
import android.os.Handler;
@@ -42,7 +41,6 @@
private boolean mIsCollectionStarted;
private boolean mEnableFullTracking;
- private int mGnssEngineCapabilities;
protected GnssMeasurementsProvider(Context context, Handler handler) {
this(context, handler, new GnssMeasurementProviderNative());
@@ -87,21 +85,6 @@
}
}
- /**
- * Injects GNSS measurement corrections into the GNSS chipset.
- *
- * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
- * measurement corrections to be injected into the GNSS chipset.
- */
- public void injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- mHandler.post(() -> {
- if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
- Log.e(TAG, "Failure in injecting GNSS corrections.");
- }
- });
- }
-
@Override
protected void unregisterFromService() {
boolean stopped = mNative.stopMeasurementCollection();
@@ -121,20 +104,20 @@
});
}
- /** Updates the framework about the capabilities of the GNSS chipset */
- public void onCapabilitiesUpdated(int capabilities) {
- mGnssEngineCapabilities = capabilities;
- boolean isGnssMeasurementsSupported =
- (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0;
+ /** Handle GNSS capabilities update from the GNSS HAL implementation. */
+ public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ final boolean isGnssMeasurementsSupported = hasSubHalCapabilityFlags
+ ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0
+ : mNative.isMeasurementSupported();
setSupported(isGnssMeasurementsSupported);
updateResult();
}
- /** Obtains the GNSS engine capabilities. */
- public int getGnssCapabilities() {
- return mGnssEngineCapabilities;
- }
-
public void onGpsEnabledChanged() {
tryUpdateRegistrationWithService();
updateResult();
@@ -195,11 +178,6 @@
public boolean stopMeasurementCollection() {
return native_stop_measurement_collection();
}
-
- public boolean injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- return native_inject_gnss_measurement_corrections(measurementCorrections);
- }
}
private static native boolean native_is_measurement_supported();
@@ -207,7 +185,4 @@
private static native boolean native_start_measurement_collection(boolean enableFullTracking);
private static native boolean native_stop_measurement_collection();
-
- private static native boolean native_inject_gnss_measurement_corrections(
- GnssMeasurementCorrections measurementCorrections);
}
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 80a3f9b..7e8b599 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.location;
@@ -51,7 +51,6 @@
mNative = aNative;
}
- // TODO(b/37460011): Use this with death recovery logic.
void resumeIfStarted() {
if (DEBUG) {
Log.d(TAG, "resumeIfStarted");
@@ -92,7 +91,16 @@
);
}
- public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
+ /** Handle GNSS capabilities update from the GNSS HAL implementation */
+ public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ final boolean isGnssNavigationMessageSupported = hasSubHalCapabilityFlags
+ ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES) != 0
+ : mNative.isNavigationMessageSupported();
setSupported(isGnssNavigationMessageSupported);
updateResult();
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 270fbc6..3872523 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,9 +17,14 @@
package com.android.server.media.projection;
import android.Manifest;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.IProcessObserver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.projection.IMediaProjection;
@@ -29,6 +34,8 @@
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -38,6 +45,7 @@
import android.util.Slog;
import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -63,6 +71,8 @@
private final Context mContext;
private final AppOpsManager mAppOps;
+ private final ActivityManagerInternal mActivityManagerInternal;
+ private final PackageManager mPackageManager;
private final MediaRouter mMediaRouter;
private final MediaRouterCallback mMediaRouterCallback;
@@ -77,6 +87,8 @@
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
mCallbackDelegate = new CallbackDelegate();
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mPackageManager = mContext.getPackageManager();
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouterCallback = new MediaRouterCallback();
Watchdog.getInstance().addMonitor(this);
@@ -88,6 +100,21 @@
false /*allowIsolated*/);
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
+ serviceTypes);
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ }
+ });
}
@Override
@@ -105,6 +132,29 @@
synchronized (mLock) { /* check for deadlock */ }
}
+ /**
+ * Called when the set of active foreground service types for a given {@code uid / pid} changes.
+ * We will stop the active projection grant if its owner targets {@code Q} or higher and has no
+ * started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
+ */
+ private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ synchronized (mLock) {
+ if (mProjectionGrant == null || mProjectionGrant.uid != uid) {
+ return;
+ }
+
+ if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) {
+ return;
+ }
+
+ if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
+ return;
+ }
+
+ mProjectionGrant.stop();
+ }
+ }
+
private void startProjectionLocked(final MediaProjection projection) {
if (mProjectionGrant != null) {
mProjectionGrant.stop();
@@ -229,10 +279,19 @@
if (packageName == null || packageName.isEmpty()) {
throw new IllegalArgumentException("package name must not be empty");
}
+
long callingToken = Binder.clearCallingIdentity();
+
MediaProjection projection;
try {
- projection = new MediaProjection(type, uid, packageName);
+ ApplicationInfo ai;
+ try {
+ ai = mPackageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No package matching :" + packageName);
+ }
+
+ projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion);
if (isPermanentGrant) {
mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
@@ -334,17 +393,19 @@
public final int uid;
public final String packageName;
public final UserHandle userHandle;
+ public final int targetSdkVersion;
private IMediaProjectionCallback mCallback;
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private int mType;
- public MediaProjection(int type, int uid, String packageName) {
+ MediaProjection(int type, int uid, String packageName, int targetSdkVersion) {
mType = type;
this.uid = uid;
this.packageName = packageName;
userHandle = new UserHandle(UserHandle.getUserId(uid));
+ this.targetSdkVersion = targetSdkVersion;
}
@Override // Binder call
@@ -400,6 +461,14 @@
+ " attempted to start already started MediaProjection");
return;
}
+
+ if (targetSdkVersion >= Build.VERSION_CODES.Q
+ && !mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ throw new SecurityException("Media projections require a foreground service"
+ + " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
+ }
+
mCallback = callback;
registerCallback(mCallback);
try {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d9ab132..de93120 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -438,6 +438,8 @@
if (getAudioAttributes() != null) {
getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
}
+ proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
+ proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
proto.end(token);
}
@@ -458,6 +460,7 @@
pw.println(prefix + this);
prefix = prefix + " ";
pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
+ pw.println(prefix + "opPkg=" + sbn.getOpPkg());
pw.println(prefix + "icon=" + iconStr);
pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
pw.println(prefix + "pri=" + notification.priority);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a679601..ec2ff28 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20173,21 +20173,20 @@
}
@Override
- public String getContentCaptureServicePackageName() {
- String contentCaptureServiceName =
- mContext.getString(R.string.config_defaultContentCaptureService);
+ public String getSystemCaptionsServicePackageName() {
+ String flattenedSystemCaptionsServiceComponentName =
+ mContext.getString(R.string.config_defaultSystemCaptionsService);
- if (TextUtils.isEmpty(contentCaptureServiceName)) {
+ if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
return null;
}
- int separatorIndex = contentCaptureServiceName.indexOf("/");
-
- if (separatorIndex < 0) {
+ ComponentName systemCaptionsServiceComponentName =
+ ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
+ if (systemCaptionsServiceComponentName == null) {
return null;
}
-
- return contentCaptureServiceName.substring(0, separatorIndex);
+ return systemCaptionsServiceComponentName.getPackageName();
}
public String getIncidentReportApproverPackageName() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index aced1a2..459de1a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2693,6 +2693,7 @@
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
// profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
+ // longVersionCode - integer version of the package.
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
@@ -2720,6 +2721,8 @@
}
sb.append(" ");
sb.append(ai.isProfileableByShell() ? "1" : "0");
+ sb.append(" ");
+ sb.append(String.valueOf(ai.longVersionCode));
sb.append("\n");
writer.append(sb);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e9077a9..0a17e130 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -748,11 +748,11 @@
grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
STORAGE_PERMISSIONS);
- // Content Capture Service
- String contentCaptureServicePackageName =
- mContext.getPackageManager().getContentCaptureServicePackageName();
- if (!TextUtils.isEmpty(contentCaptureServicePackageName)) {
- grantPermissionsToSystemPackage(contentCaptureServicePackageName, userId,
+ // System Captions Service
+ String systemCaptionsServicePackageName =
+ mContext.getPackageManager().getSystemCaptionsServicePackageName();
+ if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
+ grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
MICROPHONE_PERMISSIONS);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index c3582ea..1e2dad9 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -24,6 +25,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -220,9 +222,7 @@
@Override
public ParceledListSlice getAvailableRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getAvailableRollbacks");
+ enforceManageRollbacks("getAvailableRollbacks");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -239,9 +239,7 @@
@Override
public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getRecentlyExecutedRollbacks");
+ enforceManageRollbacks("getRecentlyCommittedRollbacks");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -259,9 +257,7 @@
@Override
public void commitRollback(int rollbackId, ParceledListSlice causePackages,
String callerPackageName, IntentSender statusReceiver) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "executeRollback");
+ enforceManageRollbacks("executeRollback");
final int callingUid = Binder.getCallingUid();
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -462,7 +458,7 @@
// TODO: This call emits the warning "Calling a method in the
// system process without a qualified user". Fix that.
// TODO: Limit this to receivers holding the
- // MANAGE_ROLLBACKS permission?
+ // MANAGE_ROLLBACKS or TEST_MANAGE_ROLLBACKS permissions?
mContext.sendBroadcast(broadcast);
});
}
@@ -484,7 +480,7 @@
@Override
public void reloadPersistedData() {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
"reloadPersistedData");
synchronized (mLock) {
@@ -499,7 +495,7 @@
@Override
public void expireRollbackForPackage(String packageName) {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -894,12 +890,19 @@
Log.i(TAG, "Enabling rollback for install of " + packageName
+ ", session:" + session.sessionId);
+ String installerPackageName = session.getInstallerPackageName();
+ if (!enableRollbackAllowed(installerPackageName, packageName)) {
+ Log.e(TAG, "Installer " + installerPackageName
+ + " is not allowed to enable rollback on " + packageName);
+ return false;
+ }
+
VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
// Get information about the currently installed package.
PackageManager pm = mContext.getPackageManager();
- PackageInfo pkgInfo = null;
+ final PackageInfo pkgInfo;
try {
pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
} catch (PackageManager.NameNotFoundException e) {
@@ -1086,6 +1089,44 @@
}
/**
+ * Returns true if the installer is allowed to enable rollback for the
+ * given named package, false otherwise.
+ */
+ private boolean enableRollbackAllowed(String installerPackageName, String packageName) {
+ if (installerPackageName == null) {
+ return false;
+ }
+
+ PackageManager pm = mContext.getPackageManager();
+ boolean manageRollbacksGranted = pm.checkPermission(
+ Manifest.permission.MANAGE_ROLLBACKS,
+ installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+ boolean testManageRollbacksGranted = pm.checkPermission(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+ // For now only allow rollbacks for modules or for testing.
+ return (isModule(packageName) && manageRollbacksGranted)
+ || testManageRollbacksGranted;
+ }
+
+ /**
+ * Returns true if the package name is the name of a module.
+ */
+ private boolean isModule(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ final ModuleInfo moduleInfo;
+ try {
+ moduleInfo = pm.getModuleInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+
+ return moduleInfo != null;
+ }
+
+ /**
* Gets the version of the package currently installed.
* Returns null if the package is not currently installed.
*/
@@ -1311,4 +1352,15 @@
}
}
}
+
+ private void enforceManageRollbacks(@NonNull String message) {
+ if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MANAGE_ROLLBACKS))
+ && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS))) {
+ throw new SecurityException(message + " requires "
+ + Manifest.permission.MANAGE_ROLLBACKS + " or "
+ + Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ }
+ }
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 050a079..00b815a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -109,6 +109,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index caba3af..a4955f0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -71,6 +71,7 @@
static jmethodID method_reportNavigationMessages;
static jmethodID method_reportLocationBatch;
static jmethodID method_reportGnssServiceDied;
+static jmethodID method_setMeasurementCorrectionsCapabilities;
static jmethodID method_correctionsGetLatitudeDegrees;
static jmethodID method_correctionsGetLongitudeDegrees;
static jmethodID method_correctionsGetAltitudeMeters;
@@ -158,10 +159,9 @@
using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback;
using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
-using IMeasurementCorrections =
- android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
-using GnssSingleSatCorrectionFlags =
- android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
@@ -201,7 +201,6 @@
sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
-
sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -572,7 +571,9 @@
template <class T>
Return<void> gnssLocationCbImpl(const T& location);
- // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics
+ Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
+
+ // TODO: Reconsider allocation cost vs threadsafety on these statics
static const char* sNmeaString;
static size_t sNmeaStringLength;
};
@@ -694,16 +695,29 @@
}
Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
- ALOGD("%s: %du\n", __func__, capabilities);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
+ return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+ /* hasSubHalCapabilityFlags = */ true);
}
Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
+ return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+ /* hasSubHalCapabilityFlags = */ false);
+}
+
+Return <void> GnssCallback::gnssSetCapabilitesCbImpl(uint32_t capabilities,
+ bool hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ ALOGD("%s: capabilities=%du, hasSubHalCapabilityFlags=%d\n", __func__, capabilities,
+ hasSubHalCapabilityFlags);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities,
+ boolToJbool(hasSubHalCapabilityFlags));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
}
Return<void> GnssCallback::gnssAcquireWakelockCb() {
@@ -1153,6 +1167,22 @@
}
/*
+ * MeasurementCorrectionsCallback implements callback methods of interface
+ * IMeasurementCorrectionsCallback.hal.
+ */
+struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+};
+
+Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) {
+ ALOGD("%s: %du\n", __func__, capabilities);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setMeasurementCorrectionsCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+/*
* GnssNiCallback implements callback methods required by the IGnssNi interface.
*/
struct GnssNiCallback : public IGnssNiCallback {
@@ -1434,7 +1464,7 @@
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
- method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+ method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(IZ)V");
method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
"(Ljava/lang/String;)V");
@@ -1474,6 +1504,9 @@
"(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
+ method_setMeasurementCorrectionsCapabilities = env->GetMethodID(clazz,
+ "setMeasurementCorrectionsCapabilities", "(I)V");
+
jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
method_correctionsGetLatitudeDegrees = env->GetMethodID(
measCorrClass,"getLatitudeDegrees", "()D");
@@ -1591,7 +1624,7 @@
}
if (gnssHal_V2_0 != nullptr) {
- // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
+ // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
if (!gnssMeasurement.isOk()) {
ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
@@ -1795,6 +1828,12 @@
gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
}
+ if (gnssCorrectionsIface != nullptr) {
+ sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+ new MeasurementCorrectionsCallback();
+ gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+ }
+
return JNI_TRUE;
}
@@ -2154,7 +2193,7 @@
jobject /* obj */) {
jstring result = nullptr;
/*
- * TODO(b/33089503) : Create a jobject to represent GnssDebug.
+ * TODO: Create a jobject to represent GnssDebug.
*/
std::stringstream internalState;
@@ -2380,13 +2419,25 @@
return boolToJbool(result.isOk());
}
-static jboolean android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections(
+static jboolean
+ android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported(
+ JNIEnv* env, jclass clazz) {
+ if (gnssCorrectionsIface != nullptr) {
+ return JNI_TRUE;
+ }
+
+ return JNI_FALSE;
+}
+
+static jboolean
+ android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
JNIEnv* env,
jobject obj /* clazz*/,
jobject correctionsObj) {
if (gnssCorrectionsIface == nullptr) {
- ALOGW("Trying to inject GNSS corrections on a chipset that does not support them.");
+ ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
+ " support them.");
return JNI_FALSE;
}
@@ -2882,18 +2933,25 @@
static const JNINativeMethod sMeasurementMethods[] = {
/* name, signature, funcPtr */
{"native_is_measurement_supported", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_is_measurement_supported)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_is_measurement_supported)},
{"native_start_measurement_collection", "(Z)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_start_measurement_collection)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_start_measurement_collection)},
{"native_stop_measurement_collection", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+};
+
+static const JNINativeMethod sMeasurementCorrectionsMethods[] = {
+ /* name, signature, funcPtr */
+ {"native_is_measurement_corrections_supported", "()Z",
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)},
{"native_inject_gnss_measurement_corrections",
- "(Landroid/location/GnssMeasurementCorrections;)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections)},
+ "(Landroid/location/GnssMeasurementCorrections;)Z",
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)},
};
static const JNINativeMethod sNavigationMessageMethods[] = {
@@ -2992,6 +3050,11 @@
NELEM(sMeasurementMethods));
jniRegisterNativeMethods(
env,
+ "com/android/server/location/GnssMeasurementCorrectionsProvider",
+ sMeasurementCorrectionsMethods,
+ NELEM(sMeasurementCorrectionsMethods));
+ jniRegisterNativeMethods(
+ env,
"com/android/server/location/GnssNavigationMessageProvider",
sNavigationMessageMethods,
NELEM(sNavigationMessageMethods));
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6386b3b3..7c91b64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -15,7 +15,10 @@
*/
package com.android.server;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -254,14 +257,22 @@
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
+ setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID);
+ }
+
+ private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) {
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
- TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ callingUid, TEST_CALLING_PACKAGE);
}
private PendingIntent getNewMockPendingIntent() {
+ return getNewMockPendingIntent(TEST_CALLING_UID);
+ }
+
+ private PendingIntent getNewMockPendingIntent(int mockUid) {
final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
- when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID);
+ when(mockPi.getCreatorUid()).thenReturn(mockUid);
when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
return mockPi;
}
@@ -724,6 +735,91 @@
verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
}
+ @Test
+ public void alarmCountKeyedOnCallingUid() {
+ final int mockCreatorUid = 431412;
+ final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi);
+ assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
+ }
+
+ @Test
+ public void alarmCountOnSet() {
+ final int numAlarms = 103;
+ final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+ for (int i = 1; i <= numAlarms; i++) {
+ setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent());
+ assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ }
+ }
+
+ @Test
+ public void alarmCountOnExpiration() throws InterruptedException {
+ final int numAlarms = 8; // This test is slow
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ int expired = 0;
+ while (expired < numAlarms) {
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ expired++;
+ assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ }
+
+ @Test
+ public void alarmCountOnUidRemoved() {
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ mService.removeLocked(TEST_CALLING_UID);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
+ public void alarmCountOnPackageRemoved() {
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ mService.removeLocked(TEST_CALLING_PACKAGE);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
+ public void alarmCountOnUserRemoved() {
+ final int mockUserId = 15;
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
+ getNewMockPendingIntent(mockUid), mockUid);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.size());
+ mService.removeUserLocked(mockUserId);
+ assertEquals(0, mService.mAlarmsPerUid.size());
+ }
+
+ @Test
+ public void alarmCountOnAlarmRemoved() {
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ for (int i = 0; i < numAlarms; i++) {
+ mService.removeLocked(pis[i], null);
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 8e78a56..c45122e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -52,6 +52,7 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
import android.os.Build;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.DataUnit;
@@ -102,6 +103,8 @@
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+
// Freeze the clocks at this moment in time
JobSchedulerService.sSystemClock =
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 26b1224..caf6c9c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1138,7 +1138,7 @@
}
@Override
- public String getContentCaptureServicePackageName() throws RemoteException {
+ public String getSystemCaptionsServicePackageName() throws RemoteException {
return null;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 1e02a12..329af95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -38,9 +38,7 @@
import static org.mockito.ArgumentMatchers.eq;
import android.app.AppOpsManager;
-import android.app.IActivityManager;
import android.app.IActivityTaskManager;
-import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
@@ -50,7 +48,6 @@
import android.util.Log;
import android.view.IWindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.server.am.AssistDataRequester;
@@ -88,12 +85,10 @@
private static final int TEST_UID = 0;
private static final String TEST_PACKAGE = "";
- private Context mContext;
private AssistDataRequester mDataRequester;
private Callbacks mCallbacks;
private Object mCallbacksLock;
private Handler mHandler;
- private IActivityManager mAm;
private IActivityTaskManager mAtm;
private IWindowManager mWm;
private AppOpsManager mAppOpsManager;
@@ -109,7 +104,6 @@
@Before
public void setUp() throws Exception {
- mAm = mock(IActivityManager.class);
mAtm = mock(IActivityTaskManager.class);
mWm = mock(IWindowManager.class);
mAppOpsManager = mock(AppOpsManager.class);
@@ -118,7 +112,7 @@
mCallbacks = new Callbacks();
mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
-
+ mDataRequester.mActivityTaskManager = mAtm;
// Gate the continuation of the assist data callbacks until we are ready within the tests
mGate = new CountDownLatch(1);
doAnswer(invocation -> {
@@ -155,7 +149,6 @@
.checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
}
- @FlakyTest(bugId = 124088319)
@Test
public void testRequestData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -176,7 +169,6 @@
assertReceivedDataCount(0, 0, 0, 0);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -187,7 +179,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testProcessPendingData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -245,7 +236,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -259,7 +249,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -270,7 +259,6 @@
assertReceivedDataCount(5, 5, 0, 0);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 17e2e90..30dcaa0 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -53,6 +53,9 @@
* <li>Operator name, short name and numeric id
* <li>Network selection mode
* </ul>
+ *
+ * For historical reasons this class is not declared as final; however,
+ * it should be treated as though it were final.
*/
public class ServiceState implements Parcelable {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index c4c5983..2edef83 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2595,7 +2595,9 @@
* {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
* it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
* is used to determine which modem is preferred.
- * @param needValidation whether validation is needed before switch happens.
+ * @param needValidation whether Telephony will wait until the network is validated by
+ * connectivity service before switching data to it. More details see
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
* @param executor The executor of where the callback will execute.
* @param callback Callback will be triggered once it succeeds or failed.
* See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c91f16b..282b1ff 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4779,18 +4779,22 @@
* Registers a listener object to receive notification of changes
* in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener}
- * and specify at least one telephony state of interest in
- * the events argument.
+ * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
+ * state of interest in the events argument.
*
- * At registration, and when a specified telephony state
- * changes, the telephony manager invokes the appropriate
- * callback method on the listener object and passes the
- * current (updated) values.
+ * At registration, and when a specified telephony state changes, the telephony manager invokes
+ * the appropriate callback method on the listener object and passes the current (updated)
+ * values.
* <p>
- * To unregister a listener, pass the listener object and set the
- * events argument to
+ * To un-register a listener, pass the listener object and set the events argument to
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+ * pass a separate listener object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}.
+ *
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
@@ -4805,17 +4809,18 @@
if (mContext == null) return;
try {
boolean notifyNow = (getITelephony() != null);
- // If the listener has not explicitly set the subId (for example, created with the
- // default constructor), replace the subId so it will listen to the account the
- // telephony manager is created with.
- if (listener.mSubId == null) {
- listener.mSubId = mSubId;
- }
-
ITelephonyRegistry registry = getTelephonyRegistry();
if (registry != null) {
- registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+ // listen to the subId the telephony manager is created with. Ignore subId in
+ // PhoneStateListener.
+ registry.listenForSubscriber(mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
+ // TODO: remove this once we remove PhoneStateListener constructor with subId.
+ if (events == PhoneStateListener.LISTEN_NONE) {
+ listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ } else {
+ listener.mSubId = mSubId;
+ }
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
@@ -10368,7 +10373,7 @@
@IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
SET_OPPORTUNISTIC_SUB_SUCCESS,
SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
- SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+ SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
public @interface SetOpportunisticSubscriptionResult {}
/**
@@ -10382,9 +10387,9 @@
public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
/**
- * The parameter passed in is invalid.
+ * The subscription is not valid. It must be an active opportunistic subscription.
*/
- public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+ public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 9d78bf4..4886a3f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -317,7 +317,8 @@
Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
ApplicationInfo callingPackageInfo = null;
try {
- callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+ callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+ callingPackage, 0, UserHandle.getUserId(uid));
if (callingPackageInfo.isSystemApp()) {
isPreinstalled = true;
if (callingPackageInfo.isPrivilegedApp()) {
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b31235b..41cb74a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -4,7 +4,7 @@
-->
<configuration description="Runs WindowManager Flicker Tests">
<option name="test-tag" value="FlickerTests" />
- <target_preparer class="com.google.android.tradefed.targetprep.GoogleDeviceSetup">
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on" />
<!-- prevents the phone from restarting -->
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 48bc9e8..377abc3 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -87,7 +87,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
// Register a broadcast receiver for notification when the
// rollback has been committed.
@@ -175,7 +175,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -233,7 +233,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -290,7 +290,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -343,7 +343,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.WRITE_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
@@ -403,7 +403,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.WRITE_DEVICE_CONFIG,
Manifest.permission.SET_TIME);
@@ -475,7 +475,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
RollbackTestUtils.uninstall(TEST_APP_A);
@@ -512,7 +512,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -540,7 +540,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.installSplit(false,
@@ -598,7 +598,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
@@ -693,6 +693,75 @@
}
/**
+ * Test that you cannot enable rollback for a package without the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @Test
+ public void testEnableRollbackPermission() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+ // We expect v2 of the app was installed, but rollback has not
+ // been enabled.
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // TODO: See if there is a way to remove this race condition
+ // between when the app is installed and when the rollback
+ // would be made available.
+ Thread.sleep(1000);
+
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test that you cannot enable rollback for a non-module package when
+ * holding the MANAGE_ROLLBACKS permission.
+ */
+ @Test
+ public void testNonModuleEnableRollback() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+ // We expect v2 of the app was installed, but rollback has not
+ // been enabled because the test app is not a module.
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // TODO: See if there is a way to remove this race condition
+ // between when the app is installed and when the rollback
+ // would be made available.
+ Thread.sleep(1000);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
* Test rollback of multi-package installs is implemented.
*/
@Test
@@ -701,7 +770,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
@@ -760,7 +829,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.KILL_BACKGROUND_PROCESSES,
Manifest.permission.RESTART_PACKAGES);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 047451b..7e711c2 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -63,7 +63,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
}
/**
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
new file mode 100644
index 0000000..75752c3
--- /dev/null
+++ b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.apf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.shared.ParcelableTestUtil;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.TestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfCapabilitiesTest {
+ @Test
+ public void testParcelUnparcel() {
+ final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
+ ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
+
+ TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
+ }
+}