summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt277
-rw-r--r--api/system-current.txt55
-rw-r--r--api/system-removed.txt3
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp57
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.h26
-rw-r--r--cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp6
-rw-r--r--cmds/statsd/src/anomaly/DurationAnomalyTracker.h6
-rw-r--r--cmds/statsd/src/atoms.proto97
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp12
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h19
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h3
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h3
-rw-r--r--cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp243
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp17
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp17
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp10
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp82
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp18
-rw-r--r--core/java/android/app/Notification.java32
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java19
-rw-r--r--core/java/android/content/Context.java1
-rw-r--r--core/java/android/content/pm/PackageManager.java2
-rw-r--r--core/java/android/content/pm/PackageParser.java257
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java75
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java49
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java81
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java13
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java62
-rw-r--r--core/java/android/hardware/location/ContextHubMessage.java9
-rw-r--r--core/java/android/hardware/location/NanoApp.java5
-rw-r--r--core/java/android/hardware/location/NanoAppFilter.java5
-rw-r--r--core/java/android/hardware/location/NanoAppInstanceInfo.java3
-rw-r--r--core/java/android/net/IpSecAlgorithm.java25
-rw-r--r--core/java/android/os/Binder.java49
-rw-r--r--core/java/android/os/IUserManager.aidl2
-rw-r--r--core/java/android/os/Seccomp.java3
-rw-r--r--core/java/android/os/UserManager.java28
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java63
-rw-r--r--core/java/android/view/Surface.java5
-rw-r--r--core/java/android/widget/MediaController2.java236
-rw-r--r--core/java/com/android/internal/app/ResolverComparator.java4
-rw-r--r--core/java/com/android/internal/os/Zygote.java4
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java4
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java5
-rw-r--r--core/jni/android_os_seccomp.cpp19
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/anim/cross_profile_apps_thumbnail_enter.xml41
-rw-r--r--core/res/res/anim/task_open_enter.xml2
-rw-r--r--core/res/res/anim/task_open_enter_cross_profile_apps.xml41
-rw-r--r--core/res/res/values/dimens.xml4
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/app/NotificationTest.java57
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--data/etc/platform.xml4
-rw-r--r--data/etc/privapp-permissions-platform.xml9
-rw-r--r--media/java/android/media/update/ApiLoader.java56
-rw-r--r--media/java/android/media/update/MediaController2Provider.java55
-rw-r--r--media/java/android/media/update/StaticProvider.java34
-rw-r--r--media/java/android/media/update/ViewProvider.java51
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--services/core/java/com/android/server/IpSecService.java37
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java55
-rw-r--r--services/core/java/com/android/server/content/SyncJobService.java53
-rw-r--r--services/core/java/com/android/server/content/SyncLogger.java7
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java2
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java18
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java18
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java32
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java90
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java4
-rw-r--r--services/core/java/com/android/server/pm/Settings.java10
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java104
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/OWNERS1
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java55
-rw-r--r--services/core/java/com/android/server/wm/AppWindowThumbnail.java9
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java39
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java105
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java13
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java13
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java162
-rw-r--r--telecomm/java/android/telecom/Log.java53
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java1
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java (renamed from telephony/java/android/telephony/RadioNetworkConstants.java)14
-rw-r--r--telephony/java/android/telephony/RadioAccessSpecifier.java12
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java58
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java153
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java47
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingRequest.java8
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingResult.java9
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingResultCallback.java5
-rw-r--r--wifi/java/android/net/wifi/rtt/ResponderConfig.java10
-rw-r--r--wifi/java/android/net/wifi/rtt/WifiRttManager.java37
-rw-r--r--wifi/java/android/net/wifi/rtt/package.html2
110 files changed, 2610 insertions, 1144 deletions
diff --git a/api/current.txt b/api/current.txt
index b2121a85313d..73d3990e7408 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9340,6 +9340,7 @@ package android.content {
field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
+ field public static final java.lang.String WIFI_RTT_RANGING_SERVICE = "wifirtt";
field public static final java.lang.String WIFI_SERVICE = "wifi";
field public static final java.lang.String WINDOW_SERVICE = "window";
}
@@ -11122,6 +11123,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final java.lang.String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
+ field public static final java.lang.String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
@@ -15531,6 +15533,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_HYPERFOCAL_DISTANCE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INTRINSIC_CALIBRATION;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_POSE_REFERENCE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
@@ -15603,6 +15606,8 @@ package android.hardware.camera2 {
method public abstract void createReprocessableCaptureSessionByConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();
field public static final int TEMPLATE_MANUAL = 6; // 0x6
+ field public static final int TEMPLATE_MOTION_TRACKING_BEST = 8; // 0x8
+ field public static final int TEMPLATE_MOTION_TRACKING_PREVIEW = 7; // 0x7
field public static final int TEMPLATE_PREVIEW = 1; // 0x1
field public static final int TEMPLATE_RECORD = 3; // 0x3
field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
@@ -15705,6 +15710,7 @@ package android.hardware.camera2 {
field public static final int CONTROL_AWB_STATE_SEARCHING = 1; // 0x1
field public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0; // 0x0
field public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6; // 0x6
+ field public static final int CONTROL_CAPTURE_INTENT_MOTION_TRACKING = 7; // 0x7
field public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1; // 0x1
field public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2; // 0x2
field public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3; // 0x3
@@ -15771,6 +15777,8 @@ package android.hardware.camera2 {
field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
+ field public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; // 0x1
+ field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0
field public static final int LENS_STATE_MOVING = 1; // 0x1
field public static final int LENS_STATE_STATIONARY = 0; // 0x0
field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
@@ -15784,6 +15792,7 @@ package android.hardware.camera2 {
field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10; // 0xa
field public static final int REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4; // 0x4
field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
@@ -20181,6 +20190,13 @@ package android.icu.util {
ctor public ICUUncheckedIOException(java.lang.String, java.lang.Throwable);
}
+ public class IllformedLocaleException extends java.lang.RuntimeException {
+ ctor public IllformedLocaleException();
+ ctor public IllformedLocaleException(java.lang.String);
+ ctor public IllformedLocaleException(java.lang.String, int);
+ method public int getErrorIndex();
+ }
+
public class IndianCalendar extends android.icu.util.Calendar {
ctor public IndianCalendar();
ctor public IndianCalendar(android.icu.util.TimeZone);
@@ -27781,6 +27797,55 @@ package android.net.wifi.p2p.nsd {
}
+package android.net.wifi.rtt {
+
+ public final class RangingRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public static int getMaxPeers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingRequest> CREATOR;
+ }
+
+ public static final class RangingRequest.Builder {
+ ctor public RangingRequest.Builder();
+ method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoint(android.net.wifi.ScanResult);
+ method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoints(java.util.List<android.net.wifi.ScanResult>);
+ method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(android.net.MacAddress);
+ method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(android.net.wifi.aware.PeerHandle);
+ method public android.net.wifi.rtt.RangingRequest build();
+ }
+
+ public final class RangingResult implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDistanceMm();
+ method public int getDistanceStdDevMm();
+ method public android.net.MacAddress getMacAddress();
+ method public android.net.wifi.aware.PeerHandle getPeerHandle();
+ method public long getRangingTimestampUs();
+ method public int getRssi();
+ method public int getStatus();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingResult> CREATOR;
+ field public static final int STATUS_FAIL = 1; // 0x1
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public abstract class RangingResultCallback {
+ ctor public RangingResultCallback();
+ method public abstract void onRangingFailure(int);
+ method public abstract void onRangingResults(java.util.List<android.net.wifi.rtt.RangingResult>);
+ field public static final int STATUS_CODE_FAIL = 1; // 0x1
+ field public static final int STATUS_CODE_FAIL_RTT_NOT_AVAILABLE = 2; // 0x2
+ }
+
+ public class WifiRttManager {
+ method public boolean isAvailable();
+ method public void startRanging(android.net.wifi.rtt.RangingRequest, android.net.wifi.rtt.RangingResultCallback, android.os.Handler);
+ field public static final java.lang.String ACTION_WIFI_RTT_STATE_CHANGED = "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
+ }
+
+}
+
package android.nfc {
public class FormatException extends java.lang.Exception {
@@ -40381,6 +40446,113 @@ package android.telecom {
package android.telephony {
+ public final class AccessNetworkConstants {
+ ctor public AccessNetworkConstants();
+ }
+
+ public static final class AccessNetworkConstants.AccessNetworkType {
+ ctor public AccessNetworkConstants.AccessNetworkType();
+ field public static final int CDMA2000 = 4; // 0x4
+ field public static final int EUTRAN = 3; // 0x3
+ field public static final int GERAN = 1; // 0x1
+ field public static final int IWLAN = 5; // 0x5
+ field public static final int UTRAN = 2; // 0x2
+ }
+
+ public static final class AccessNetworkConstants.EutranBand {
+ ctor public AccessNetworkConstants.EutranBand();
+ field public static final int BAND_1 = 1; // 0x1
+ field public static final int BAND_10 = 10; // 0xa
+ field public static final int BAND_11 = 11; // 0xb
+ field public static final int BAND_12 = 12; // 0xc
+ field public static final int BAND_13 = 13; // 0xd
+ field public static final int BAND_14 = 14; // 0xe
+ field public static final int BAND_17 = 17; // 0x11
+ field public static final int BAND_18 = 18; // 0x12
+ field public static final int BAND_19 = 19; // 0x13
+ field public static final int BAND_2 = 2; // 0x2
+ field public static final int BAND_20 = 20; // 0x14
+ field public static final int BAND_21 = 21; // 0x15
+ field public static final int BAND_22 = 22; // 0x16
+ field public static final int BAND_23 = 23; // 0x17
+ field public static final int BAND_24 = 24; // 0x18
+ field public static final int BAND_25 = 25; // 0x19
+ field public static final int BAND_26 = 26; // 0x1a
+ field public static final int BAND_27 = 27; // 0x1b
+ field public static final int BAND_28 = 28; // 0x1c
+ field public static final int BAND_3 = 3; // 0x3
+ field public static final int BAND_30 = 30; // 0x1e
+ field public static final int BAND_31 = 31; // 0x1f
+ field public static final int BAND_33 = 33; // 0x21
+ field public static final int BAND_34 = 34; // 0x22
+ field public static final int BAND_35 = 35; // 0x23
+ field public static final int BAND_36 = 36; // 0x24
+ field public static final int BAND_37 = 37; // 0x25
+ field public static final int BAND_38 = 38; // 0x26
+ field public static final int BAND_39 = 39; // 0x27
+ field public static final int BAND_4 = 4; // 0x4
+ field public static final int BAND_40 = 40; // 0x28
+ field public static final int BAND_41 = 41; // 0x29
+ field public static final int BAND_42 = 42; // 0x2a
+ field public static final int BAND_43 = 43; // 0x2b
+ field public static final int BAND_44 = 44; // 0x2c
+ field public static final int BAND_45 = 45; // 0x2d
+ field public static final int BAND_46 = 46; // 0x2e
+ field public static final int BAND_47 = 47; // 0x2f
+ field public static final int BAND_48 = 48; // 0x30
+ field public static final int BAND_5 = 5; // 0x5
+ field public static final int BAND_6 = 6; // 0x6
+ field public static final int BAND_65 = 65; // 0x41
+ field public static final int BAND_66 = 66; // 0x42
+ field public static final int BAND_68 = 68; // 0x44
+ field public static final int BAND_7 = 7; // 0x7
+ field public static final int BAND_70 = 70; // 0x46
+ field public static final int BAND_8 = 8; // 0x8
+ field public static final int BAND_9 = 9; // 0x9
+ }
+
+ public static final class AccessNetworkConstants.GeranBand {
+ ctor public AccessNetworkConstants.GeranBand();
+ field public static final int BAND_450 = 3; // 0x3
+ field public static final int BAND_480 = 4; // 0x4
+ field public static final int BAND_710 = 5; // 0x5
+ field public static final int BAND_750 = 6; // 0x6
+ field public static final int BAND_850 = 8; // 0x8
+ field public static final int BAND_DCS1800 = 12; // 0xc
+ field public static final int BAND_E900 = 10; // 0xa
+ field public static final int BAND_ER900 = 14; // 0xe
+ field public static final int BAND_P900 = 9; // 0x9
+ field public static final int BAND_PCS1900 = 13; // 0xd
+ field public static final int BAND_R900 = 11; // 0xb
+ field public static final int BAND_T380 = 1; // 0x1
+ field public static final int BAND_T410 = 2; // 0x2
+ field public static final int BAND_T810 = 7; // 0x7
+ }
+
+ public static final class AccessNetworkConstants.UtranBand {
+ ctor public AccessNetworkConstants.UtranBand();
+ field public static final int BAND_1 = 1; // 0x1
+ field public static final int BAND_10 = 10; // 0xa
+ field public static final int BAND_11 = 11; // 0xb
+ field public static final int BAND_12 = 12; // 0xc
+ field public static final int BAND_13 = 13; // 0xd
+ field public static final int BAND_14 = 14; // 0xe
+ field public static final int BAND_19 = 19; // 0x13
+ field public static final int BAND_2 = 2; // 0x2
+ field public static final int BAND_20 = 20; // 0x14
+ field public static final int BAND_21 = 21; // 0x15
+ field public static final int BAND_22 = 22; // 0x16
+ field public static final int BAND_25 = 25; // 0x19
+ field public static final int BAND_26 = 26; // 0x1a
+ field public static final int BAND_3 = 3; // 0x3
+ field public static final int BAND_4 = 4; // 0x4
+ field public static final int BAND_5 = 5; // 0x5
+ field public static final int BAND_6 = 6; // 0x6
+ field public static final int BAND_7 = 7; // 0x7
+ field public static final int BAND_8 = 8; // 0x8
+ field public static final int BAND_9 = 9; // 0x9
+ }
+
public class CarrierConfigManager {
method public android.os.PersistableBundle getConfig();
method public android.os.PersistableBundle getConfigForSubId(int);
@@ -40905,111 +41077,6 @@ package android.telephony {
field public static final android.os.Parcelable.Creator<android.telephony.RadioAccessSpecifier> CREATOR;
}
- public final class RadioNetworkConstants {
- ctor public RadioNetworkConstants();
- }
-
- public static final class RadioNetworkConstants.EutranBands {
- ctor public RadioNetworkConstants.EutranBands();
- field public static final int BAND_1 = 1; // 0x1
- field public static final int BAND_10 = 10; // 0xa
- field public static final int BAND_11 = 11; // 0xb
- field public static final int BAND_12 = 12; // 0xc
- field public static final int BAND_13 = 13; // 0xd
- field public static final int BAND_14 = 14; // 0xe
- field public static final int BAND_17 = 17; // 0x11
- field public static final int BAND_18 = 18; // 0x12
- field public static final int BAND_19 = 19; // 0x13
- field public static final int BAND_2 = 2; // 0x2
- field public static final int BAND_20 = 20; // 0x14
- field public static final int BAND_21 = 21; // 0x15
- field public static final int BAND_22 = 22; // 0x16
- field public static final int BAND_23 = 23; // 0x17
- field public static final int BAND_24 = 24; // 0x18
- field public static final int BAND_25 = 25; // 0x19
- field public static final int BAND_26 = 26; // 0x1a
- field public static final int BAND_27 = 27; // 0x1b
- field public static final int BAND_28 = 28; // 0x1c
- field public static final int BAND_3 = 3; // 0x3
- field public static final int BAND_30 = 30; // 0x1e
- field public static final int BAND_31 = 31; // 0x1f
- field public static final int BAND_33 = 33; // 0x21
- field public static final int BAND_34 = 34; // 0x22
- field public static final int BAND_35 = 35; // 0x23
- field public static final int BAND_36 = 36; // 0x24
- field public static final int BAND_37 = 37; // 0x25
- field public static final int BAND_38 = 38; // 0x26
- field public static final int BAND_39 = 39; // 0x27
- field public static final int BAND_4 = 4; // 0x4
- field public static final int BAND_40 = 40; // 0x28
- field public static final int BAND_41 = 41; // 0x29
- field public static final int BAND_42 = 42; // 0x2a
- field public static final int BAND_43 = 43; // 0x2b
- field public static final int BAND_44 = 44; // 0x2c
- field public static final int BAND_45 = 45; // 0x2d
- field public static final int BAND_46 = 46; // 0x2e
- field public static final int BAND_47 = 47; // 0x2f
- field public static final int BAND_48 = 48; // 0x30
- field public static final int BAND_5 = 5; // 0x5
- field public static final int BAND_6 = 6; // 0x6
- field public static final int BAND_65 = 65; // 0x41
- field public static final int BAND_66 = 66; // 0x42
- field public static final int BAND_68 = 68; // 0x44
- field public static final int BAND_7 = 7; // 0x7
- field public static final int BAND_70 = 70; // 0x46
- field public static final int BAND_8 = 8; // 0x8
- field public static final int BAND_9 = 9; // 0x9
- }
-
- public static final class RadioNetworkConstants.GeranBands {
- ctor public RadioNetworkConstants.GeranBands();
- field public static final int BAND_450 = 3; // 0x3
- field public static final int BAND_480 = 4; // 0x4
- field public static final int BAND_710 = 5; // 0x5
- field public static final int BAND_750 = 6; // 0x6
- field public static final int BAND_850 = 8; // 0x8
- field public static final int BAND_DCS1800 = 12; // 0xc
- field public static final int BAND_E900 = 10; // 0xa
- field public static final int BAND_ER900 = 14; // 0xe
- field public static final int BAND_P900 = 9; // 0x9
- field public static final int BAND_PCS1900 = 13; // 0xd
- field public static final int BAND_R900 = 11; // 0xb
- field public static final int BAND_T380 = 1; // 0x1
- field public static final int BAND_T410 = 2; // 0x2
- field public static final int BAND_T810 = 7; // 0x7
- }
-
- public static final class RadioNetworkConstants.RadioAccessNetworks {
- ctor public RadioNetworkConstants.RadioAccessNetworks();
- field public static final int EUTRAN = 3; // 0x3
- field public static final int GERAN = 1; // 0x1
- field public static final int UTRAN = 2; // 0x2
- }
-
- public static final class RadioNetworkConstants.UtranBands {
- ctor public RadioNetworkConstants.UtranBands();
- field public static final int BAND_1 = 1; // 0x1
- field public static final int BAND_10 = 10; // 0xa
- field public static final int BAND_11 = 11; // 0xb
- field public static final int BAND_12 = 12; // 0xc
- field public static final int BAND_13 = 13; // 0xd
- field public static final int BAND_14 = 14; // 0xe
- field public static final int BAND_19 = 19; // 0x13
- field public static final int BAND_2 = 2; // 0x2
- field public static final int BAND_20 = 20; // 0x14
- field public static final int BAND_21 = 21; // 0x15
- field public static final int BAND_22 = 22; // 0x16
- field public static final int BAND_25 = 25; // 0x19
- field public static final int BAND_26 = 26; // 0x1a
- field public static final int BAND_3 = 3; // 0x3
- field public static final int BAND_4 = 4; // 0x4
- field public static final int BAND_5 = 5; // 0x5
- field public static final int BAND_6 = 6; // 0x6
- field public static final int BAND_7 = 7; // 0x7
- field public static final int BAND_8 = 8; // 0x8
- field public static final int BAND_9 = 9; // 0x9
- }
-
public class ServiceState implements android.os.Parcelable {
ctor public ServiceState();
ctor public ServiceState(android.telephony.ServiceState);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6a628a83c181..66f607849173 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -174,6 +174,7 @@ package android {
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
+ field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final java.lang.String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
@@ -1449,7 +1450,7 @@ package android.hardware.location {
method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
}
- public class ContextHubMessage {
+ public deprecated class ContextHubMessage {
ctor public ContextHubMessage(int, int, byte[]);
method public int describeContents();
method public byte[] getData();
@@ -1580,7 +1581,7 @@ package android.hardware.location {
field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
}
- public class NanoApp {
+ public deprecated class NanoApp {
ctor public NanoApp();
ctor public deprecated NanoApp(int, byte[]);
ctor public NanoApp(long, byte[]);
@@ -1628,7 +1629,7 @@ package android.hardware.location {
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
}
- public class NanoAppFilter {
+ public deprecated class NanoAppFilter {
ctor public NanoAppFilter(long, int, int, long);
method public int describeContents();
method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
@@ -1643,7 +1644,7 @@ package android.hardware.location {
field public static final int VENDOR_ANY = -1; // 0xffffffff
}
- public class NanoAppInstanceInfo {
+ public deprecated class NanoAppInstanceInfo {
ctor public NanoAppInstanceInfo();
method public int describeContents();
method public long getAppId();
@@ -3257,6 +3258,52 @@ package android.net.wifi.aware {
}
+package android.net.wifi.rtt {
+
+ public static final class RangingRequest.Builder {
+ method public android.net.wifi.rtt.RangingRequest.Builder addResponder(android.net.wifi.rtt.ResponderConfig);
+ }
+
+ public final class ResponderConfig implements android.os.Parcelable {
+ ctor public ResponderConfig(android.net.MacAddress, int, boolean, int, int, int, int, int);
+ ctor public ResponderConfig(android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int);
+ method public int describeContents();
+ method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult);
+ method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle);
+ method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(android.net.MacAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+ field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR;
+ field public static final int PREAMBLE_HT = 1; // 0x1
+ field public static final int PREAMBLE_LEGACY = 0; // 0x0
+ field public static final int PREAMBLE_VHT = 2; // 0x2
+ field public static final int RESPONDER_AP = 0; // 0x0
+ field public static final int RESPONDER_AWARE = 4; // 0x4
+ field public static final int RESPONDER_P2P_CLIENT = 3; // 0x3
+ field public static final int RESPONDER_P2P_GO = 2; // 0x2
+ field public static final int RESPONDER_STA = 1; // 0x1
+ field public final int centerFreq0;
+ field public final int centerFreq1;
+ field public final int channelWidth;
+ field public final int frequency;
+ field public final android.net.MacAddress macAddress;
+ field public final android.net.wifi.aware.PeerHandle peerHandle;
+ field public final int preamble;
+ field public final int responderType;
+ field public final boolean supports80211mc;
+ }
+
+ public class WifiRttManager {
+ method public void cancelRanging(android.os.WorkSource);
+ method public void startRanging(android.os.WorkSource, android.net.wifi.rtt.RangingRequest, android.net.wifi.rtt.RangingResultCallback, android.os.Handler);
+ }
+
+}
+
package android.nfc {
public final class NfcAdapter {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index f98d011faf77..a3bf576fb9a0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -142,10 +142,7 @@ package android.net.wifi {
}
public class WifiManager {
- method public deprecated java.util.List<android.net.wifi.BatchedScanResult> getBatchedScanResults();
method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
- method public deprecated boolean isBatchedScanSupported();
- method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
}
}
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 05c68e1fa471..f10b2cf618cd 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -162,45 +162,23 @@ int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) c
return 0;
}
-bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
- const DimToValMap& currentBucket) {
- if (currentBucketNum > mMostRecentBucketNum + 1) {
- addPastBucket(nullptr, currentBucketNum - 1);
- }
- for (auto itr = currentBucket.begin(); itr != currentBucket.end(); itr++) {
- if (itr->second + getSumOverPastBuckets(itr->first) > mAlert.trigger_if_sum_gt()) {
- return true;
- }
- }
- // In theory, we also need to check the dimsions not in the current bucket. In single-thread
- // mode, usually we could avoid the following loops.
- for (auto itr = mSumOverPastBuckets.begin(); itr != mSumOverPastBuckets.end(); itr++) {
- if (itr->second > mAlert.trigger_if_sum_gt()) {
- return true;
- }
- }
- return false;
-}
-
bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const HashableDimensionKey& key,
const int64_t& currentBucketValue) {
if (currentBucketNum > mMostRecentBucketNum + 1) {
+ // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
addPastBucket(key, 0, currentBucketNum - 1);
}
return mAlert.has_trigger_if_sum_gt()
&& getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
}
-void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
- // TODO: This should also take in the const HashableDimensionKey& key, to pass
- // more details to incidentd and to make mRefractoryPeriodEndsSec key-specific.
+void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableDimensionKey& key) {
// TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now.
- if (isInRefractoryPeriod(timestampNs)) {
+ if (isInRefractoryPeriod(timestampNs, key)) {
VLOG("Skipping anomaly declaration since within refractory period");
return;
}
- // TODO(guardrail): Consider guarding against too short refractory periods.
- mLastAnomalyTimestampNs = timestampNs;
+ mRefractoryPeriodEndsSec[key] = (timestampNs / NS_PER_SEC) + mAlert.refractory_period_secs();
// TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
// if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
@@ -208,7 +186,7 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
if (!mSubscriptions.empty()) {
if (mAlert.has_id()) {
ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
- informSubscribers();
+ informSubscribers(key);
} else {
ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
}
@@ -218,6 +196,7 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
+ // TODO: This should also take in the const HashableDimensionKey& key?
android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
mConfigKey.GetId(), mAlert.id());
}
@@ -227,24 +206,24 @@ void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
const HashableDimensionKey& key,
const int64_t& currentBucketValue) {
if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
- declareAnomaly(timestampNs);
+ declareAnomaly(timestampNs, key);
}
}
-void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
- const int64_t& currBucketNum,
- const DimToValMap& currentBucket) {
- if (detectAnomaly(currBucketNum, currentBucket)) {
- declareAnomaly(timestampNs);
+bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs,
+ const HashableDimensionKey& key) {
+ const auto& it = mRefractoryPeriodEndsSec.find(key);
+ if (it != mRefractoryPeriodEndsSec.end()) {
+ if ((timestampNs / NS_PER_SEC) <= it->second) {
+ return true;
+ } else {
+ mRefractoryPeriodEndsSec.erase(key);
+ }
}
+ return false;
}
-bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) const {
- return mLastAnomalyTimestampNs >= 0 &&
- timestampNs - mLastAnomalyTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
-}
-
-void AnomalyTracker::informSubscribers() {
+void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
VLOG("informSubscribers called.");
if (mSubscriptions.empty()) {
ALOGE("Attempt to call with no subscribers.");
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 2d5ab867da00..472c02c7ee7f 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -52,17 +52,14 @@ public:
const int64_t& bucketNum);
// Returns true if detected anomaly for the existing buckets on one or more dimension keys.
- bool detectAnomaly(const int64_t& currBucketNum, const DimToValMap& currentBucket);
bool detectAnomaly(const int64_t& currBucketNum, const HashableDimensionKey& key,
const int64_t& currentBucketValue);
// Informs incidentd about the detected alert.
- void declareAnomaly(const uint64_t& timestampNs);
+ void declareAnomaly(const uint64_t& timestampNs, const HashableDimensionKey& key);
// Detects the alert and informs the incidentd when applicable.
void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
- const DimToValMap& currentBucket);
- void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
const HashableDimensionKey& key,
const int64_t& currentBucketValue);
@@ -82,9 +79,11 @@ public:
return mAlert.trigger_if_sum_gt();
}
- // Helper function to return the timestamp of the last detected anomaly.
- inline int64_t getLastAnomalyTimestampNs() const {
- return mLastAnomalyTimestampNs;
+ // Returns the refractory period timestamp (in seconds) for the given key.
+ // If there is no stored refractory period ending timestamp, returns 0.
+ uint32_t getRefractoryPeriodEndsSec(const HashableDimensionKey& key) const {
+ const auto& it = mRefractoryPeriodEndsSec.find(key);
+ return it != mRefractoryPeriodEndsSec.end() ? it->second : 0;
}
inline int getNumOfPastBuckets() const {
@@ -121,8 +120,11 @@ protected:
// The bucket number of the last added bucket.
int64_t mMostRecentBucketNum = -1;
- // The timestamp when the last anomaly was declared.
- int64_t mLastAnomalyTimestampNs = -1;
+ // Map from each dimension to the timestamp that its refractory period (if this anomaly was
+ // declared for that dimension) ends, in seconds. Only anomalies that occur after this period
+ // ends will be declared.
+ // Entries may be, but are not guaranteed to be, removed after the period is finished.
+ unordered_map<HashableDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
void flushPastBuckets(const int64_t& currBucketNum);
@@ -133,7 +135,7 @@ protected:
// and remove any items with value 0.
void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
- bool isInRefractoryPeriod(const uint64_t& timestampNs) const;
+ bool isInRefractoryPeriod(const uint64_t& timestampNs, const HashableDimensionKey& key);
// Calculates the corresponding bucket index within the circular array.
size_t index(int64_t bucketNum) const;
@@ -142,12 +144,12 @@ protected:
virtual void resetStorage();
// Informs the subscribers that an anomaly has occurred.
- void informSubscribers();
+ void informSubscribers(const HashableDimensionKey& key);
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
FRIEND_TEST(GaugeMetricProducerTest, TestAnomalyDetection);
- FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetection);
+ FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
};
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index d30810fc800d..7576a38db51d 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -46,7 +46,7 @@ void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensio
if (itr->second != nullptr &&
static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
- declareAnomaly(timestampNs);
+ declareAnomaly(timestampNs, dimensionKey);
stopAlarm(dimensionKey);
}
}
@@ -55,7 +55,7 @@ void DurationAnomalyTracker::startAlarm(const HashableDimensionKey& dimensionKey
const uint64_t& timestampNs) {
uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
- if (isInRefractoryPeriod(timestampNs)) {
+ if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
return;
}
@@ -104,7 +104,7 @@ void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
// Now declare each of these alarms to have fired.
for (const auto& kv : matchedAlarms) {
- declareAnomaly(timestampNs /* TODO: , kv.first */);
+ declareAnomaly(timestampNs, kv.first);
mAlarms.erase(kv.first);
firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it.
}
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 182ce3ba74c0..de7093d3b1b6 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -50,7 +50,7 @@ public:
const uint64_t& timestampNs);
// Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
- // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
+ // and removes it from firedAlarms.
// TODO: This will actually be called from a different thread, so make it thread-safe!
// This means that almost every function in DurationAnomalyTracker needs to be locked.
// But this should be done at the level of StatsLogProcessor, which needs to lock
@@ -70,10 +70,10 @@ protected:
void resetStorage() override;
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
- FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
- FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
};
} // namespace statsd
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8637b79388ed..7f77ef7b7ff9 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -81,6 +81,9 @@ message Atom {
DropboxErrorChanged dropbox_error_changed = 45;
AnomalyDetected anomaly_detected = 46;
AppHook app_hook = 47;
+ AppStartChanged app_start_changed = 48;
+ AppStartCancelChanged app_start_cancel_changed = 49;
+ AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
@@ -855,6 +858,100 @@ message AnomalyDetected {
optional int64 alert_id = 3;
}
+message AppStartChanged {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1;
+
+ // The app package name.
+ optional string pkg_name = 2;
+
+ enum TransitionType {
+ APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ WARM = 1;
+ HOT = 2;
+ COLD = 3;
+ }
+ // The transition type.
+ optional TransitionType type = 3;
+
+ // The activity name.
+ optional string activity_name = 4;
+
+ // The name of the calling app. Empty if not set.
+ optional string calling_pkg_name = 5;
+
+ // Whether the app is an instant app.
+ optional bool is_instant_app = 6;
+
+ // Device uptime when activity started.
+ optional int64 activity_start_msec = 7;
+
+ // TODO: Update android/app/ActivityManagerInternal.java constants to depend on our proto enum.
+ enum TransitionReason {
+ APP_START_TRANSITION_REASON_UNKNOWN = 0;
+ SPLASH_SCREEN = 1;
+ WINDOWS_DRAWN = 2;
+ TIMEOUT = 3;
+ SNAPSHOT = 4;
+ }
+ optional TransitionReason reason = 8;
+
+ optional int32 transition_delay_msec = 9;
+ // -1 if not set.
+ optional int32 starting_window_delay_msec = 10;
+ // -1 if not set.
+ optional int32 bind_application_delay_msec = 11;
+ optional int32 windows_drawn_delay_msec = 12;
+
+ // Empty if not set.
+ optional string launch_token = 13;
+
+}
+
+message AppStartCancelChanged {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1;
+
+ // The app package name.
+ optional string pkg_name = 2;
+
+ enum TransitionType {
+ APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ WARM = 1;
+ HOT = 2;
+ COLD = 3;
+ }
+ // The transition type.
+ optional TransitionType type = 3;
+
+ // The activity name.
+ optional string activity_name = 4;
+}
+
+message AppStartFullyDrawnChanged {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1;
+
+ // The app package name.
+ optional string pkg_name = 2;
+
+ enum TransitionType {
+ APP_START_TRANSITION_TYPE_UNKNOWN = 0;
+ WITH_BUNDLE = 1;
+ WITHOUT_BUNDLE = 2;
+ }
+ // The transition type.
+ optional TransitionType type = 3;
+
+ // The activity name.
+ optional string activity_name = 4;
+
+ optional bool transition_process_running = 5;
+
+ // App startup time (until call to Activity#reportFullyDrawn()).
+ optional int64 app_startup_time_ms = 6;
+}
+
/**
* Pulls bytes transferred via wifi (Sum of foreground and background usage).
*
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 5842f3ccbaf9..36dd6167663b 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -85,6 +85,14 @@ StatsdStats& StatsdStats::getInstance() {
return statsInstance;
}
+void StatsdStats::addToIceBoxLocked(const StatsdStatsReport_ConfigStats& stats) {
+ // The size of mIceBox grows strictly by one at a time. It won't be > kMaxIceBoxSize.
+ if (mIceBox.size() == kMaxIceBoxSize) {
+ mIceBox.pop_front();
+ }
+ mIceBox.push_back(stats);
+}
+
void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
int matchersCount, int alertsCount, bool isValid) {
lock_guard<std::mutex> lock(mLock);
@@ -107,7 +115,7 @@ void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int
mConfigStats[key] = configStats;
} else {
configStats.set_deletion_time_sec(nowTimeSec);
- mIceBox.push_back(configStats);
+ addToIceBoxLocked(configStats);
}
}
@@ -123,7 +131,7 @@ void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
mMetricsStats.erase(key);
mAlertStats.erase(key);
mConditionStats.erase(key);
- mIceBox.push_back(it->second);
+ addToIceBoxLocked(it->second);
mConfigStats.erase(it);
}
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 2f108239737f..52ab253b6721 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -21,6 +21,7 @@
#include <gtest/gtest_prod.h>
#include <log/log_time.h>
+#include <list>
#include <mutex>
#include <string>
#include <vector>
@@ -45,6 +46,9 @@ public:
const static int kMaxMetricCountPerConfig = 300;
const static int kMaxMatcherCountPerConfig = 500;
+ // The max number of old config stats we keep.
+ const static int kMaxIceBoxSize = 20;
+
const static int kMaxTimestampCount = 20;
const static int kMaxLogSourceCount = 50;
@@ -202,19 +206,21 @@ private:
StatsdStatsReport_UidMapStats mUidMapStats;
// The stats about the configs that are still in use.
+ // The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats;
// Stores the stats for the configs that are no longer in use.
- std::vector<const StatsdStatsReport_ConfigStats> mIceBox;
+ // The size of the vector is capped by kMaxIceBoxSize.
+ std::list<const StatsdStatsReport_ConfigStats> mIceBox;
// Stores the number of output tuple of condition trackers when it's bigger than
// kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
- // it means some data has been dropped.
+ // it means some data has been dropped. The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, std::map<const int64_t, int>> mConditionStats;
// Stores the number of output tuple of metric producers when it's bigger than
// kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
- // it means some data has been dropped.
+ // it means some data has been dropped. The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, std::map<const int64_t, int>> mMetricsStats;
// Stores the number of times a pushed atom is logged.
@@ -223,6 +229,7 @@ private:
// This is a vector, not a map because it will be accessed A LOT -- for each stats log.
std::vector<int> mPushedAtomStats;
+ // Maps PullAtomId to its stats. The size is capped by the puller atom counts.
std::map<int, PulledAtomStats> mPulledAtomStats;
// Stores the number of times statsd modified the anomaly alarm registered with
@@ -230,10 +237,10 @@ private:
int mAnomalyAlarmRegisteredStats = 0;
// Stores the number of times an anomaly detection alert has been declared
- // (per config, per alert name).
+ // (per config, per alert name). The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, std::map<const int64_t, int>> mAlertStats;
- // Stores how many times a matcher have been matched.
+ // Stores how many times a matcher have been matched. The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, std::map<const int64_t, int>> mMatcherStats;
void noteConfigRemovedInternalLocked(const ConfigKey& key);
@@ -249,6 +256,8 @@ private:
void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
+ void addToIceBoxLocked(const StatsdStatsReport_ConfigStats& stats);
+
FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 6087ae502e7b..16fc7ee3c6e9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -84,7 +84,7 @@ private:
FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
- FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetection);
+ FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 023c25e20214..371460e804bd 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -169,7 +169,8 @@ protected:
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
- FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 293726c590e9..638b7ad7af26 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -67,7 +67,8 @@ private:
FRIEND_TEST(OringDurationTrackerTest, TestCrossBucketBoundary);
FRIEND_TEST(OringDurationTrackerTest, TestDurationConditionChange);
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
- FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetection);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
+ FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
};
} // namespace statsd
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 5842bc889f93..66bfa68ecc55 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -54,11 +54,73 @@ std::shared_ptr<DimToValMap> MockBucket(
return bucket;
}
+// Returns the value, for the given key, in that bucket, or 0 if not present.
+int64_t getBucketValue(const std::shared_ptr<DimToValMap>& bucket,
+ const HashableDimensionKey& key) {
+ const auto& itr = bucket->find(key);
+ if (itr != bucket->end()) {
+ return itr->second;
+ }
+ return 0;
+}
+
+// Returns true if keys in trueList are detected as anomalies and keys in falseList are not.
+bool detectAnomaliesPass(AnomalyTracker& tracker,
+ const int64_t& bucketNum,
+ const std::shared_ptr<DimToValMap>& currentBucket,
+ const std::set<const HashableDimensionKey>& trueList,
+ const std::set<const HashableDimensionKey>& falseList) {
+ for (HashableDimensionKey key : trueList) {
+ if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
+ return false;
+ }
+ }
+ for (HashableDimensionKey key : falseList) {
+ if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Calls tracker.detectAndDeclareAnomaly on each key in the bucket.
+void detectAndDeclareAnomalies(AnomalyTracker& tracker,
+ const int64_t& bucketNum,
+ const std::shared_ptr<DimToValMap>& bucket,
+ const int64_t& eventTimestamp) {
+ for (const auto& kv : *bucket) {
+ tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second);
+ }
+}
+
+// Asserts that the refractory time for each key in timestamps is the corresponding
+// timestamp (in ns) + refractoryPeriodSec.
+// If a timestamp value is negative, instead asserts that the refractory period is inapplicable
+// (either non-existant or already past).
+void checkRefractoryTimes(AnomalyTracker& tracker,
+ const int64_t& currTimestampNs,
+ const int32_t& refractoryPeriodSec,
+ const std::unordered_map<HashableDimensionKey, int64_t>& timestamps) {
+ for (const auto& kv : timestamps) {
+ if (kv.second < 0) {
+ // Make sure that, if there is a refractory period, it is already past.
+ EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first),
+ currTimestampNs / NS_PER_SEC + 1)
+ << "Failure was at currTimestampNs " << currTimestampNs;
+ } else {
+ EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
+ kv.second / NS_PER_SEC + refractoryPeriodSec)
+ << "Failure was at currTimestampNs " << currTimestampNs;
+ }
+ }
+}
+
TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
+ const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
Alert alert;
alert.set_num_buckets(3);
- alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
+ alert.set_refractory_period_secs(refractoryPeriodSec);
alert.set_trigger_if_sum_gt(2);
AnomalyTracker anomalyTracker(alert, kConfigKey);
@@ -66,26 +128,31 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
HashableDimensionKey keyB = getMockDimensionKey(1, "b");
HashableDimensionKey keyC = getMockDimensionKey(1, "c");
+ int64_t eventTimestamp0 = 10 * NS_PER_SEC;
+ int64_t eventTimestamp1 = bucketSizeNs + 11 * NS_PER_SEC;
+ int64_t eventTimestamp2 = 2 * bucketSizeNs + 12 * NS_PER_SEC;
+ int64_t eventTimestamp3 = 3 * bucketSizeNs + 13 * NS_PER_SEC;
+ int64_t eventTimestamp4 = 4 * bucketSizeNs + 14 * NS_PER_SEC;
+ int64_t eventTimestamp5 = 5 * bucketSizeNs + 5 * NS_PER_SEC;
+ int64_t eventTimestamp6 = 6 * bucketSizeNs + 16 * NS_PER_SEC;
+
std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
- int64_t eventTimestamp0 = 10;
std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}});
- int64_t eventTimestamp1 = bucketSizeNs + 11;
std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}});
- int64_t eventTimestamp2 = 2 * bucketSizeNs + 12;
std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}});
- int64_t eventTimestamp3 = 3 * bucketSizeNs + 13;
- std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 1}});
- int64_t eventTimestamp4 = 4 * bucketSizeNs + 14;
+ std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 5}});
std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}});
- int64_t eventTimestamp5 = 5 * bucketSizeNs + 15;
std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
- int64_t eventTimestamp6 = 6 * bucketSizeNs + 16;
+ // Start time with no events.
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(0, *bucket0));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp0, 0, *bucket0);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
+
+ // Event from bucket #0 occurs.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 0, bucket0, {}, {keyA, keyB, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 0, bucket0, eventTimestamp1);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp0, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}});
// Adds past bucket #0
anomalyTracker.addPastBucket(bucket0, 0);
@@ -94,9 +161,12 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 1, *bucket1);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
+
+ // Event from bucket #1 occurs.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}});
// Adds past bucket #0 again. The sum does not change.
anomalyTracker.addPastBucket(bucket0, 0);
@@ -105,9 +175,10 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1 + 1, 1, *bucket1);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1L);
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1 + 1);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}});
// Adds past bucket #1.
anomalyTracker.addPastBucket(bucket1, 1);
@@ -116,9 +187,12 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 2, *bucket2);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+
+ // Event from bucket #2 occurs. New anomaly on keyB.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
// Adds past bucket #1 again. Nothing changes.
anomalyTracker.addPastBucket(bucket1, 1);
@@ -127,9 +201,11 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2 + 1, 2, *bucket2);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+ // Event from bucket #2 occurs (again).
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2 + 1);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
// Adds past bucket #2.
anomalyTracker.addPastBucket(bucket2, 2);
@@ -137,10 +213,12 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(3, *bucket3));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 3, *bucket3);
- // Within refractory period.
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+
+ // Event from bucket #3 occurs. New anomaly on keyA.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 3, bucket3, {keyA}, {keyB, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 3, bucket3, eventTimestamp3);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
+ {{keyA, eventTimestamp3}, {keyB, eventTimestamp2}, {keyC, -1}});
// Adds bucket #3.
anomalyTracker.addPastBucket(bucket3, 3L);
@@ -148,37 +226,46 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(4, *bucket4));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 4, *bucket4);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+
+ // Event from bucket #4 occurs. New anomaly on keyB.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 4, bucket4, {keyB}, {keyA, keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 4, bucket4, eventTimestamp4);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
+ {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
// Adds bucket #4.
anomalyTracker.addPastBucket(bucket4, 4);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(5, *bucket5));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 5, *bucket5);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp5);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
+
+ // Event from bucket #5 occurs. New anomaly on keyA, which is still in refractory.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 5, bucket5, {keyA, keyB}, {keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 5, bucket5, eventTimestamp5);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
+ {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
// Adds bucket #5.
anomalyTracker.addPastBucket(bucket5, 5);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(6, *bucket6));
- // Within refractory period.
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 6, *bucket6);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp5);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
+
+ // Event from bucket #6 occurs. New anomaly on keyA, which is now out of refractory.
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 6, bucket6, {keyA, keyB}, {keyC}));
+ detectAndDeclareAnomalies(anomalyTracker, 6, bucket6, eventTimestamp6);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
+ {{keyA, eventTimestamp6}, {keyB, eventTimestamp4}, {keyC, -1}});
}
TEST(AnomalyTrackerTest, TestSparseBuckets) {
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
+ const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
Alert alert;
alert.set_num_buckets(3);
- alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
+ alert.set_refractory_period_secs(refractoryPeriodSec);
alert.set_trigger_if_sum_gt(2);
AnomalyTracker anomalyTracker(alert, kConfigKey);
@@ -204,9 +291,10 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(9, *bucket9));
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 9, *bucket9);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, -1);
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD}));
+ detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Add past bucket #9
anomalyTracker.addPastBucket(bucket9, 9);
@@ -215,25 +303,27 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(16, *bucket16));
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 16, *bucket16);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+ detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Add past bucket #16
anomalyTracker.addPastBucket(bucket16, 16);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(18, *bucket18));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
// Within refractory period.
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 18, *bucket18);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp2);
+ detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
@@ -243,13 +333,14 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 20, *bucket20);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
+ detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Add bucket #18 again. Nothing changes.
anomalyTracker.addPastBucket(bucket18, 18);
@@ -257,13 +348,14 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4 + 1, 20, *bucket20);
+ detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1);
// Within refractory period.
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp4 + 1, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Add past bucket #20
anomalyTracker.addPastBucket(bucket20, 20);
@@ -271,32 +363,37 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(25, *bucket25));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 25, *bucket25);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Add past bucket #25
anomalyTracker.addPastBucket(bucket25, 25);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
- EXPECT_FALSE(anomalyTracker.detectAnomaly(28, *bucket28));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
+ {keyA, keyB, keyC, keyD, keyE}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 28, *bucket28);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp4);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
// Updates current bucket #28.
(*bucket28)[keyE] = 5;
- EXPECT_TRUE(anomalyTracker.detectAnomaly(28, *bucket28));
+ EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
+ {keyA, keyB, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6 + 7, 28, *bucket28);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
- EXPECT_EQ(anomalyTracker.mLastAnomalyTimestampNs, eventTimestamp6 + 7);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
+ // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
+ {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 768336b08416..c39151313c55 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -191,13 +191,14 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
EXPECT_EQ(1LL, bucketInfo.mCount);
}
-TEST(CountMetricProducerTest, TestAnomalyDetection) {
+TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
Alert alert;
alert.set_id(11);
alert.set_metric_id(1);
alert.set_trigger_if_sum_gt(2);
alert.set_num_buckets(2);
- alert.set_refractory_period_secs(1);
+ const int32_t refPeriodSec = 1;
+ alert.set_refractory_period_secs(refPeriodSec);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
@@ -220,7 +221,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
- LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3 + NS_PER_SEC);
+ LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
// Two events in bucket #0.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -228,13 +229,13 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
// One event in bucket #2. No alarm as bucket #0 is trashed out.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
// Two events in bucket #3.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
@@ -243,12 +244,14 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
// Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event5.GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event5.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event7.GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event7.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index ad9c5a391743..82772d854db2 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -201,6 +201,8 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(25);
alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 60;
+ alert.set_refractory_period_secs(refPeriodSec);
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
int tagId = 1;
@@ -213,10 +215,10 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(13L,
gaugeProducer.mCurrentSlicedBucket->begin()->second->begin()->second.value_int());
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
std::shared_ptr<LogEvent> event2 =
- std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 10);
+ std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
event2->write("some value");
event2->write(15);
event2->init();
@@ -225,19 +227,21 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(15L,
gaugeProducer.mCurrentSlicedBucket->begin()->second->begin()->second.value_int());
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event2->GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
std::shared_ptr<LogEvent> event3 =
std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
event3->write("some value");
- event3->write(24);
+ event3->write(26);
event3->init();
gaugeProducer.onDataPulled({event3});
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(24L,
+ EXPECT_EQ(26L,
gaugeProducer.mCurrentSlicedBucket->begin()->second->begin()->second.value_int());
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
// The event4 does not have the gauge field. Thus the current bucket value is 0.
std::shared_ptr<LogEvent> event4 =
@@ -247,7 +251,6 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
gaugeProducer.onDataPulled({event4});
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second->empty());
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs());
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index f98be1b24f4e..0772b0d4001d 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -210,7 +210,8 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
alert.set_num_buckets(2);
- alert.set_refractory_period_secs(1);
+ const int32_t refPeriodSec = 1;
+ alert.set_refractory_period_secs(refPeriodSec);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -225,15 +226,16 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
tracker.noteStart(key1, true, eventStartTimeNs, ConditionKey());
tracker.noteStop(key1, eventStartTimeNs + 10, false);
- EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
EXPECT_EQ(10LL, tracker.mDuration);
tracker.noteStart(key2, true, eventStartTimeNs + 20, ConditionKey());
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
tracker.noteStop(key2, eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
- EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs,
- (long long)(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC));
+
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
+ (eventStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 89c6abe7cefd..6b8893e5973f 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -309,13 +309,14 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
}
-TEST(OringDurationTrackerTest, TestAnomalyDetection) {
+TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
alert.set_num_buckets(2);
- alert.set_refractory_period_secs(1);
+ const int32_t refPeriodSec = 45;
+ alert.set_refractory_period_secs(refPeriodSec);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -328,23 +329,86 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) {
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker});
- tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
- tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
- EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
EXPECT_TRUE(tracker.mStarted.empty());
EXPECT_EQ(10LL, tracker.mDuration);
EXPECT_EQ(0u, tracker.mStarted.size());
- tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs + 20, ConditionKey());
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs + 20, ConditionKey());
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
+ // The alarm is set to fire at 51s, and when it does, an anomaly would be declared. However,
+ // because this is a unit test, the alarm won't actually fire at all. Since the alarm fails
+ // to fire in time, the anomaly is instead caught when noteStop is called, at around 71s.
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
- tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
- EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
- anomalyTracker->mLastAnomalyTimestampNs);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
+ (eventStartTimeNs + 2 * bucketSizeNs + 25) / NS_PER_SEC + refPeriodSec);
+}
+
+TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
+ Alert alert;
+ alert.set_id(101);
+ alert.set_metric_id(1);
+ alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
+ alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 45;
+ alert.set_refractory_period_secs(refPeriodSec);
+
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ConditionKey conkey;
+ conkey[StringToId("APP_BACKGROUND")] = kConditionKey1;
+ uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
+ uint64_t bucketSizeNs = 30 * NS_PER_SEC;
+
+ sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
+ bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker});
+
+ tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
+ EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ sp<const AnomalyAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
+ EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
+
+ tracker.noteStop(kEventKey1, 17 * NS_PER_SEC, false); // stop key1 (2 seconds later)
+ EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
+
+ tracker.noteStart(kEventKey1, true, 22 * NS_PER_SEC, conkey); // start key1 again
+ EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ alarm = anomalyTracker->mAlarms.begin()->second;
+ EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
+
+ tracker.noteStart(kEventKey2, true, 32 * NS_PER_SEC, conkey); // start key2
+ EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ alarm = anomalyTracker->mAlarms.begin()->second;
+ EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
+
+ tracker.noteStop(kEventKey1, 47 * NS_PER_SEC, false); // stop key1
+ EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ alarm = anomalyTracker->mAlarms.begin()->second;
+ EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
+
+ // Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time.
+ std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> firedAlarms({alarm});
+ anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms);
+ EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
+
+ tracker.noteStop(kEventKey2, 69 * NS_PER_SEC, false); // stop key2
+ EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 459da0170fc1..fff3dbf5428d 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -249,7 +249,8 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(130);
alert.set_num_buckets(2);
- alert.set_refractory_period_secs(3);
+ const int32_t refPeriodSec = 3;
+ alert.set_refractory_period_secs(refPeriodSec);
ValueMetric metric;
metric.set_id(metricId);
@@ -297,23 +298,28 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
// Two events in bucket #0.
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL); // Value sum == 30 <= 130.
+ // Value sum == 30 <= 130.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
// One event in bucket #2. No alarm as bucket #0 is trashed out.
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL); // Value sum == 130 <= 130.
+ // Value sum == 130 <= 130.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
// Three events in bucket #3.
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
// Anomaly at event 4 since Value sum == 131 > 130!
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event4->GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
// Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event4->GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
// Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
- EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event6->GetTimestampNs());
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
+ event6->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 85c3be826c0d..046a128cc81e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5994,8 +5994,15 @@ public class Notification implements Parcelable
/**
* Sets the title to be displayed on this conversation. May be set to {@code null}.
*
- * @param conversationTitle A name for the conversation, or {@code null}
- * @return this object for method chaining.
+ * <p>This API's behavior was changed in SDK version {@link Build.VERSION_CODES#P}. If your
+ * application's target version is less than {@link Build.VERSION_CODES#P}, setting a
+ * conversation title to a non-null value will make {@link #isGroupConversation()} return
+ * {@code true} and passing {@code null} will make it return {@code false}. In
+ * {@link Build.VERSION_CODES#P} and beyond, use {@link #setGroupConversation(boolean)}
+ * to set group conversation status.
+ *
+ * @param conversationTitle Title displayed for this conversation
+ * @return this object for method chaining
*/
public MessagingStyle setConversationTitle(@Nullable CharSequence conversationTitle) {
mConversationTitle = conversationTitle;
@@ -6083,6 +6090,7 @@ public class Notification implements Parcelable
/**
* Sets whether this conversation notification represents a group.
+ *
* @param isGroupConversation {@code true} if the conversation represents a group,
* {@code false} otherwise.
* @return this object for method chaining
@@ -6093,9 +6101,27 @@ public class Notification implements Parcelable
}
/**
- * Returns {@code true} if this notification represents a group conversation.
+ * Returns {@code true} if this notification represents a group conversation, otherwise
+ * {@code false}.
+ *
+ * <p> If the application that generated this {@link MessagingStyle} targets an SDK version
+ * less than {@link Build.VERSION_CODES#P}, this method becomes dependent on whether or
+ * not the conversation title is set; returning {@code true} if the conversation title is
+ * a non-null value, or {@code false} otherwise. From {@link Build.VERSION_CODES#P} forward,
+ * this method returns what's set by {@link #setGroupConversation(boolean)} allowing for
+ * named, non-group conversations.
+ *
+ * @see #setConversationTitle(CharSequence)
*/
public boolean isGroupConversation() {
+ // When target SDK version is < P, a non-null conversation title dictates if this is
+ // as group conversation.
+ if (mBuilder != null
+ && mBuilder.mContext.getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.P) {
+ return mConversationTitle != null;
+ }
+
return mIsGroupConversation;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0b747416bbbf..76c078ec9c05 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -7518,7 +7518,8 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to disable the keyguard altogether.
+ * Called by a device owner or profile owner of secondary users that is affiliated with the
+ * device to disable the keyguard altogether.
* <p>
* Setting the keyguard to disabled has the same effect as choosing "None" as the screen lock
* type. However, this call has no effect if a password, pin or pattern is currently set. If a
@@ -7533,7 +7534,10 @@ public class DevicePolicyManager {
* @param disabled {@code true} disables the keyguard, {@code false} reenables it.
* @return {@code false} if attempting to disable the keyguard while a lock password was in
* place. {@code true} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not the device owner, or a profile owner of
+ * secondary user that is affiliated with the device.
+ * @see #isAffiliatedUser
+ * @see #getSecondaryUsers
*/
public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) {
throwIfParentInstance("setKeyguardDisabled");
@@ -7545,9 +7549,9 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to disable the status bar. Disabling the status bar blocks
- * notifications, quick settings and other screen overlays that allow escaping from a single use
- * device.
+ * Called by device owner or profile owner of secondary users that is affiliated with the
+ * device to disable the status bar. Disabling the status bar blocks notifications, quick
+ * settings and other screen overlays that allow escaping from a single use device.
* <p>
* <strong>Note:</strong> This method has no effect for LockTask mode. The behavior of the
* status bar in LockTask mode can be configured with
@@ -7558,7 +7562,10 @@ public class DevicePolicyManager {
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param disabled {@code true} disables the status bar, {@code false} reenables it.
* @return {@code false} if attempting to disable the status bar failed. {@code true} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not the device owner, or a profile owner of
+ * secondary user that is affiliated with the device.
+ * @see #isAffiliatedUser
+ * @see #getSecondaryUsers
*/
public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) {
throwIfParentInstance("setStatusBarDisabled");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c5c6aa2ecf53..ee8bfd169b5e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3530,7 +3530,6 @@ public abstract class Context {
*
* @see #getSystemService
* @see android.net.wifi.rtt.WifiRttManager
- * @hide
*/
public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5f82c2a76a18..6cd4285f51e3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2327,8 +2327,6 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports Wi-Fi RTT (IEEE 802.11mc).
- *
- * @hide RTT_API
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 367c39dfd8ff..77eb57f25613 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -85,6 +85,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
import android.util.apk.ApkSignatureVerifier;
import android.view.Gravity;
@@ -111,7 +112,8 @@ import java.lang.reflect.Constructor;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
-import java.security.cert.CertificateException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
@@ -156,6 +158,10 @@ public class PackageParser {
private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
+ public static final int APK_SIGNING_UNKNOWN = 0;
+ public static final int APK_SIGNING_V1 = 1;
+ public static final int APK_SIGNING_V2 = 2;
+
private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
// TODO: switch outError users to PackageParserException
@@ -471,7 +477,8 @@ public class PackageParser {
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
- public final SigningDetails signingDetails;
+ public final Signature[] signatures;
+ public final Certificate[][] certificates;
public final boolean coreApp;
public final boolean debuggable;
public final boolean multiArch;
@@ -479,11 +486,10 @@ public class PackageParser {
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
- public ApkLite(String codePath, String packageName, String splitName,
- boolean isFeatureSplit,
+ public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
- SigningDetails signingDetails, boolean coreApp,
+ Signature[] signatures, Certificate[][] certificates, boolean coreApp,
boolean debuggable, boolean multiArch, boolean use32bitAbi,
boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
@@ -496,8 +502,9 @@ public class PackageParser {
this.versionCodeMajor = versionCodeMajor;
this.revisionCode = revisionCode;
this.installLocation = installLocation;
- this.signingDetails = signingDetails;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
+ this.signatures = signatures;
+ this.certificates = certificates;
this.coreApp = coreApp;
this.debuggable = debuggable;
this.multiArch = multiArch;
@@ -800,10 +807,10 @@ public class PackageParser {
}
}
if ((flags&PackageManager.GET_SIGNATURES) != 0) {
- if (p.mSigningDetails.hasSignatures()) {
- int numberOfSigs = p.mSigningDetails.signatures.length;
- pi.signatures = new Signature[numberOfSigs];
- System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
+ int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
+ if (N > 0) {
+ pi.signatures = new Signature[N];
+ System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
}
}
return pi;
@@ -1342,7 +1349,7 @@ public class PackageParser {
pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
pkg.setBaseCodePath(apkPath);
- pkg.setSigningDetails(SigningDetails.UNKNOWN);
+ pkg.setSignatures(null);
return pkg;
@@ -1462,19 +1469,57 @@ public class PackageParser {
return pkg;
}
- /** Parses the public keys from the set of signatures. */
- public static ArraySet<PublicKey> toSigningKeys(Signature[] signatures)
- throws CertificateException {
- ArraySet<PublicKey> keys = new ArraySet<>(signatures.length);
- for (int i = 0; i < signatures.length; i++) {
- keys.add(signatures[i].getPublicKey());
+ public static int getApkSigningVersion(Package pkg) {
+ try {
+ if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
+ return APK_SIGNING_V2;
+ }
+ return APK_SIGNING_V1;
+ } catch (IOException e) {
+ }
+ return APK_SIGNING_UNKNOWN;
+ }
+
+ /**
+ * Populates the correct packages fields with the given certificates.
+ * <p>
+ * This is useful when we've already processed the certificates [such as during package
+ * installation through an installer session]. We don't re-process the archive and
+ * simply populate the correct fields.
+ */
+ public static void populateCertificates(Package pkg, Certificate[][] certificates)
+ throws PackageParserException {
+ pkg.mCertificates = null;
+ pkg.mSignatures = null;
+ pkg.mSigningKeys = null;
+
+ pkg.mCertificates = certificates;
+ try {
+ pkg.mSignatures = ApkSignatureVerifier.convertToSignatures(certificates);
+ } catch (CertificateEncodingException e) {
+ // certificates weren't encoded properly; something went wrong
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + pkg.baseCodePath, e);
+ }
+ pkg.mSigningKeys = new ArraySet<>(certificates.length);
+ for (int i = 0; i < certificates.length; i++) {
+ Certificate[] signerCerts = certificates[i];
+ Certificate signerCert = signerCerts[0];
+ pkg.mSigningKeys.add(signerCert.getPublicKey());
+ }
+ // add signatures to child packages
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ Package childPkg = pkg.childPackages.get(i);
+ childPkg.mCertificates = pkg.mCertificates;
+ childPkg.mSignatures = pkg.mSignatures;
+ childPkg.mSigningKeys = pkg.mSigningKeys;
}
- return keys;
}
/**
* Collect certificates from all the APKs described in the given package,
- * populating {@link Package#mSigningDetails}. Also asserts that all APK
+ * populating {@link Package#mSignatures}. Also asserts that all APK
* contents are signed correctly and consistently.
*/
public static void collectCertificates(Package pkg, @ParseFlags int parseFlags)
@@ -1483,13 +1528,17 @@ public class PackageParser {
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
Package childPkg = pkg.childPackages.get(i);
- childPkg.mSigningDetails = pkg.mSigningDetails;
+ childPkg.mCertificates = pkg.mCertificates;
+ childPkg.mSignatures = pkg.mSignatures;
+ childPkg.mSigningKeys = pkg.mSigningKeys;
}
}
private static void collectCertificatesInternal(Package pkg, @ParseFlags int parseFlags)
throws PackageParserException {
- pkg.mSigningDetails = SigningDetails.UNKNOWN;
+ pkg.mCertificates = null;
+ pkg.mSignatures = null;
+ pkg.mSigningKeys = null;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
@@ -1509,12 +1558,12 @@ public class PackageParser {
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
- int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
+ int minSignatureScheme = ApkSignatureVerifier.VERSION_JAR_SIGNATURE_SCHEME;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// must use v2 signing scheme
- minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+ minSignatureScheme = ApkSignatureVerifier.VERSION_APK_SIGNATURE_SCHEME_V2;
}
- SigningDetails verified;
+ ApkSignatureVerifier.Result verified;
if ((parseFlags & PARSE_IS_SYSTEM_DIR) != 0) {
// systemDir APKs are already trusted, save time by not verifying
verified = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
@@ -1523,7 +1572,7 @@ public class PackageParser {
verified = ApkSignatureVerifier.verify(apkPath, minSignatureScheme);
}
if (verified.signatureSchemeVersion
- < SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ < ApkSignatureVerifier.VERSION_APK_SIGNATURE_SCHEME_V2) {
// TODO (b/68860689): move this logic to packagemanagerserivce
if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
@@ -1534,10 +1583,17 @@ public class PackageParser {
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
- if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
- pkg.mSigningDetails = verified;
+ if (pkg.mCertificates == null) {
+ pkg.mCertificates = verified.certs;
+ pkg.mSignatures = verified.sigs;
+ pkg.mSigningKeys = new ArraySet<>(verified.certs.length);
+ for (int i = 0; i < verified.certs.length; i++) {
+ Certificate[] signerCerts = verified.certs[i];
+ Certificate signerCert = signerCerts[0];
+ pkg.mSigningKeys.add(signerCert.getPublicKey());
+ }
} else {
- if (!Signature.areExactMatch(pkg.mSigningDetails.signatures, verified.signatures)) {
+ if (!Signature.areExactMatch(pkg.mSignatures, verified.sigs)) {
throw new PackageParserException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
apkPath + " has mismatched certificates");
@@ -1599,7 +1655,8 @@ public class PackageParser {
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
- final SigningDetails signingDetails;
+ final Signature[] signatures;
+ final Certificate[][] certificates;
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package((String) null);
@@ -1609,13 +1666,15 @@ public class PackageParser {
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- signingDetails = tempPkg.mSigningDetails;
+ signatures = tempPkg.mSignatures;
+ certificates = tempPkg.mCertificates;
} else {
- signingDetails = SigningDetails.UNKNOWN;
+ signatures = null;
+ certificates = null;
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, parser, attrs, signingDetails);
+ return parseApkLite(apkPath, parser, attrs, signatures, certificates);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1702,7 +1761,7 @@ public class PackageParser {
}
private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
- SigningDetails signingDetails)
+ Signature[] signatures, Certificate[][] certificates)
throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
@@ -1795,7 +1854,7 @@ public class PackageParser {
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, versionCode, versionCodeMajor, revisionCode,
- installLocation, verifiers, signingDetails, coreApp, debuggable,
+ installLocation, verifiers, signatures, certificates, coreApp, debuggable,
multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
}
@@ -5675,117 +5734,6 @@ public class PackageParser {
return true;
}
- /** A container for signing-related data of an application package. */
- public static final class SigningDetails implements Parcelable {
-
- @IntDef({SigningDetails.SignatureSchemeVersion.UNKNOWN,
- SigningDetails.SignatureSchemeVersion.JAR,
- SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
- SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3})
- public @interface SignatureSchemeVersion {
- int UNKNOWN = 0;
- int JAR = 1;
- int SIGNING_BLOCK_V2 = 2;
- int SIGNING_BLOCK_V3 = 3;
- }
-
- @Nullable
- public final Signature[] signatures;
- @SignatureSchemeVersion
- public final int signatureSchemeVersion;
- @Nullable
- public final ArraySet<PublicKey> publicKeys;
-
- /** A representation of unknown signing details. Use instead of null. */
- public static final SigningDetails UNKNOWN =
- new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null);
-
- @VisibleForTesting
- public SigningDetails(Signature[] signatures,
- @SignatureSchemeVersion int signatureSchemeVersion,
- ArraySet<PublicKey> keys) {
- this.signatures = signatures;
- this.signatureSchemeVersion = signatureSchemeVersion;
- this.publicKeys = keys;
- }
-
- public SigningDetails(Signature[] signatures,
- @SignatureSchemeVersion int signatureSchemeVersion)
- throws CertificateException {
- this(signatures, signatureSchemeVersion, toSigningKeys(signatures));
- }
-
- /** Returns true if the signing details have one or more signatures. */
- public boolean hasSignatures() {
- return signatures != null && signatures.length > 0;
- }
-
- /** Returns true if the signatures in this and other match exactly. */
- public boolean signaturesMatchExactly(SigningDetails other) {
- return Signature.areExactMatch(this.signatures, other.signatures);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- boolean isUnknown = UNKNOWN == this;
- dest.writeBoolean(isUnknown);
- if (isUnknown) {
- return;
- }
- dest.writeTypedArray(this.signatures, flags);
- dest.writeInt(this.signatureSchemeVersion);
- dest.writeArraySet(this.publicKeys);
- }
-
- protected SigningDetails(Parcel in) {
- final ClassLoader boot = Object.class.getClassLoader();
- this.signatures = in.createTypedArray(Signature.CREATOR);
- this.signatureSchemeVersion = in.readInt();
- this.publicKeys = (ArraySet<PublicKey>) in.readArraySet(boot);
- }
-
- public static final Creator<SigningDetails> CREATOR = new Creator<SigningDetails>() {
- @Override
- public SigningDetails createFromParcel(Parcel source) {
- if (source.readBoolean()) {
- return UNKNOWN;
- }
- return new SigningDetails(source);
- }
-
- @Override
- public SigningDetails[] newArray(int size) {
- return new SigningDetails[size];
- }
- };
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SigningDetails)) return false;
-
- SigningDetails that = (SigningDetails) o;
-
- if (signatureSchemeVersion != that.signatureSchemeVersion) return false;
- if (!Signature.areExactMatch(signatures, that.signatures)) return false;
- return publicKeys != null ? publicKeys.equals(that.publicKeys)
- : that.publicKeys == null;
- }
-
- @Override
- public int hashCode() {
- int result = +Arrays.hashCode(signatures);
- result = 31 * result + signatureSchemeVersion;
- result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0);
- return result;
- }
- }
-
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
@@ -5892,7 +5840,8 @@ public class PackageParser {
public int mSharedUserLabel;
// Signatures that were read from the package.
- @NonNull public SigningDetails mSigningDetails = SigningDetails.UNKNOWN;
+ public Signature[] mSignatures;
+ public Certificate[][] mCertificates;
// For use by package manager service for quick lookup of
// preferred up order.
@@ -5944,6 +5893,7 @@ public class PackageParser {
/**
* Data used to feed the KeySetManagerService
*/
+ public ArraySet<PublicKey> mSigningKeys;
public ArraySet<String> mUpgradeKeySets;
public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
@@ -6087,13 +6037,12 @@ public class PackageParser {
}
}
- /** Sets signing details on the package and any of its children. */
- public void setSigningDetails(@NonNull SigningDetails signingDetails) {
- mSigningDetails = signingDetails;
+ public void setSignatures(Signature[] signatures) {
+ this.mSignatures = signatures;
if (childPackages != null) {
final int packageCount = childPackages.size();
for (int i = 0; i < packageCount; i++) {
- childPackages.get(i).mSigningDetails = signingDetails;
+ childPackages.get(i).mSignatures = signatures;
}
}
}
@@ -6399,7 +6348,8 @@ public class PackageParser {
}
mSharedUserLabel = dest.readInt();
- mSigningDetails = dest.readParcelable(boot);
+ mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
+ mCertificates = (Certificate[][]) dest.readSerializable();
mPreferredOrder = dest.readInt();
@@ -6439,6 +6389,7 @@ public class PackageParser {
mTrustedOverlay = (dest.readInt() == 1);
mCompileSdkVersion = dest.readInt();
mCompileSdkVersionCodename = dest.readString();
+ mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
mKeySetMapping = readKeySetMapping(dest);
@@ -6538,7 +6489,8 @@ public class PackageParser {
dest.writeString(mSharedUserId);
dest.writeInt(mSharedUserLabel);
- dest.writeParcelable(mSigningDetails, flags);
+ dest.writeParcelableArray(mSignatures, flags);
+ dest.writeSerializable(mCertificates);
dest.writeInt(mPreferredOrder);
@@ -6563,6 +6515,7 @@ public class PackageParser {
dest.writeInt(mTrustedOverlay ? 1 : 0);
dest.writeInt(mCompileSdkVersion);
dest.writeString(mCompileSdkVersionCodename);
+ dest.writeArraySet(mSigningKeys);
dest.writeArraySet(mUpgradeKeySets);
writeKeySetMapping(dest, mKeySetMapping);
dest.writeString(cpuAbiOverride);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 5a638967f01b..1201ef48220a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1149,36 +1149,33 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
/**
* <p>Position of the camera optical center.</p>
* <p>The position of the camera device's lens optical center,
- * as a three-dimensional vector <code>(x,y,z)</code>, relative to the
- * optical center of the largest camera device facing in the
- * same direction as this camera, in the {@link android.hardware.SensorEvent Android sensor coordinate
- * axes}. Note that only the axis definitions are shared with
- * the sensor coordinate system, but not the origin.</p>
- * <p>If this device is the largest or only camera device with a
- * given facing, then this position will be <code>(0, 0, 0)</code>; a
- * camera device with a lens optical center located 3 cm from
- * the main sensor along the +X axis (to the right from the
- * user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
- * <p>To transform a pixel coordinates between two cameras
- * facing the same direction, first the source camera
- * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then
- * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
- * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
- * of the source camera, the translation of the source camera
- * relative to the destination camera, the
- * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
- * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
- * of the destination camera. This obtains a
- * radial-distortion-free coordinate in the destination
- * camera pixel coordinates.</p>
- * <p>To compare this against a real image from the destination
- * camera, the destination camera image then needs to be
- * corrected for radial distortion before comparison or
- * sampling.</p>
+ * as a three-dimensional vector <code>(x,y,z)</code>.</p>
+ * <p>Prior to Android P, or when {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is PRIMARY_CAMERA, this position
+ * is relative to the optical center of the largest camera device facing in the same
+ * direction as this camera, in the {@link android.hardware.SensorEvent Android sensor
+ * coordinate axes}. Note that only the axis definitions are shared with the sensor
+ * coordinate system, but not the origin.</p>
+ * <p>If this device is the largest or only camera device with a given facing, then this
+ * position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
+ * from the main sensor along the +X axis (to the right from the user's perspective) will
+ * report <code>(0.03, 0, 0)</code>.</p>
+ * <p>To transform a pixel coordinates between two cameras facing the same direction, first
+ * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source
+ * camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
+ * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera
+ * relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination
+ * camera, and finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} of the destination
+ * camera. This obtains a radial-distortion-free coordinate in the destination camera pixel
+ * coordinates.</p>
+ * <p>To compare this against a real image from the destination camera, the destination camera
+ * image then needs to be corrected for radial distortion before comparison or sampling.</p>
+ * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
+ * the center of the primary gyroscope on the device.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
@@ -1289,6 +1286,28 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<float[]>("android.lens.radialDistortion", float[].class);
/**
+ * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+ * <p>Different calibration methods and use cases can produce better or worse results
+ * depending on the selected coordinate origin.</p>
+ * <p>For devices designed to support the MOTION_TRACKING capability, the GYROSCOPE origin
+ * makes device calibration and later usage by applications combining camera and gyroscope
+ * information together simpler.</p>
+ * <p><b>Possible values:</b>
+ * <ul>
+ * <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
+ * <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
+ * </ul></p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
+ * @see #LENS_POSE_REFERENCE_GYROSCOPE
+ */
+ @PublicKey
+ public static final Key<Integer> LENS_POSE_REFERENCE =
+ new Key<Integer>("android.lens.poseReference", int.class);
+
+ /**
* <p>List of noise reduction modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} that are supported
* by this camera device.</p>
* <p>Full-capability camera devices will always support OFF and FAST.</p>
@@ -1559,6 +1578,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO CONSTRAINED_HIGH_SPEED_VIDEO}</li>
+ * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1573,6 +1593,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING
* @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT
* @see #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING
*/
@PublicKey
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -1643,7 +1664,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* time-consuming hardware re-configuration or internal camera pipeline
* change. For performance reasons we advise clients to pass their initial
* values as part of
- * {@link SessionConfiguration#setSessionParameters }.i
+ * {@link SessionConfiguration#setSessionParameters }.
* Once the camera capture session is enabled it is also recommended to avoid
* changing them from their initial values set in
* {@link SessionConfiguration#setSessionParameters }.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 87e503def4e3..ce1fba798c0e 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -144,6 +144,37 @@ public abstract class CameraDevice implements AutoCloseable {
*/
public static final int TEMPLATE_MANUAL = 6;
+ /**
+ * A template for selecting camera parameters that match TEMPLATE_PREVIEW as closely as
+ * possible while improving the camera output for motion tracking use cases.
+ *
+ * <p>This template is best used by applications that are frequently switching between motion
+ * tracking use cases and regular still capture use cases, to minimize the IQ changes
+ * when swapping use cases.</p>
+ *
+ * <p>This template is guaranteed to be supported on camera devices that support the
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}
+ * capability.</p>
+ *
+ * @see #createCaptureRequest
+ */
+ public static final int TEMPLATE_MOTION_TRACKING_PREVIEW = 7;
+
+ /**
+ * A template for selecting camera parameters that maximize the quality of camera output for
+ * motion tracking use cases.
+ *
+ * <p>This template is best used by applications dedicated to motion tracking applications,
+ * which aren't concerned about fast switches between motion tracking and other use cases.</p>
+ *
+ * <p>This template is guaranteed to be supported on camera devices that support the
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}
+ * capability.</p>
+ *
+ * @see #createCaptureRequest
+ */
+ public static final int TEMPLATE_MOTION_TRACKING_BEST = 8;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"TEMPLATE_"}, value =
@@ -386,6 +417,24 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <p>MOTION_TRACKING-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
+ * includes
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING})
+ * devices support at least the below stream combinations in addition to those for
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices. The
+ * {@code FULL FOV 640} entry means that the device will support a resolution that's 640 pixels
+ * wide, with the height set so that the resolution aspect ratio matches the MAXIMUM output
+ * aspect ratio. So for a device with a 4:3 image sensor, this will be 640x480, and for a
+ * device with a 16:9 sensor, this will be 640x360, and so on.
+ *
+ * <table>
+ * <tr><th colspan="7">MOTION_TRACKING-capability additional guaranteed configurations</th></tr>
+ * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code FULL FOV 640}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Live preview with a tracking YUV output and a maximum-resolution YUV for still captures.</td> </tr>
+ * </table><br>
+ * </p>
+ *
* <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
* support at least the below stream combinations in addition to those for
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index cb11d0f54a7b..1c7f2896b167 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -336,6 +336,30 @@ public abstract class CameraMetadata<TKey> {
public static final int LENS_FACING_EXTERNAL = 2;
//
+ // Enumeration values for CameraCharacteristics#LENS_POSE_REFERENCE
+ //
+
+ /**
+ * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} is relative to the optical center of
+ * the largest camera device facing the same direction as this camera.</p>
+ * <p>This default value for API levels before Android P.</p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
+ */
+ public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0;
+
+ /**
+ * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} is relative to the position of the
+ * primary gyroscope of this Android device.</p>
+ * <p>This is the value reported by all devices that support the MOTION_TRACKING capability.</p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
+ */
+ public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1;
+
+ //
// Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
//
@@ -665,6 +689,7 @@ public abstract class CameraMetadata<TKey> {
* </ul>
* </li>
* <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
+ * <li>As of Android P, the {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} entry is listed by this device.</li>
* <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
* normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
* format.</li>
@@ -680,6 +705,7 @@ public abstract class CameraMetadata<TKey> {
* @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
* @see CameraCharacteristics#LENS_FACING
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
* @see CameraCharacteristics#LENS_RADIAL_DISTORTION
@@ -774,6 +800,51 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9;
+ /**
+ * <p>The device supports controls and metadata required for accurate motion tracking for
+ * use cases such as augmented reality, electronic image stabilization, and so on.</p>
+ * <p>This means this camera device has accurate optical calibration and timestamps relative
+ * to the inertial sensors.</p>
+ * <p>This capability requires the camera device to support the following:</p>
+ * <ul>
+ * <li>Capture request templates {@link android.hardware.camera2.CameraDevice#TEMPLATE_MOTION_TRACKING_PREVIEW } and {@link android.hardware.camera2.CameraDevice#TEMPLATE_MOTION_TRACKING_BEST } are defined.</li>
+ * <li>The stream configurations listed in {@link android.hardware.camera2.CameraDevice#createCaptureSession } for MOTION_TRACKING are
+ * supported, either at 30 or 60fps maximum frame rate.</li>
+ * <li>The following camera characteristics and capture result metadata are provided:<ul>
+ * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
+ * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
+ * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+ * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+ * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} with value GYROSCOPE</li>
+ * </ul>
+ * </li>
+ * <li>The {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} field has value <code>REALTIME</code>. When compared to
+ * timestamps from the device's gyroscopes, the clock difference for events occuring at
+ * the same actual time instant will be less than 1 ms.</li>
+ * <li>The value of the {@link CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW android.sensor.rollingShutterSkew} field is accurate to within 1 ms.</li>
+ * <li>The value of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime} is guaranteed to be available in the
+ * capture result.</li>
+ * <li>The {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} control supports MOTION_TRACKING to limit maximum
+ * exposure to 20 milliseconds.</li>
+ * <li>The stream configurations required for MOTION_TRACKING (listed at {@link android.hardware.camera2.CameraDevice#createCaptureSession }) can operate at least at
+ * 30fps; optionally, they can operate at 60fps, and '[60, 60]' is listed in
+ * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}.</li>
+ * </ul>
+ *
+ * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
+ * @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
+ * @see CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
+
//
// Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
//
@@ -1661,6 +1732,16 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6;
+ /**
+ * <p>This request is for a motion tracking use case, where
+ * the application will use camera and inertial sensor data to
+ * locate and track objects in the world.</p>
+ * <p>The camera device auto-exposure routine will limit the exposure time
+ * of the camera to no more than 20 milliseconds, to minimize motion blur.</p>
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+ */
+ public static final int CONTROL_CAPTURE_INTENT_MOTION_TRACKING = 7;
+
//
// Enumeration values for CaptureRequest#CONTROL_EFFECT_MODE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 77da2a51a016..cf27c704f7e5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1487,10 +1487,13 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains PRIVATE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if
- * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are
- * always supported.</p>
+ * <p>All intents are supported by all devices, except that:
+ * * ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * PRIVATE_REPROCESSING or YUV_REPROCESSING.
+ * * MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * MANUAL_SENSOR.
+ * * MOTION_TRACKING will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * MOTION_TRACKING.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
@@ -1500,6 +1503,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <li>{@link #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT VIDEO_SNAPSHOT}</li>
* <li>{@link #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
* <li>{@link #CONTROL_CAPTURE_INTENT_MANUAL MANUAL}</li>
+ * <li>{@link #CONTROL_CAPTURE_INTENT_MOTION_TRACKING MOTION_TRACKING}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1512,6 +1516,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
* @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
* @see #CONTROL_CAPTURE_INTENT_MANUAL
+ * @see #CONTROL_CAPTURE_INTENT_MOTION_TRACKING
*/
@PublicKey
public static final Key<Integer> CONTROL_CAPTURE_INTENT =
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 6d7b06fc609f..b6b0c907a8f9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1754,10 +1754,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains PRIVATE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if
- * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are
- * always supported.</p>
+ * <p>All intents are supported by all devices, except that:
+ * * ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * PRIVATE_REPROCESSING or YUV_REPROCESSING.
+ * * MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * MANUAL_SENSOR.
+ * * MOTION_TRACKING will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * MOTION_TRACKING.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
@@ -1767,6 +1770,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <li>{@link #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT VIDEO_SNAPSHOT}</li>
* <li>{@link #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
* <li>{@link #CONTROL_CAPTURE_INTENT_MANUAL MANUAL}</li>
+ * <li>{@link #CONTROL_CAPTURE_INTENT_MOTION_TRACKING MOTION_TRACKING}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1779,6 +1783,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
* @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
* @see #CONTROL_CAPTURE_INTENT_MANUAL
+ * @see #CONTROL_CAPTURE_INTENT_MOTION_TRACKING
*/
@PublicKey
public static final Key<Integer> CONTROL_CAPTURE_INTENT =
@@ -2761,36 +2766,33 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Position of the camera optical center.</p>
* <p>The position of the camera device's lens optical center,
- * as a three-dimensional vector <code>(x,y,z)</code>, relative to the
- * optical center of the largest camera device facing in the
- * same direction as this camera, in the {@link android.hardware.SensorEvent Android sensor coordinate
- * axes}. Note that only the axis definitions are shared with
- * the sensor coordinate system, but not the origin.</p>
- * <p>If this device is the largest or only camera device with a
- * given facing, then this position will be <code>(0, 0, 0)</code>; a
- * camera device with a lens optical center located 3 cm from
- * the main sensor along the +X axis (to the right from the
- * user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
- * <p>To transform a pixel coordinates between two cameras
- * facing the same direction, first the source camera
- * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then
- * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
- * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
- * of the source camera, the translation of the source camera
- * relative to the destination camera, the
- * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
- * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
- * of the destination camera. This obtains a
- * radial-distortion-free coordinate in the destination
- * camera pixel coordinates.</p>
- * <p>To compare this against a real image from the destination
- * camera, the destination camera image then needs to be
- * corrected for radial distortion before comparison or
- * sampling.</p>
+ * as a three-dimensional vector <code>(x,y,z)</code>.</p>
+ * <p>Prior to Android P, or when {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is PRIMARY_CAMERA, this position
+ * is relative to the optical center of the largest camera device facing in the same
+ * direction as this camera, in the {@link android.hardware.SensorEvent Android sensor
+ * coordinate axes}. Note that only the axis definitions are shared with the sensor
+ * coordinate system, but not the origin.</p>
+ * <p>If this device is the largest or only camera device with a given facing, then this
+ * position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
+ * from the main sensor along the +X axis (to the right from the user's perspective) will
+ * report <code>(0.03, 0, 0)</code>.</p>
+ * <p>To transform a pixel coordinates between two cameras facing the same direction, first
+ * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source
+ * camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
+ * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera
+ * relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination
+ * camera, and finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} of the destination
+ * camera. This obtains a radial-distortion-free coordinate in the destination camera pixel
+ * coordinates.</p>
+ * <p>To compare this against a real image from the destination camera, the destination camera
+ * image then needs to be corrected for radial distortion before comparison or sampling.</p>
+ * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
+ * the center of the primary gyroscope on the device.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index bca2ae6d2e8f..2a4ad0013d4b 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -19,14 +19,20 @@ package android.hardware.location;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
import java.util.Arrays;
/**
+ * @deprecated Use {@link android.hardware.location.NanoAppMessage} instead to send messages with
+ * {@link android.hardware.location.ContextHubClient#sendMessageToNanoApp(
+ * NanoAppMessage)} and receive messages with
+ * {@link android.hardware.location.ContextHubClientCallback#onMessageFromNanoApp(
+ * ContextHubClient, NanoAppMessage)}.
+ *
* @hide
*/
@SystemApi
+@Deprecated
public class ContextHubMessage {
private int mType;
private int mVersion;
@@ -34,7 +40,6 @@ public class ContextHubMessage {
private static final String TAG = "ContextHubMessage";
-
/**
* Get the message type
*
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index 0465defc41ef..b5c01ec214eb 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -28,9 +28,14 @@ import android.util.Log;
* Nano apps are expected to be used only by bundled apps only
* at this time.
*
+ * @deprecated Use {@link android.hardware.location.NanoAppBinary} instead to load a nanoapp with
+ * {@link android.hardware.location.ContextHubManager#loadNanoApp(
+ * ContextHubInfo, NanoAppBinary)}.
+ *
* @hide
*/
@SystemApi
+@Deprecated
public class NanoApp {
private final String TAG = "NanoApp";
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 5ccf546a55ad..75a96ee8c802 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -16,15 +16,18 @@
package android.hardware.location;
-
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
+ * @deprecated Use {@link android.hardware.location.ContextHubManager#queryNanoApps(ContextHubInfo)}
+ * to find loaded nanoapps, which doesn't require using this class as a parameter.
+ *
* @hide
*/
@SystemApi
+@Deprecated
public class NanoAppFilter {
private static final String TAG = "NanoAppFilter";
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index c00819bde6dc..f1926eaa2195 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -28,9 +28,12 @@ import libcore.util.EmptyArray;
*
* TODO(b/69270990) Remove this class once the old API is deprecated.
*
+ * @deprecated Use {@link android.hardware.location.NanoAppState} instead.
+ *
* @hide
*/
@SystemApi
+@Deprecated
public class NanoAppInstanceInfo {
private String mPublisher = "Unknown";
private String mName = "Unknown";
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index f82627b942c3..7d752e89e6f6 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -231,6 +231,31 @@ public final class IpSecAlgorithm implements Parcelable {
}
}
+ /** @hide */
+ public boolean isAuthentication() {
+ switch (getName()) {
+ // Fallthrough
+ case AUTH_HMAC_MD5:
+ case AUTH_HMAC_SHA1:
+ case AUTH_HMAC_SHA256:
+ case AUTH_HMAC_SHA384:
+ case AUTH_HMAC_SHA512:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** @hide */
+ public boolean isEncryption() {
+ return getName().equals(CRYPT_AES_CBC);
+ }
+
+ /** @hide */
+ public boolean isAead() {
+ return getName().equals(AUTH_CRYPT_AES_GCM);
+ }
+
@Override
public String toString() {
return new StringBuilder()
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 33470f36d938..eb264d6d308c 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -805,7 +805,7 @@ final class BinderProxy implements IBinder {
/**
* Return the total number of pairs in the map.
*/
- int size() {
+ private int size() {
int size = 0;
for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
if (a != null) {
@@ -816,6 +816,24 @@ final class BinderProxy implements IBinder {
}
/**
+ * Return the total number of pairs in the map containing values that have
+ * not been cleared. More expensive than the above size function.
+ */
+ private int unclearedSize() {
+ int size = 0;
+ for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
+ if (a != null) {
+ for (WeakReference<BinderProxy> ref : a) {
+ if (ref.get() != null) {
+ ++size;
+ }
+ }
+ }
+ }
+ return size;
+ }
+
+ /**
* Remove ith entry from the hash bucket indicated by hash.
*/
private void remove(int hash, int index) {
@@ -908,17 +926,31 @@ final class BinderProxy implements IBinder {
Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size
+ " total = " + totalSize);
mWarnBucketSize += WARN_INCREMENT;
- if (Build.IS_DEBUGGABLE && totalSize > CRASH_AT_SIZE) {
- diagnosticCrash();
+ if (Build.IS_DEBUGGABLE && totalSize >= CRASH_AT_SIZE) {
+ // Use the number of uncleared entries to determine whether we should
+ // really report a histogram and crash. We don't want to fundamentally
+ // change behavior for a debuggable process, so we GC only if we are
+ // about to crash.
+ final int totalUnclearedSize = unclearedSize();
+ if (totalUnclearedSize >= CRASH_AT_SIZE) {
+ dumpProxyInterfaceCounts();
+ Runtime.getRuntime().gc();
+ throw new AssertionError("Binder ProxyMap has too many entries: "
+ + totalSize + " (total), " + totalUnclearedSize + " (uncleared), "
+ + unclearedSize() + " (uncleared after GC). BinderProxy leak?");
+ } else if (totalSize > 3 * totalUnclearedSize / 2) {
+ Log.v(Binder.TAG, "BinderProxy map has many cleared entries: "
+ + (totalSize - totalUnclearedSize) + " of " + totalSize
+ + " are cleared");
+ }
}
}
}
/**
- * Dump a histogram to the logcat, then throw an assertion error. Used to diagnose
- * abnormally large proxy maps.
+ * Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps.
*/
- private void diagnosticCrash() {
+ private void dumpProxyInterfaceCounts() {
Map<String, Integer> counts = new HashMap<>();
for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
if (a != null) {
@@ -953,11 +985,6 @@ final class BinderProxy implements IBinder {
Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i].getKey() + " x"
+ sorted[i].getValue());
}
-
- // Now throw an assertion.
- final int totalSize = size();
- throw new AssertionError("Binder ProxyMap has too many entries: " + totalSize
- + ". BinderProxy leak?");
}
// Corresponding ArrayLists in the following two arrays always have the same size.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index f643c578ebe7..01d6b022043f 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -98,4 +98,6 @@ interface IUserManager {
boolean isUserNameSet(int userHandle);
boolean hasRestrictedProfiles();
boolean trySetQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target);
+ long getUserStartRealtime();
+ long getUserUnlockRealtime();
}
diff --git a/core/java/android/os/Seccomp.java b/core/java/android/os/Seccomp.java
index f14e93fe9403..335e44b65711 100644
--- a/core/java/android/os/Seccomp.java
+++ b/core/java/android/os/Seccomp.java
@@ -20,5 +20,6 @@ package android.os;
* @hide
*/
public final class Seccomp {
- public static final native void setPolicy();
+ public static native void setSystemServerPolicy();
+ public static native void setAppPolicy();
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 38993b71a31d..44238df108cf 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1392,6 +1392,34 @@ public class UserManager {
}
/**
+ * Return the time when the calling user started in elapsed milliseconds since boot,
+ * or 0 if not started.
+ *
+ * @hide
+ */
+ public long getUserStartRealtime() {
+ try {
+ return mService.getUserStartRealtime();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return the time when the calling user was unlocked elapsed milliseconds since boot,
+ * or 0 if not unlocked.
+ *
+ * @hide
+ */
+ public long getUserUnlockRealtime() {
+ try {
+ return mService.getUserUnlockRealtime();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the UserInfo object describing a specific user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle the user handle of the user whose information is being requested.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0850bd997c3a..2ec4906f082b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8704,6 +8704,8 @@ public final class Settings {
/**
* Whether soft AP will shut down after a timeout period when no devices are connected.
+ *
+ * Type: int (0 for false, 1 for true)
* @hide
*/
public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
@@ -9800,6 +9802,14 @@ public final class Settings {
public static final java.lang.String APP_STANDBY_ENABLED = "app_standby_enabled";
/**
+ * Whether or not Network Watchlist feature is enabled.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled";
+
+ /**
* Get the key that retrieves a bluetooth headset's priority.
* @hide
*/
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 555c4740389a..81467292d491 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -25,7 +25,6 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.Signature;
import android.os.Trace;
import android.util.jar.StrictJarFile;
@@ -53,6 +52,10 @@ import java.util.zip.ZipEntry;
*/
public class ApkSignatureVerifier {
+ public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
+ public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
+ public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3;
+
private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
/**
@@ -60,11 +63,10 @@ public class ApkSignatureVerifier {
*
* @throws PackageParserException if the APK's signature failed to verify.
*/
- public static PackageParser.SigningDetails verify(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion)
+ public static Result verify(String apkPath, int minSignatureSchemeVersion)
throws PackageParserException {
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
// V3 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -78,11 +80,10 @@ public class ApkSignatureVerifier {
ApkSignatureSchemeV3Verifier.verify(apkPath);
Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V3);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v3 signature in package " + apkPath, e);
}
@@ -96,7 +97,7 @@ public class ApkSignatureVerifier {
}
// redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
// V2 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -109,11 +110,10 @@ public class ApkSignatureVerifier {
Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(
- signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V2);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V2) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v2 signature in package " + apkPath, e);
}
@@ -127,7 +127,7 @@ public class ApkSignatureVerifier {
}
// redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
+ if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
// V1 and is older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -145,8 +145,7 @@ public class ApkSignatureVerifier {
*
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV1Signature(
- String apkPath, boolean verifyFull)
+ private static Result verifyV1Signature(String apkPath, boolean verifyFull)
throws PackageParserException {
StrictJarFile jarFile = null;
@@ -212,7 +211,7 @@ public class ApkSignatureVerifier {
}
}
}
- return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
+ return new Result(lastCerts, lastSigs, VERSION_JAR_SIGNATURE_SCHEME);
} catch (GeneralSecurityException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
@@ -290,11 +289,10 @@ public class ApkSignatureVerifier {
* @throws PackageParserException if the APK's signature failed to verify.
* or greater is not found, except in the case of no JAR signature.
*/
- public static PackageParser.SigningDetails plsCertsNoVerifyOnlyCerts(
- String apkPath, int minSignatureSchemeVersion)
+ public static Result plsCertsNoVerifyOnlyCerts(String apkPath, int minSignatureSchemeVersion)
throws PackageParserException {
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
// V3 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -308,11 +306,10 @@ public class ApkSignatureVerifier {
ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath);
Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V3);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v3 signature in package " + apkPath, e);
}
@@ -326,7 +323,7 @@ public class ApkSignatureVerifier {
}
// redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
// V2 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -339,11 +336,10 @@ public class ApkSignatureVerifier {
Certificate[][] signerCerts =
ApkSignatureSchemeV2Verifier.plsCertsNoVerifyOnlyCerts(apkPath);
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V2);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V2) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v2 signature in package " + apkPath, e);
}
@@ -357,7 +353,7 @@ public class ApkSignatureVerifier {
}
// redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
+ if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
// V1 and is older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
@@ -367,4 +363,19 @@ public class ApkSignatureVerifier {
// v2 didn't work, try jarsigner
return verifyV1Signature(apkPath, false);
}
+
+ /**
+ * Result of a successful APK verification operation.
+ */
+ public static class Result {
+ public final Certificate[][] certs;
+ public final Signature[] sigs;
+ public final int signatureSchemeVersion;
+
+ public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
+ this.certs = certs;
+ this.sigs = sigs;
+ this.signatureSchemeVersion = signingVersion;
+ }
+ }
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index a417a4a04e2f..1f7f8b9a0c32 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -182,6 +182,11 @@ public class Surface implements Parcelable {
* SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
* SurfaceTexture#updateTexImage}.
*
+ * Please note that holding onto the Surface created here is not enough to
+ * keep the provided SurfaceTexture from being reclaimed. In that sense,
+ * the Surface will act like a
+ * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture.
+ *
* @param surfaceTexture The {@link SurfaceTexture} that is updated by this
* Surface.
* @throws OutOfResourcesException if the surface could not be created.
diff --git a/core/java/android/widget/MediaController2.java b/core/java/android/widget/MediaController2.java
new file mode 100644
index 000000000000..9035137d5362
--- /dev/null
+++ b/core/java/android/widget/MediaController2.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 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.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.media.session.MediaController;
+import android.media.update.ApiLoader;
+import android.media.update.MediaController2Provider;
+import android.media.update.ViewProvider;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+/**
+ * TODO PUBLIC API
+ * @hide
+ */
+public class MediaController2 extends FrameLayout {
+ private final MediaController2Provider mProvider;
+
+ public MediaController2(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mProvider = ApiLoader.getProvider(context)
+ .createMediaController2(this, new SuperProvider());
+ }
+
+ public void setController(MediaController controller) {
+ mProvider.setController_impl(controller);
+ }
+
+ public void setAnchorView(View view) {
+ mProvider.setAnchorView_impl(view);
+ }
+
+ public void show() {
+ mProvider.show_impl();
+ }
+
+ public void show(int timeout) {
+ mProvider.show_impl(timeout);
+ }
+
+ public boolean isShowing() {
+ return mProvider.isShowing_impl();
+ }
+
+ public void hide() {
+ mProvider.hide_impl();
+ }
+
+ public void setPrevNextListeners(OnClickListener next, OnClickListener prev) {
+ mProvider.setPrevNextListeners_impl(next, prev);
+ }
+
+ public void showCCButton() {
+ mProvider.showCCButton_impl();
+ }
+
+ public boolean isPlaying() {
+ return mProvider.isPlaying_impl();
+ }
+
+ public int getCurrentPosition() {
+ return mProvider.getCurrentPosition_impl();
+ }
+
+ public int getBufferPercentage() {
+ return mProvider.getBufferPercentage_impl();
+ }
+
+ public boolean canPause() {
+ return mProvider.canPause_impl();
+ }
+
+ public boolean canSeekBackward() {
+ return mProvider.canSeekBackward_impl();
+ }
+
+ public boolean canSeekForward() {
+ return mProvider.canSeekForward_impl();
+ }
+
+ public void showSubtitle() {
+ mProvider.showSubtitle_impl();
+ }
+
+ public void hideSubtitle() {
+ mProvider.hideSubtitle_impl();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ mProvider.onAttachedToWindow_impl();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mProvider.onDetachedFromWindow_impl();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mProvider.onLayout_impl(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mProvider.draw_impl(canvas);
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName() {
+ return mProvider.getAccessibilityClassName_impl();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return mProvider.onTouchEvent_impl(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev) {
+ return mProvider.onTrackballEvent_impl(ev);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return mProvider.onKeyDown_impl(keyCode, event);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ mProvider.onFinishInflate_impl();
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return mProvider.dispatchKeyEvent_impl(event);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mProvider.setEnabled_impl(enabled);
+ }
+
+ private class SuperProvider implements ViewProvider {
+ @Override
+ public void onAttachedToWindow_impl() {
+ MediaController2.super.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow_impl() {
+ MediaController2.super.onDetachedFromWindow();
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ MediaController2.super.onLayout(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void draw_impl(Canvas canvas) {
+ MediaController2.super.draw(canvas);
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName_impl() {
+ return MediaController2.super.getAccessibilityClassName();
+ }
+
+ @Override
+ public boolean onTouchEvent_impl(MotionEvent ev) {
+ return MediaController2.super.onTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent_impl(MotionEvent ev) {
+ return MediaController2.super.onTrackballEvent(ev);
+ }
+
+ @Override
+ public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
+ return MediaController2.super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public void onFinishInflate_impl() {
+ MediaController2.super.onFinishInflate();
+ }
+
+ @Override
+ public boolean dispatchKeyEvent_impl(KeyEvent event) {
+ return MediaController2.super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public void setEnabled_impl(boolean enabled) {
+ MediaController2.super.setEnabled(enabled);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 77cfc2fc5bd4..96d3baf7cf0b 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -411,6 +411,9 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
mContext.unbindService(mConnection);
mConnection.destroy();
}
+ if (mAfterCompute != null) {
+ mAfterCompute.afterCompute();
+ }
if (DEBUG) {
Log.d(TAG, "Unbinded Resolver Ranker.");
}
@@ -573,7 +576,6 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
if (DEBUG) {
Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction");
}
- return;
} else {
try {
mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index cbc63cf813cb..3ebe921234b6 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import android.os.IVold;
+import android.os.Seccomp;
import android.os.Trace;
import android.system.ErrnoException;
import android.system.Os;
@@ -153,6 +154,9 @@ public final class Zygote {
*/
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+ // Set system server specific seccomp policy.
+ Seccomp.setSystemServerPolicy();
+
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 6a87b1f4d3fd..24c4a8d8d438 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -30,6 +30,7 @@ import android.net.Credentials;
import android.net.LocalSocket;
import android.os.FactoryTest;
import android.os.Process;
+import android.os.Seccomp;
import android.os.SystemProperties;
import android.os.Trace;
import android.system.ErrnoException;
@@ -767,6 +768,9 @@ class ZygoteConnection {
Process.setArgV0(parsedArgs.niceName);
}
+ // Set app specific seccomp policy.
+ Seccomp.setAppPolicy();
+
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 2be6212b9f1e..c906db74f8a9 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -650,7 +650,7 @@ public class ZygoteInit {
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
@@ -782,9 +782,6 @@ public class ZygoteInit {
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
- // Set seccomp policy
- Seccomp.setPolicy();
-
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
index 06e2a167de0a..b9006e4403cd 100644
--- a/core/jni/android_os_seccomp.cpp
+++ b/core/jni/android_os_seccomp.cpp
@@ -21,20 +21,33 @@
#include "seccomp_policy.h"
-static void Seccomp_setPolicy(JNIEnv* /*env*/) {
+static void Seccomp_setSystemServerPolicy(JNIEnv* /*env*/) {
if (security_getenforce() == 0) {
ALOGI("seccomp disabled by setenforce 0");
return;
}
- if (!set_seccomp_filter()) {
+ if (!set_system_seccomp_filter()) {
+ ALOGE("Failed to set seccomp policy - killing");
+ exit(1);
+ }
+}
+
+static void Seccomp_setAppPolicy(JNIEnv* /*env*/) {
+ if (security_getenforce() == 0) {
+ ALOGI("seccomp disabled by setenforce 0");
+ return;
+ }
+
+ if (!set_app_seccomp_filter()) {
ALOGE("Failed to set seccomp policy - killing");
exit(1);
}
}
static const JNINativeMethod method_table[] = {
- NATIVE_METHOD(Seccomp, setPolicy, "()V"),
+ NATIVE_METHOD(Seccomp, setSystemServerPolicy, "()V"),
+ NATIVE_METHOD(Seccomp, setAppPolicy, "()V"),
};
namespace android {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3a6b2de49311..beb5cdc748c6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1801,6 +1801,15 @@
<permission android:name="android.permission.ALLOCATE_AGGRESSIVE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide
+ Allows an application to use reserved disk space.
+ <p>Not for use by third-party applications. Should only be requested by
+ apps that provide core system functionality, to ensure system stability
+ when disk is otherwise completely full.
+ -->
+ <permission android:name="android.permission.USE_RESERVED_DISK"
+ android:protectionLevel="signature|privileged" />
+
<!-- ================================== -->
<!-- Permissions for screenlock -->
<!-- ================================== -->
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
new file mode 100644
index 000000000000..3254ebba2f66
--- /dev/null
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, 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.
+*/
+-->
+<!-- This should be kept in sync with task_open_enter.xml -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" android:zAdjustment="top">
+
+ <alpha android:fromAlpha="0" android:toAlpha="1.0"
+ android:startOffset="300"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quart"
+ android:duration="167"/>
+
+ <translate android:fromYDelta="110%" android:toYDelta="0"
+ android:startOffset="300"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:duration="417"/>
+
+ <!-- To keep the thumbnail around longer -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="717"
+ android:duration="200"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index e511cc9d9931..b73e14fc637f 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -16,7 +16,7 @@
** limitations under the License.
*/
-->
-
+<!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
new file mode 100644
index 000000000000..ad89fde92065
--- /dev/null
+++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, 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.
+*/
+-->
+<!-- This should in sync with task_open_enter.xml -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" android:zAdjustment="top">
+
+ <alpha android:fromAlpha="0" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quart"
+ android:startOffset="300"
+ android:duration="167"/>
+
+ <translate android:fromYDelta="110%" android:toYDelta="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="417"/>
+
+ <!-- To keep the transition around longer for the thumbnail, should be kept in sync with
+ cross_profile_apps_thumbmail.xml -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:startOffset="717"
+ android:duration="200"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a659b370560f..6c1661c4abc2 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -631,4 +631,8 @@
<!-- Default dialog corner radius -->
<dimen name="dialog_corner_radius">2dp</dimen>
+
+ <!-- Size of thumbnail used in the cross profile apps animation -->
+ <dimen name="cross_profile_apps_thumbnail_size">72dp</dimen>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4343ba01702b..9f582ad8768d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1578,8 +1578,10 @@
<java-symbol type="anim" name="voice_activity_close_enter" />
<java-symbol type="anim" name="voice_activity_open_exit" />
<java-symbol type="anim" name="voice_activity_open_enter" />
- <java-symbol type="anim" name="activity_open_exit" />
- <java-symbol type="anim" name="activity_open_enter" />
+ <java-symbol type="anim" name="task_open_exit" />
+ <java-symbol type="anim" name="task_open_enter" />
+ <java-symbol type="anim" name="cross_profile_apps_thumbnail_enter" />
+ <java-symbol type="anim" name="task_open_enter_cross_profile_apps" />
<java-symbol type="array" name="config_autoRotationTiltTolerance" />
<java-symbol type="array" name="config_keyboardTapVibePattern" />
@@ -1726,6 +1728,7 @@
<java-symbol type="style" name="Theme.ExpandedMenu" />
<java-symbol type="string" name="forward_intent_to_owner" />
<java-symbol type="string" name="forward_intent_to_work" />
+ <java-symbol type="dimen" name="cross_profile_apps_thumbnail_size" />
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 718393410d3b..b51c677e74ff 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -28,6 +28,7 @@ import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.test.InstrumentationRegistry;
@@ -215,9 +216,11 @@ public class NotificationTest {
}
@Test
- public void testMessagingStyle_isGroupConversation() {
+ public void messagingStyle_isGroupConversation() {
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
- .setGroupConversation(true);
+ .setGroupConversation(true)
+ .setConversationTitle("test conversation title");
Notification notification = new Notification.Builder(mContext, "test id")
.setSmallIcon(1)
.setContentTitle("test title")
@@ -228,6 +231,56 @@ public class NotificationTest {
assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
}
+ @Test
+ public void messagingStyle_isGroupConversation_noConversationTitle() {
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
+ .setGroupConversation(true)
+ .setConversationTitle(null);
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("test title")
+ .setStyle(messagingStyle)
+ .build();
+
+ assertTrue(messagingStyle.isGroupConversation());
+ assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
+ }
+
+ @Test
+ public void messagingStyle_isGroupConversation_withConversationTitle_legacy() {
+ // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
+ .setGroupConversation(false)
+ .setConversationTitle("test conversation title");
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("test title")
+ .setStyle(messagingStyle)
+ .build();
+
+ assertTrue(messagingStyle.isGroupConversation());
+ assertFalse(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
+ }
+
+ @Test
+ public void messagingStyle_isGroupConversation_withoutConversationTitle_legacy() {
+ // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
+ .setGroupConversation(true)
+ .setConversationTitle(null);
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("test title")
+ .setStyle(messagingStyle)
+ .build();
+
+ assertFalse(messagingStyle.isGroupConversation());
+ assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
+ }
+
private Notification.Builder getMediaNotification() {
MediaSession session = new MediaSession(mContext, "test");
return new Notification.Builder(mContext, "color")
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index dfefbfd79551..7cfedc8a1f52 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -282,6 +282,7 @@ public class SettingsBackupTest {
Settings.Global.NETWORK_SCORING_UI_ENABLED,
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+ Settings.Global.NETWORK_WATCHLIST_ENABLED,
Settings.Global.NEW_CONTACT_AGGREGATOR,
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1affba053057..d2c855b5badb 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -112,6 +112,10 @@
<group gid="media" />
</permission>
+ <permission name="android.permission.USE_RESERVED_DISK">
+ <group gid="reserved_disk" />
+ </permission>
+
<!-- These are permissions that were mapped to gids but we need
to keep them here until an upgrade from L to the current
version is to be supported. These permissions are built-in
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 7bb28599c505..4732beca6394 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -136,6 +136,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
<privapp-permissions package="com.android.phone">
@@ -181,6 +182,7 @@ applications that come with the platform
<privapp-permissions package="com.android.providers.calendar">
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
<privapp-permissions package="com.android.providers.contacts">
@@ -189,6 +191,7 @@ applications that come with the platform
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
<privapp-permissions package="com.android.providers.downloads">
@@ -203,12 +206,14 @@ applications that come with the platform
<permission name="android.permission.ACCESS_MTP"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
<privapp-permissions package="com.android.providers.telephony">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
<privapp-permissions package="com.android.provision">
@@ -253,6 +258,7 @@ applications that come with the platform
<permission name="android.permission.SET_TIME"/>
<permission name="android.permission.STATUS_BAR"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.USER_ACTIVITY"/>
<permission name="android.permission.WRITE_APN_SETTINGS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
@@ -316,6 +322,7 @@ applications that come with the platform
<permission name="android.permission.STOP_APP_SWITCHES"/>
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
@@ -329,6 +336,7 @@ applications that come with the platform
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
@@ -365,6 +373,7 @@ applications that come with the platform
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_DREAM_STATE"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
new file mode 100644
index 000000000000..b57e02d559e0
--- /dev/null
+++ b/media/java/android/media/update/ApiLoader.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 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.media.update;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+/**
+ * @hide
+ */
+public final class ApiLoader {
+ private static Object sMediaLibrary;
+
+ private static final String UPDATE_PACKAGE = "com.android.media.update";
+ private static final String UPDATE_CLASS = "com.android.media.update.ApiFactory";
+ private static final String UPDATE_METHOD = "initialize";
+
+ private ApiLoader() { }
+
+ public static StaticProvider getProvider(Context context) {
+ try {
+ return (StaticProvider) getMediaLibraryImpl(context);
+ } catch (NameNotFoundException | ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
+ private static synchronized Object getMediaLibraryImpl(Context appContext)
+ throws NameNotFoundException, ReflectiveOperationException {
+ if (sMediaLibrary != null) return sMediaLibrary;
+
+ // TODO Dynamically find the package name
+ Context libContext = appContext.createPackageContext(UPDATE_PACKAGE,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ sMediaLibrary = libContext.getClassLoader()
+ .loadClass(UPDATE_CLASS)
+ .getMethod(UPDATE_METHOD, Context.class)
+ .invoke(null, appContext);
+ return sMediaLibrary;
+ }
+}
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
new file mode 100644
index 000000000000..71fbd084e643
--- /dev/null
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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.media.update;
+
+import android.annotation.SystemApi;
+import android.media.session.MediaController;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.widget.MediaController2
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface MediaController2Provider extends ViewProvider {
+ void setController_impl(MediaController controller);
+ void setAnchorView_impl(View view);
+ void show_impl();
+ void show_impl(int timeout);
+ boolean isShowing_impl();
+ void hide_impl();
+ void setPrevNextListeners_impl(OnClickListener next, OnClickListener prev);
+ void showCCButton_impl();
+ boolean isPlaying_impl();
+ int getCurrentPosition_impl();
+ int getBufferPercentage_impl();
+ boolean canPause_impl();
+ boolean canSeekBackward_impl();
+ boolean canSeekForward_impl();
+ void showSubtitle_impl();
+ void hideSubtitle_impl();
+}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
new file mode 100644
index 000000000000..19f01c2bcc7f
--- /dev/null
+++ b/media/java/android/media/update/StaticProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.media.update;
+
+import android.annotation.SystemApi;
+import android.widget.MediaController2;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * This interface provides access to constructors and static methods that are otherwise not directly
+ * accessible via an implementation object.
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface StaticProvider {
+ MediaController2Provider createMediaController2(
+ MediaController2 instance, ViewProvider superProvider);
+}
diff --git a/media/java/android/media/update/ViewProvider.java b/media/java/android/media/update/ViewProvider.java
new file mode 100644
index 000000000000..bc8f20302d35
--- /dev/null
+++ b/media/java/android/media/update/ViewProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.media.update;
+
+import android.annotation.SystemApi;
+import android.graphics.Canvas;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.view.View
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface ViewProvider {
+ // TODO Add more (all?) methods from View
+ void onAttachedToWindow_impl();
+ void onDetachedFromWindow_impl();
+ void onLayout_impl(boolean changed, int left, int top, int right, int bottom);
+ void draw_impl(Canvas canvas);
+ CharSequence getAccessibilityClassName_impl();
+ boolean onTouchEvent_impl(MotionEvent ev);
+ boolean onTrackballEvent_impl(MotionEvent ev);
+ boolean onKeyDown_impl(int keyCode, KeyEvent event);
+ void onFinishInflate_impl();
+ boolean dispatchKeyEvent_impl(KeyEvent event);
+ void setEnabled_impl(boolean enabled);
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d675a7a83056..b3d635741b86 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -43,6 +43,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.MANAGE_USB" />
+ <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 29ecac0080ee..aa2cdbb7730f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -49,6 +49,7 @@
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
+ <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
<!-- Networking and telephony -->
<uses-permission android:name="android.permission.BLUETOOTH" />
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 5c098e32045b..02cfe3dc75e5 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -52,6 +52,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -1030,6 +1031,30 @@ public class IpSecService extends IIpSecService.Stub {
releaseResource(userRecord.mEncapSocketRecords, resourceId);
}
+ @VisibleForTesting
+ void validateAlgorithms(IpSecConfig config, int direction) throws IllegalArgumentException {
+ IpSecAlgorithm auth = config.getAuthentication(direction);
+ IpSecAlgorithm crypt = config.getEncryption(direction);
+ IpSecAlgorithm aead = config.getAuthenticatedEncryption(direction);
+
+ // Validate the algorithm set
+ Preconditions.checkArgument(
+ aead != null || crypt != null || auth != null,
+ "No Encryption or Authentication algorithms specified");
+ Preconditions.checkArgument(
+ auth == null || auth.isAuthentication(),
+ "Unsupported algorithm for Authentication");
+ Preconditions.checkArgument(
+ crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption");
+ Preconditions.checkArgument(
+ aead == null || aead.isAead(),
+ "Unsupported algorithm for Authenticated Encryption");
+ Preconditions.checkArgument(
+ aead == null || (auth == null && crypt == null),
+ "Authenticated Encryption is mutually exclusive with other Authentication "
+ + "or Encryption algorithms");
+ }
+
/**
* Checks an IpSecConfig parcel to ensure that the contents are sane and throws an
* IllegalArgumentException if they are not.
@@ -1079,17 +1104,7 @@ public class IpSecService extends IIpSecService.Stub {
}
for (int direction : DIRECTIONS) {
- IpSecAlgorithm crypt = config.getEncryption(direction);
- IpSecAlgorithm auth = config.getAuthentication(direction);
- IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction);
- if (authenticatedEncryption == null && crypt == null && auth == null) {
- throw new IllegalArgumentException(
- "No Encryption or Authentication algorithms specified");
- } else if (authenticatedEncryption != null && (auth != null || crypt != null)) {
- throw new IllegalArgumentException(
- "Authenticated Encryption is mutually"
- + " exclusive with other Authentication or Encryption algorithms");
- }
+ validateAlgorithms(config, direction);
// Retrieve SPI record; will throw IllegalArgumentException if not found
userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction));
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index eb022b78d958..66f0592e36e5 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -42,6 +42,7 @@ import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.StatsLog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.SomeArgs;
@@ -431,6 +432,12 @@ class ActivityMetricsLogger {
builder.setType(type);
builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
mMetricsLogger.write(builder);
+ StatsLog.write(
+ StatsLog.APP_START_CANCEL_CHANGED,
+ info.launchedActivity.appInfo.uid,
+ info.launchedActivity.packageName,
+ convertAppStartTransitionType(type),
+ info.launchedActivity.info.name);
}
private void logAppTransitionMultiEvents() {
@@ -450,9 +457,9 @@ class ActivityMetricsLogger {
builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
info.launchedActivity.launchedFromPackage);
}
- if (info.launchedActivity.info.launchToken != null) {
- builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN,
- info.launchedActivity.info.launchToken);
+ String launchToken = info.launchedActivity.info.launchToken;
+ if (launchToken != null) {
+ builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN, launchToken);
info.launchedActivity.info.launchToken = null;
}
builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
@@ -470,9 +477,37 @@ class ActivityMetricsLogger {
}
builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
mMetricsLogger.write(builder);
+ StatsLog.write(
+ StatsLog.APP_START_CHANGED,
+ info.launchedActivity.appInfo.uid,
+ info.launchedActivity.packageName,
+ convertAppStartTransitionType(type),
+ info.launchedActivity.info.name,
+ info.launchedActivity.launchedFromPackage,
+ isInstantApp,
+ mCurrentTransitionDeviceUptime * 1000,
+ info.reason,
+ mCurrentTransitionDelayMs,
+ info.startingWindowDelayMs,
+ info.bindApplicationDelayMs,
+ info.windowsDrawnDelayMs,
+ launchToken);
}
}
+ private int convertAppStartTransitionType(int tronType) {
+ if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
+ return StatsLog.APP_START_CHANGED__TYPE__COLD;
+ }
+ if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
+ return StatsLog.APP_START_CHANGED__TYPE__WARM;
+ }
+ if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
+ return StatsLog.APP_START_CHANGED__TYPE__HOT;
+ }
+ return StatsLog.APP_START_CHANGED__TYPE__APP_START_TRANSITION_TYPE_UNKNOWN;
+ }
+
void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
final StackTransitionInfo info = mLastStackTransitionInfo.get(r.getStackId());
if (info == null) {
@@ -481,14 +516,24 @@ class ActivityMetricsLogger {
final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
builder.setPackageName(r.packageName);
builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
- builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS,
- SystemClock.uptimeMillis() - mLastTransitionStartTime);
+ long startupTimeMs = SystemClock.uptimeMillis() - mLastTransitionStartTime;
+ builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
builder.setType(restoredFromBundle
? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
: TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
info.currentTransitionProcessRunning ? 1 : 0);
mMetricsLogger.write(builder);
+ StatsLog.write(
+ StatsLog.APP_START_FULLY_DRAWN_CHANGED,
+ info.launchedActivity.appInfo.uid,
+ info.launchedActivity.packageName,
+ restoredFromBundle
+ ? StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITH_BUNDLE
+ : StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITHOUT_BUNDLE,
+ info.launchedActivity.info.name,
+ info.currentTransitionProcessRunning,
+ startupTimeMs);
}
private int getTransitionType(StackTransitionInfo info) {
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 29b322eaff10..d957ca054819 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -25,6 +25,9 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
public class SyncJobService extends JobService {
private static final String TAG = "SyncManager";
@@ -32,7 +35,14 @@ public class SyncJobService extends JobService {
public static final String EXTRA_MESSENGER = "messenger";
private Messenger mMessenger;
- private SparseArray<JobParameters> jobParamsMap = new SparseArray<JobParameters>();
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final SparseArray<JobParameters> mJobParamsMap = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mStartedSyncs = new SparseBooleanArray();
private final SyncLogger mLogger = SyncLogger.getInstance();
@@ -69,8 +79,10 @@ public class SyncJobService extends JobService {
mLogger.purgeOldLogs();
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- synchronized (jobParamsMap) {
- jobParamsMap.put(params.getJobId(), params);
+ synchronized (mLock) {
+ final int jobId = params.getJobId();
+ mJobParamsMap.put(jobId, params);
+ mStartedSyncs.delete(jobId);
}
Message m = Message.obtain();
m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC;
@@ -97,8 +109,18 @@ public class SyncJobService extends JobService {
+ params.getStopReason());
}
mLogger.log("onStopJob() ", mLogger.jobParametersToString(params));
- synchronized (jobParamsMap) {
- jobParamsMap.remove(params.getJobId());
+ synchronized (mLock) {
+ final int jobId = params.getJobId();
+ mJobParamsMap.remove(jobId);
+
+ if (!mStartedSyncs.get(jobId)) {
+ final String message = "Job " + jobId + " didn't start: params=" +
+ jobParametersToString(params);
+ mLogger.log(message);
+ Slog.wtf(TAG, message);
+ }
+
+ mStartedSyncs.delete(jobId);
}
Message m = Message.obtain();
m.what = SyncManager.SyncHandler.MESSAGE_STOP_SYNC;
@@ -117,8 +139,8 @@ public class SyncJobService extends JobService {
}
public void callJobFinished(int jobId, boolean needsReschedule, String why) {
- synchronized (jobParamsMap) {
- JobParameters params = jobParamsMap.get(jobId);
+ synchronized (mLock) {
+ JobParameters params = mJobParamsMap.get(jobId);
mLogger.log("callJobFinished()",
" jobid=", jobId,
" needsReschedule=", needsReschedule,
@@ -126,10 +148,25 @@ public class SyncJobService extends JobService {
" why=", why);
if (params != null) {
jobFinished(params, needsReschedule);
- jobParamsMap.remove(jobId);
+ mJobParamsMap.remove(jobId);
} else {
Slog.e(TAG, "Job params not found for " + String.valueOf(jobId));
}
}
}
+
+ public void markSyncStarted(int jobId) {
+ synchronized (mLock) {
+ mStartedSyncs.put(jobId, true);
+ }
+ }
+
+ public static String jobParametersToString(JobParameters params) {
+ if (params == null) {
+ return "job:null";
+ } else {
+ return "job:#" + params.getJobId() + ":"
+ + SyncOperation.maybeCreateFromJobExtras(params.getExtras());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 85037688d2d4..75c01819a9ea 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -233,12 +233,7 @@ public class SyncLogger {
@Override
public String jobParametersToString(JobParameters params) {
- if (params == null) {
- return "job:null";
- } else {
- return "job:#" + params.getJobId() + ":"
- + SyncOperation.maybeCreateFromJobExtras(params.getExtras());
- }
+ return SyncJobService.jobParametersToString(params);
}
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 965159bdfd76..ad2cf6c18d92 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2898,6 +2898,8 @@ public class SyncManager {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) Slog.v(TAG, op.toString());
+ mSyncJobService.markSyncStarted(op.jobId);
+
if (mStorageIsLow) {
deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
return;
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index f35e6ec92dae..3bcc36f0ba2c 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -29,6 +29,7 @@ import android.os.SharedMemory;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
@@ -53,9 +54,6 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
private static final String TAG = NetworkWatchlistService.class.getSimpleName();
static final boolean DEBUG = false;
- private static final String PROPERTY_NETWORK_WATCHLIST_ENABLED =
- "ro.network_watchlist_enabled";
-
private static final int MAX_NUM_OF_WATCHLIST_DIGESTS = 10000;
public static class Lifecycle extends SystemService {
@@ -67,8 +65,10 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
@Override
public void onStart() {
- if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
+ if (Settings.Global.getInt(getContext().getContentResolver(),
+ Settings.Global.NETWORK_WATCHLIST_ENABLED, 0) == 0) {
// Watchlist service is disabled
+ Slog.i(TAG, "Network Watchlist service is disabled");
return;
}
mService = new NetworkWatchlistService(getContext());
@@ -77,11 +77,13 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
@Override
public void onBootPhase(int phase) {
- if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
- // Watchlist service is disabled
- return;
- }
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ if (Settings.Global.getInt(getContext().getContentResolver(),
+ Settings.Global.NETWORK_WATCHLIST_ENABLED, 0) == 0) {
+ // Watchlist service is disabled
+ Slog.i(TAG, "Network Watchlist service is disabled");
+ return;
+ }
try {
mService.initIpConnectivityMetrics();
mService.startWatchlistLogging();
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index af20cd77e626..c964f912feb1 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -49,6 +49,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -301,7 +302,7 @@ class InstantAppRegistry {
// into account but also allow the value from the old computation to avoid
// data loss.
final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests(
- pkg.mSigningDetails.signatures);
+ pkg.mSignatures);
final String signaturesSha256Digest = PackageUtils.computeSignaturesSha256Digest(
signaturesSha256Digests);
@@ -312,7 +313,7 @@ class InstantAppRegistry {
}
// For backwards compatibility we accept match based on first signature
- if (pkg.mSigningDetails.signatures.length > 1 && currentCookieFile.equals(computeInstantCookieFile(
+ if (pkg.mSignatures.length > 1 && currentCookieFile.equals(computeInstantCookieFile(
pkg.packageName, signaturesSha256Digests[0], userId))) {
return;
}
@@ -1175,13 +1176,12 @@ class InstantAppRegistry {
// We prefer the modern computation procedure where all certs are taken
// into account and delete the file derived via the legacy hash computation.
File newCookieFile = computeInstantCookieFile(pkg.packageName,
- PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId);
- if (!pkg.mSigningDetails.hasSignatures()) {
- Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
- }
- File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
- if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
- oldCookieFile.delete();
+ PackageUtils.computeSignaturesSha256Digest(pkg.mSignatures), userId);
+ if (pkg.mSignatures.length > 0) {
+ File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+ if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
+ oldCookieFile.delete();
+ }
}
cancelPendingPersistLPw(pkg, userId);
addPendingPersistCookieLPw(userId, pkg, cookie, newCookieFile);
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 93d3b77511bc..fca95857c7e0 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -188,7 +188,7 @@ public class KeySetManagerService {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Passed invalid package to keyset validation.");
}
- ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
+ ArraySet<PublicKey> signingKeys = pkg.mSigningKeys;
if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package has invalid signing-key-set.");
@@ -223,7 +223,7 @@ public class KeySetManagerService {
PackageSetting ps = mPackages.get(pkg.packageName);
Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
+ "does not have a corresponding entry in mPackages.");
- addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
+ addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys);
if (pkg.mKeySetMapping != null) {
addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
if (pkg.mUpgradeKeySets != null) {
@@ -371,7 +371,7 @@ public class KeySetManagerService {
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
- if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
+ if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4e918983ddd6..5577de8ccde9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -58,6 +58,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.Signature;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
@@ -83,7 +84,6 @@ import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
-import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.NativeLibraryHelper;
@@ -107,7 +107,7 @@ import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.security.cert.CertificateException;
+import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -227,7 +227,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private long mVersionCode;
@GuardedBy("mLock")
- private PackageParser.SigningDetails mSigningDetails;
+ private Signature[] mSignatures;
+ @GuardedBy("mLock")
+ private Certificate[][] mCertificates;
/**
* Path to the validated base APK for this session, which may point at an
@@ -855,7 +857,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
Preconditions.checkNotNull(mPackageName);
- Preconditions.checkNotNull(mSigningDetails);
+ Preconditions.checkNotNull(mSignatures);
Preconditions.checkNotNull(mResolvedBaseFile);
if (needToAskForPermissionsLocked()) {
@@ -936,7 +938,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mRelinquished = true;
mPm.installStage(mPackageName, stageDir, localObserver, params,
- mInstallerPackageName, mInstallerUid, user, mSigningDetails);
+ mInstallerPackageName, mInstallerUid, user, mCertificates);
}
/**
@@ -955,7 +957,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throws PackageManagerException {
mPackageName = null;
mVersionCode = -1;
- mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+ mSignatures = null;
mResolvedBaseFile = null;
mResolvedStagedFiles.clear();
@@ -1007,8 +1009,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mPackageName = apk.packageName;
mVersionCode = apk.getLongVersionCode();
}
- if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
- mSigningDetails = apk.signingDetails;
+ if (mSignatures == null) {
+ mSignatures = apk.signatures;
+ mCertificates = apk.certificates;
}
assertApkConsistentLocked(String.valueOf(addedFile), apk);
@@ -1057,15 +1060,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mPackageName = pkgInfo.packageName;
mVersionCode = pkgInfo.getLongVersionCode();
}
- if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
- try {
- mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
- pkgInfo.applicationInfo.sourceDir,
- PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
- } catch (PackageParserException e) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Couldn't obtain signatures from base APK");
- }
+ if (mSignatures == null) {
+ mSignatures = pkgInfo.signatures;
}
}
@@ -1159,7 +1155,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
}
- if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
+ if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
tag + " signatures are inconsistent");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3df7c47e16d7..44aad4405a1b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -337,6 +337,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -5359,7 +5360,7 @@ public class PackageManagerService extends IPackageManager.Stub
|| filterAppAccessLPr(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
+ return compareSignatures(p1.mSignatures, p2.mSignatures);
}
}
@@ -8193,11 +8194,19 @@ public class PackageManagerService extends IPackageManager.Stub
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
- if ((ps.pkg != null) &&
- PackageParser.SigningDetails.UNKNOWN != ps.pkg.mSigningDetails) {
- // Optimization: reuse the existing cached signing data
+ long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ ArraySet<PublicKey> signingKs;
+ synchronized (mPackages) {
+ signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
+ }
+ if (ps.signatures.mSignatures != null
+ && ps.signatures.mSignatures.length != 0
+ && signingKs != null) {
+ // Optimization: reuse the existing cached certificates
// if the package appears to be unchanged.
- pkg.mSigningDetails = ps.pkg.mSigningDetails;
+ pkg.mSignatures = ps.signatures.mSignatures;
+ pkg.mSigningKeys = signingKs;
return;
}
@@ -8537,7 +8546,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
*/
- if (compareSignatures(ps.signatures.mSignatures, pkg.mSigningDetails.signatures)
+ if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
@@ -9509,10 +9518,9 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] expectedCertDigests = requiredCertDigests[i];
// For apps targeting O MR1 we require explicit enumeration of all certs.
final String[] libCertDigests = (targetSdk > Build.VERSION_CODES.O)
- ? PackageUtils.computeSignaturesSha256Digests(
- libPkg.mSigningDetails.signatures)
+ ? PackageUtils.computeSignaturesSha256Digests(libPkg.mSignatures)
: PackageUtils.computeSignaturesSha256Digests(
- new Signature[]{libPkg.mSigningDetails.signatures[0]});
+ new Signature[]{libPkg.mSignatures[0]});
// Take a shortcut if sizes don't match. Note that if an app doesn't
// target O we don't parse the "additional-certificate" tags similarly
@@ -9848,14 +9856,14 @@ public class PackageManagerService extends IPackageManager.Stub
if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
- pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
} else {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
} else {
- pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
String msg = "System package " + pkg.packageName
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
@@ -9865,8 +9873,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
- final boolean compatMatch = verifySignatures(signatureCheckPs,
- pkg.mSigningDetails.signatures,
+ final boolean compatMatch = verifySignatures(signatureCheckPs, pkg.mSignatures,
compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
@@ -9876,14 +9883,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
- pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
} catch (PackageManagerException e) {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw e;
}
// The signature has changed, but this package is in the system
// image... let's recover!
- pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
// However... if this package is part of a shared user, but it
// doesn't match the signature of the shared user, let's fail.
// What this means is that you can't change the signatures
@@ -9891,7 +9898,7 @@ public class PackageManagerService extends IPackageManager.Stub
// that unreasonable.
if (signatureCheckPs.sharedUser != null) {
if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures,
- pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) {
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Signature mismatch for shared user: "
@@ -13197,7 +13204,7 @@ public class PackageManagerService extends IPackageManager.Stub
void installStage(String packageName, File stagedDir,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
- PackageParser.SigningDetails signingDetails) {
+ Certificate[][] certificates) {
if (DEBUG_EPHEMERAL) {
if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + packageName);
@@ -13215,7 +13222,7 @@ public class PackageManagerService extends IPackageManager.Stub
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, signingDetails, installReason);
+ sessionParams.grantedRuntimePermissions, certificates, installReason);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -13819,7 +13826,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
if (pkg == null) {
return -1;
- } else if (pkg.mSigningDetails.signatures.length != 1) {
+ } else if (pkg.mSignatures.length != 1) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " has more than one signature; ignoring");
return -1;
@@ -13833,7 +13840,7 @@ public class PackageManagerService extends IPackageManager.Stub
final byte[] expectedPublicKey;
try {
- final Signature verifierSig = pkg.mSigningDetails.signatures[0];
+ final Signature verifierSig = pkg.mSignatures[0];
final PublicKey publicKey = verifierSig.getPublicKey();
expectedPublicKey = publicKey.getEncoded();
} catch (CertificateException e) {
@@ -14525,13 +14532,13 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final VerificationInfo verificationInfo;
- final PackageParser.SigningDetails signingDetails;
+ final Certificate[][] certificates;
final int installReason;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
+ String[] grantedPermissions, Certificate[][] certificates, int installReason) {
super(user);
this.origin = origin;
this.move = move;
@@ -14542,7 +14549,7 @@ public class PackageManagerService extends IPackageManager.Stub
this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
this.grantedRuntimePermissions = grantedPermissions;
- this.signingDetails = signingDetails;
+ this.certificates = certificates;
this.installReason = installReason;
}
@@ -14973,7 +14980,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** If non-null, drop an async trace when the install completes */
final String traceMethod;
final int traceCookie;
- final PackageParser.SigningDetails signingDetails;
+ final Certificate[][] certificates;
final int installReason;
// The list of instruction sets supported by this app. This is currently
@@ -14985,7 +14992,7 @@ public class PackageManagerService extends IPackageManager.Stub
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
- String traceMethod, int traceCookie, PackageParser.SigningDetails signingDetails,
+ String traceMethod, int traceCookie, Certificate[][] certificates,
int installReason) {
this.origin = origin;
this.move = move;
@@ -14999,7 +15006,7 @@ public class PackageManagerService extends IPackageManager.Stub
this.installGrantPermissions = installGrantPermissions;
this.traceMethod = traceMethod;
this.traceCookie = traceCookie;
- this.signingDetails = signingDetails;
+ this.certificates = certificates;
this.installReason = installReason;
}
@@ -15095,7 +15102,7 @@ public class PackageManagerService extends IPackageManager.Stub
params.installerPackageName, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.signingDetails,
+ params.traceMethod, params.traceCookie, params.certificates,
params.installReason);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
@@ -15105,7 +15112,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
- null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
+ null, null, null, 0, null /*certificates*/,
PackageManager.INSTALL_REASON_UNKNOWN);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -15326,7 +15333,7 @@ public class PackageManagerService extends IPackageManager.Stub
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.signingDetails,
+ params.traceMethod, params.traceCookie, params.certificates,
params.installReason);
}
@@ -15665,8 +15672,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
// default to original signature matching
- if (compareSignatures(oldPackage.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
+ if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package has a different signature: " + pkgName);
@@ -16478,8 +16484,14 @@ public class PackageManagerService extends IPackageManager.Stub
try {
// either use what we've been given or parse directly from the APK
- if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
- pkg.setSigningDetails(args.signingDetails);
+ if (args.certificates != null) {
+ try {
+ PackageParser.populateCertificates(pkg, args.certificates);
+ } catch (PackageParserException e) {
+ // there was something wrong with the certificates we were given;
+ // try to pull them from the APK
+ PackageParser.collectCertificates(pkg, parseFlags);
+ }
} else {
PackageParser.collectCertificates(pkg, parseFlags);
}
@@ -16598,8 +16610,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
final boolean compatMatch = verifySignatures(
- signatureCheckPs, pkg.mSigningDetails.signatures, compareCompat,
- compareRecover);
+ signatureCheckPs, pkg.mSignatures, compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
@@ -16650,7 +16661,7 @@ public class PackageManagerService extends IPackageManager.Stub
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
- pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH;
+ pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
@@ -16926,8 +16937,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (ActivityIntentInfo filter : a.intents) {
if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG,
- "Intent filter needs verification, so processing all filters");
+ Slog.d(TAG, "Intent filter needs verification, so processing all filters");
}
needToVerify = true;
break;
@@ -22235,8 +22245,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
installerPackageName, volumeUuid, null /*verificationInfo*/, user,
- packageAbiOverride, null /*grantedPermissions*/,
- PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN);
+ packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/,
+ PackageManager.INSTALL_REASON_UNKNOWN);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 37f9a74fe0ba..fbf3d82455c8 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -17,6 +17,8 @@
package com.android.server.pm;
import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.SELinuxUtil;
import android.content.pm.Signature;
import android.os.Environment;
import android.util.Slog;
@@ -451,7 +453,7 @@ final class Policy {
public String getMatchedSeInfo(PackageParser.Package pkg) {
// Check for exact signature matches across all certs.
Signature[] certs = mCerts.toArray(new Signature[0]);
- if (!Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
+ if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b5d3af1c6a28..4cf18149d853 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -955,7 +955,7 @@ public final class Settings {
}
// Update signatures if needed.
if (p.signatures.mSignatures == null) {
- p.signatures.assignSignatures(pkg.mSigningDetails.signatures);
+ p.signatures.assignSignatures(pkg.mSignatures);
}
// Update flags if needed.
if (pkg.applicationInfo.flags != p.pkgFlags) {
@@ -964,7 +964,7 @@ public final class Settings {
// If this app defines a shared user id initialize
// the shared user signatures as well.
if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
- p.sharedUser.signatures.assignSignatures(pkg.mSigningDetails.signatures);
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
}
// Update static shared library dependencies if needed
if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null
@@ -4565,8 +4565,10 @@ public final class Settings {
}
pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println();
- final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion;
- pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
+ final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
+ if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
+ pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
+ }
pw.print(prefix); pw.print(" applicationInfo=");
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 7bab318069ff..ebf6672cf57e 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -459,8 +459,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}
// Then, for the pinned set for each launcher, set the pin flag one by one.
- mShortcutUser.mService.getUserShortcutsLocked(getPackageUserId())
- .forAllLaunchers(launcherShortcuts -> {
+ mShortcutUser.forAllLaunchers(launcherShortcuts -> {
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
getPackageName(), getPackageUserId());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c3dce3133026..7d575668da94 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -63,6 +63,7 @@ import android.os.SELinux;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -79,6 +80,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.Xml;
@@ -241,8 +243,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final IBinder mUserRestriconToken = new Binder();
/**
- * User-related information that is used for persisting to flash. Only UserInfo is
- * directly exposed to other system apps.
+ * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
*/
@VisibleForTesting
static class UserData {
@@ -260,6 +261,12 @@ public class UserManagerService extends IUserManager.Stub {
// Whether to perist the seed account information to be available after a boot
boolean persistSeedData;
+ /** Elapsed realtime since boot when the user started. */
+ long startRealtime;
+
+ /** Elapsed realtime since boot when the user was unlocked. */
+ long unlockRealtime;
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -453,6 +460,37 @@ public class UserManagerService extends IUserManager.Stub {
mUms.cleanupPartialUsers();
}
}
+
+ @Override
+ public void onStartUser(int userHandle) {
+ synchronized (mUms.mUsersLock) {
+ final UserData user = mUms.getUserDataLU(userHandle);
+ if (user != null) {
+ user.startRealtime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ synchronized (mUms.mUsersLock) {
+ final UserData user = mUms.getUserDataLU(userHandle);
+ if (user != null) {
+ user.unlockRealtime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ @Override
+ public void onStopUser(int userHandle) {
+ synchronized (mUms.mUsersLock) {
+ final UserData user = mUms.getUserDataLU(userHandle);
+ if (user != null) {
+ user.startRealtime = 0;
+ user.unlockRealtime = 0;
+ }
+ }
+ }
}
// TODO b/28848102 Add support for test dependencies injection
@@ -1057,6 +1095,29 @@ public class UserManagerService extends IUserManager.Stub {
return mLocalService.isUserRunning(userId);
}
+ @Override
+ public long getUserStartRealtime() {
+ final int userId = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized (mUsersLock) {
+ final UserData user = getUserDataLU(userId);
+ if (user != null) {
+ return user.startRealtime;
+ }
+ return 0;
+ }
+ }
+
+ @Override
+ public long getUserUnlockRealtime() {
+ synchronized (mUsersLock) {
+ final UserData user = getUserDataLU(UserHandle.getUserId(Binder.getCallingUid()));
+ if (user != null) {
+ return user.unlockRealtime;
+ }
+ return 0;
+ }
+ }
+
private void checkManageOrInteractPermIfCallerInOtherProfileGroup(int userId, String name) {
int callingUserId = UserHandle.getCallingUserId();
if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) ||
@@ -3484,6 +3545,7 @@ public class UserManagerService extends IUserManager.Stub {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
long now = System.currentTimeMillis();
+ final long nowRealtime = SystemClock.elapsedRealtime();
StringBuilder sb = new StringBuilder();
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
@@ -3511,25 +3573,20 @@ public class UserManagerService extends IUserManager.Stub {
}
pw.println(UserState.stateToString(state));
pw.print(" Created: ");
- if (userInfo.creationTime == 0) {
- pw.println("<unknown>");
- } else {
- sb.setLength(0);
- TimeUtils.formatDuration(now - userInfo.creationTime, sb);
- sb.append(" ago");
- pw.println(sb);
- }
+ dumpTimeAgo(pw, sb, now, userInfo.creationTime);
+
pw.print(" Last logged in: ");
- if (userInfo.lastLoggedInTime == 0) {
- pw.println("<unknown>");
- } else {
- sb.setLength(0);
- TimeUtils.formatDuration(now - userInfo.lastLoggedInTime, sb);
- sb.append(" ago");
- pw.println(sb);
- }
+ dumpTimeAgo(pw, sb, now, userInfo.lastLoggedInTime);
+
pw.print(" Last logged in fingerprint: ");
pw.println(userInfo.lastLoggedInFingerprint);
+
+ pw.print(" Start time: ");
+ dumpTimeAgo(pw, sb, nowRealtime, userData.startRealtime);
+
+ pw.print(" Unlock time: ");
+ dumpTimeAgo(pw, sb, nowRealtime, userData.unlockRealtime);
+
pw.print(" Has profile owner: ");
pw.println(mIsUserManaged.get(userId));
pw.println(" Restrictions:");
@@ -3593,6 +3650,17 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
+ if (time == 0) {
+ pw.println("<unknown>");
+ } else {
+ sb.setLength(0);
+ TimeUtils.formatDuration(nowTime - time, sb);
+ sb.append(" ago");
+ pw.println(sb);
+ }
+ }
+
final class MainHandler extends Handler {
@Override
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 6e07eaac9c44..34c3ce359e86 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -27,6 +27,7 @@ import android.app.admin.DevicePolicyManager;
import android.companion.CompanionDeviceManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageList;
@@ -61,6 +62,8 @@ import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageSetting;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1166,8 +1169,7 @@ public final class DefaultPermissionGrantPolicy {
final String systemPackageName = mServiceInternal.getKnownPackageName(
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage = getPackage(systemPackageName);
- return compareSignatures(systemPackage.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
+ return compareSignatures(systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH;
}
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 6c8c9b20ecdb..ffc4731feadd 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -5,3 +5,4 @@ per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
per-file DefaultPermissionGrantPolicy.java = toddke@google.com
per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
+per-file DefaultPermissionGrantPolicy.java = patb@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 786b998862de..90ac4ab7dd42 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -29,6 +29,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -55,17 +56,21 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.RoSystemProperties;
import com.android.internal.util.ArrayUtils;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
+import com.android.server.pm.ProcessLoggingHandler;
import com.android.server.pm.SharedUserSetting;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
@@ -1010,10 +1015,10 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
final PackageParser.Package systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
boolean allowed = (PackageManagerServiceUtils.compareSignatures(
- bp.getSourceSignatures(), pkg.mSigningDetails.signatures)
+ bp.getSourceSignatures(), pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (PackageManagerServiceUtils.compareSignatures(
- systemPackage.mSigningDetails.signatures, pkg.mSigningDetails.signatures)
+ systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && (privilegedPermission || oemPermission)) {
if (pkg.isSystem()) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2ac758344f52..d4b437a5a25e 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -49,14 +49,17 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
import static com.android.server.wm.proto.AppTransitionProto.APP_TRANSITION_STATE;
import static com.android.server.wm.proto.AppTransitionProto.LAST_USED_APP_TRANSITION;
+import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Debug;
import android.os.IBinder;
@@ -70,7 +73,10 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
+import android.view.DisplayListCanvas;
import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -391,6 +397,11 @@ public class AppTransition implements Dump {
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
}
+
+ boolean isNextAppTransitionOpenCrossProfileApps() {
+ return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
+ }
+
/**
* @return true if and only if we are currently fetching app transition specs from the future
* passed into {@link #overridePendingAppTransitionMultiThumbFuture}
@@ -978,6 +989,43 @@ public class AppTransition implements Dump {
}
/**
+ * Creates an overlay with a background color and a thumbnail for the cross profile apps
+ * animation.
+ */
+ GraphicBuffer createCrossProfileAppsThumbnail(
+ @DrawableRes int thumbnailDrawableRes, Rect frame) {
+ final int width = frame.width();
+ final int height = frame.height();
+
+ final RenderNode node = RenderNode.create("CrossProfileAppsThumbnail", null);
+ node.setLeftTopRightBottom(0, 0, width, height);
+ node.setClipToBounds(false);
+
+ final DisplayListCanvas canvas = node.start(width, height);
+ canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
+ final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
+ final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
+ drawable.setBounds(
+ (width - thumbnailSize) / 2,
+ (height - thumbnailSize) / 2,
+ (width + thumbnailSize) / 2,
+ (height + thumbnailSize) / 2);
+ drawable.draw(canvas);
+ node.end(canvas);
+
+ return ThreadedRenderer.createHardwareBitmap(node, width, height)
+ .createGraphicBufferHandle();
+ }
+
+ Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
+ final Animation animation = loadAnimationRes(
+ "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
+ return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
+ appRect.height(), 0, null);
+ }
+
+ /**
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
* when a thumbnail is specified with the pending animation override.
*/
@@ -1624,9 +1672,10 @@ public class AppTransition implements Dump {
&& (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
|| transit == TRANSIT_TASK_TO_FRONT)) {
+
a = loadAnimationRes("android", enter
- ? com.android.internal.R.anim.activity_open_enter
- : com.android.internal.R.anim.activity_open_exit);
+ ? com.android.internal.R.anim.task_open_enter_cross_profile_apps
+ : com.android.internal.R.anim.task_open_exit);
Slog.v(TAG,
"applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
+ " anim=" + a + " transit=" + appTransitionToString(transit)
@@ -2007,6 +2056,8 @@ public class AppTransition implements Dump {
return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
+ case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
+ return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
default:
return "unknown type=" + mNextAppTransitionType;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index c16a5315060f..487b52ca02b9 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -49,7 +49,8 @@ class AppWindowThumbnail implements Animatable {
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
mAppToken = appToken;
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+ appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
mWidth = thumbnailHeader.getWidth();
mHeight = thumbnailHeader.getHeight();
@@ -84,10 +85,14 @@ class AppWindowThumbnail implements Animatable {
}
void startAnimation(Transaction t, Animation anim) {
+ startAnimation(t, anim, null /* position */);
+ }
+
+ void startAnimation(Transaction t, Animation anim, Point position) {
anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mAppToken.mService.getTransitionAnimationScaleLocked());
mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter(
- new WindowAnimationSpec(anim, null /* position */,
+ new WindowAnimationSpec(anim, position,
mAppToken.mService.mAppTransition.canSkipFirstFrame()),
mAppToken.mService.mSurfaceAnimationRunner), false /* hidden */);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 01e925e509c8..fc0564d35a3f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
@@ -31,6 +30,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
@@ -56,7 +56,6 @@ import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;
import android.annotation.CallSuper;
import android.app.Activity;
-import android.app.WindowConfiguration.WindowingMode;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
@@ -69,13 +68,14 @@ import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.view.SurfaceControl.Transaction;
-import android.view.animation.Animation;
import android.view.IApplicationToken;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.Animation;
+import com.android.internal.R;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
import com.android.server.policy.WindowManagerPolicy.StartingSurface;
@@ -1775,6 +1775,37 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader));
}
+ /**
+ * Attaches a surface with a thumbnail for the
+ * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
+ */
+ void attachCrossProfileAppsThumbnailAnimation() {
+ if (!isReallyAnimating()) {
+ return;
+ }
+ clearThumbnail();
+
+ final WindowState win = findMainWindow();
+ if (win == null) {
+ return;
+ }
+ final Rect frame = win.mFrame;
+ final int thumbnailDrawableRes = getTask().mUserId == mService.mCurrentUserId
+ ? R.drawable.ic_account_circle
+ : R.drawable.ic_corp_badge_no_background;
+ final GraphicBuffer thumbnail =
+ mService.mAppTransition
+ .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
+ if (thumbnail == null) {
+ return;
+ }
+ mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail);
+ final Animation animation =
+ mService.mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(win.mFrame);
+ mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left,
+ frame.top));
+ }
+
private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) {
final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 722486351e19..2cc2a0e70eba 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -49,7 +49,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -336,9 +335,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
new TaskForResizePointSearchResult();
private final ApplySurfaceChangesTransactionState mTmpApplySurfaceChangesTransactionState =
new ApplySurfaceChangesTransactionState();
- private final ScreenshotApplicationState mScreenshotApplicationState =
- new ScreenshotApplicationState();
- private final Transaction mTmpTransaction = new Transaction();
// True if this display is in the process of being removed. Used to determine if the removal of
// the display's direct children should be allowed.
@@ -655,10 +651,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWallpaperController.updateWallpaperVisibility();
}
- // Use mTmpTransaction instead of mPendingTransaction because we don't want to commit
- // other changes in mPendingTransaction at this point.
- w.handleWindowMovedIfNeeded(mTmpTransaction);
- SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ w.handleWindowMovedIfNeeded(mPendingTransaction);
final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -693,33 +686,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
}
- final TaskStack stack = w.getStack();
- if (!winAnimator.isWaitingForOpening()
- || (stack != null && stack.isAnimatingBounds())) {
- // Updates the shown frame before we set up the surface. This is needed
- // because the resizing could change the top-left position (in addition to
- // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
- // position the surface.
- //
- // If an animation is being started, we can't call this method because the
- // animation hasn't processed its initial transformation yet, but in general
- // we do want to update the position if the window is animating. We make an exception
- // for the bounds animating state, where an application may have been waiting
- // for an exit animation to start, but instead enters PiP. We need to ensure
- // we always recompute the top-left in this case.
- winAnimator.computeShownFrameLocked();
- }
- winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
-
- // Since setSurfaceBoundariesLocked applies the clipping, we need to apply the position
- // to the surface of the window container and also the position of the stack window
- // container as well. Use mTmpTransaction instead of mPendingTransaction to avoid
- // committing any existing changes in there.
- w.updateSurfacePosition(mTmpTransaction);
- if (stack != null) {
- stack.updateSurfaceBounds(mTmpTransaction);
- }
- SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
final AppWindowToken atoken = w.mAppToken;
@@ -2822,6 +2788,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTmpRecoveringMemory = recoveringMemory;
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
+ prepareSurfaces();
mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
mTmpApplySurfaceChangesTransactionState.displayHasContent,
@@ -3497,47 +3464,37 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
-
- final int NORMAL_STACK_STATE = 0;
- final int SPLIT_SCREEN_STACK_STATE = 1;
- final int ASSISTANT_STACK_STATE = 2;
- final int BOOSTED_STATE = 3;
- final int ALWAYS_ON_TOP_STATE = 4;
-
int layer = 0;
- for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- layer++;
- if (state == NORMAL_STACK_STATE && !s.inSplitScreenPrimaryWindowingMode() &&
- !s.isActivityTypeAssistant() &&
- !s.needsZBoost() && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer);
- } else if (state == SPLIT_SCREEN_STACK_STATE &&
- s.inSplitScreenPrimaryWindowingMode()) {
- s.assignLayer(t, layer);
- } else if (state == ASSISTANT_STACK_STATE &&
- s.isActivityTypeAssistant()) {
- s.assignLayer(t, layer);
- } else if (state == BOOSTED_STATE && s.needsZBoost()) {
- s.assignLayer(t, layer);
- } else if (state == ALWAYS_ON_TOP_STATE &&
- s.isAlwaysOnTop()) {
- s.assignLayer(t, layer);
- }
+
+ // We allow stacks to change visual order from the AM specified order due to
+ // Z-boosting during animations. However we must take care to ensure TaskStacks
+ // which are marked as alwaysOnTop remain that way.
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ s.assignChildLayers();
+ if (!s.needsZBoost() && !s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
}
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (state == BOOSTED_STATE && mAppAnimationLayer != null) {
- t.setLayer(mAppAnimationLayer, layer++);
+ }
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ if (s.needsZBoost() && !s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
}
}
for (int i = 0; i < mChildren.size(); i++) {
final TaskStack s = mChildren.get(i);
- s.assignChildLayers(t);
+ if (s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
+ }
}
+ // The appropriate place for App-Transitions to occur is right
+ // above all other animations but still below things in the Picture-and-Picture
+ // windowing mode.
+ if (mAppAnimationLayer != null) {
+ t.setLayer(mAppAnimationLayer, layer++);
+ }
}
@Override
@@ -3571,18 +3528,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
&& imeContainer.getSurfaceControl() != null;
for (int j = 0; j < mChildren.size(); ++j) {
final WindowToken wt = mChildren.get(j);
-
- // The divider is unique in that it does not have an AppWindowToken but needs to be
- // interleaved with them. In particular it must be above any split-screen stacks
- // but below any always-on-top stacks.
- if (wt.windowType == TYPE_DOCK_DIVIDER) {
- final TaskStack dockedStack = getSplitScreenPrimaryStack();
- if (dockedStack != null) {
- wt.assignRelativeLayer(t, dockedStack.getSurfaceControl(),
- Integer.MAX_VALUE);
- continue;
- }
- }
wt.assignLayer(t, j);
wt.assignChildLayers(t);
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index a32e711df534..e67cdbaac35b 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -30,6 +30,7 @@ import android.view.SurfaceControl.Transaction;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -55,16 +56,20 @@ class SurfaceAnimator {
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
+ * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
+ * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, Runnable animationFinishedCallback,
- WindowManagerService service) {
+ Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
+ addAfterPrepareSurfaces);
}
- private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback) {
+ private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback,
+ Consumer<Runnable> addAfterPrepareSurfaces) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -80,7 +85,7 @@ class SurfaceAnimator {
// reparents the surface onto the leash is executed already. Otherwise this may be
// executed first, leading to surface loss, as the reparent operations wouldn't
// be in order.
- mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+ addAfterPrepareSurfaces.accept(() -> {
if (anim != mAnimation) {
// Callback was from another animation - ignore.
return;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index bdda944f236b..7b4281c61f12 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -44,6 +44,7 @@ import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.RemoteException;
@@ -145,6 +146,7 @@ public class TaskStack extends WindowContainer<Task> implements
* For {@link #prepareSurfaces}.
*/
final Rect mTmpDimBoundsRect = new Rect();
+ private final Point mLastSurfaceSize = new Point();
TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
super(service);
@@ -744,7 +746,13 @@ public class TaskStack extends WindowContainer<Task> implements
}
final Rect stackBounds = getBounds();
- transaction.setSize(mSurfaceControl, stackBounds.width(), stackBounds.height());
+ final int width = stackBounds.width();
+ final int height = stackBounds.height();
+ if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
+ return;
+ }
+ transaction.setSize(mSurfaceControl, width, height);
+ mLastSurfaceSize.set(width, height);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 729587375421..3efd6ac0afef 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -47,7 +47,6 @@ public class WindowAnimator {
final WindowManagerService mService;
final Context mContext;
final WindowManagerPolicy mPolicy;
- private final WindowSurfacePlacer mWindowPlacerLocked;
/** Is any window animating? */
private boolean mAnimating;
@@ -74,7 +73,7 @@ public class WindowAnimator {
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
- boolean mInitialized = false;
+ private boolean mInitialized = false;
// When set to true the animator will go over all windows after an animation frame is posted and
// check if some got replaced and can be removed.
@@ -98,7 +97,6 @@ public class WindowAnimator {
mService = service;
mContext = service.mContext;
mPolicy = service.mPolicy;
- mWindowPlacerLocked = service.mWindowPlacerLocked;
AnimationThread.getHandler().runWithScissors(
() -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
@@ -241,7 +239,7 @@ public class WindowAnimator {
}
if (hasPendingLayoutChanges || doRequest) {
- mWindowPlacerLocked.requestTraversal();
+ mService.mWindowPlacerLocked.requestTraversal();
}
final boolean rootAnimating = mService.mRoot.isSelfOrChildAnimating();
@@ -254,7 +252,7 @@ public class WindowAnimator {
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
}
if (!rootAnimating && mLastRootAnimating) {
- mWindowPlacerLocked.requestTraversal();
+ mService.mWindowPlacerLocked.requestTraversal();
mService.mTaskSnapshotController.setPersisterPaused(false);
Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5d445eff0c92..36e6418a39b5 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -95,6 +95,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
protected final WindowManagerService mService;
private final Point mTmpPos = new Point();
+ protected final Point mLastSurfacePosition = new Point();
/** Total number of elements in this subtree, including our own hierarchy element. */
private int mTreeWeight = 1;
@@ -102,7 +103,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+ service.mAnimator::addAfterPrepareSurfacesRunnable, service);
}
@Override
@@ -1177,7 +1179,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
getRelativePosition(mTmpPos);
+ if (mTmpPos.equals(mLastSurfacePosition)) {
+ return;
+ }
+
transaction.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
+ mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).updateSurfacePosition(transaction);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a2ffbc96fe5..e91b16d013c6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -928,7 +928,6 @@ public class WindowManagerService extends IWindowManager.Stub
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
installLock(this, INDEX_WINDOW);
- mRoot = new RootWindowContainer(this);
mContext = context;
mHaveInputMethods = haveInputMethods;
mAllowBootMessages = showBootMsgs;
@@ -952,8 +951,11 @@ public class WindowManagerService extends IWindowManager.Stub
mDisplaySettings = new DisplaySettings();
mDisplaySettings.readSettingsLocked();
- mWindowPlacerLocked = new WindowSurfacePlacer(this);
mPolicy = policy;
+ mAnimator = new WindowAnimator(this);
+ mRoot = new RootWindowContainer(this);
+
+ mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
mWindowTracing = WindowTracing.createDefaultAndStartLooper(context);
@@ -1051,7 +1053,6 @@ public class WindowManagerService extends IWindowManager.Stub
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
mHoldingScreenWakeLock.setReferenceCounted(false);
- mAnimator = new WindowAnimator(this);
mSurfaceAnimationRunner = new SurfaceAnimationRunner();
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b3809dd8f6c9..0ad60c93bb46 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4487,6 +4487,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Leash is now responsible for position, so set our position to 0.
t.setPosition(mSurfaceControl, 0, 0);
+ mLastSurfacePosition.set(0, 0);
}
@Override
@@ -4502,8 +4503,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
- if (!mSurfaceAnimator.hasLeash()) {
+ if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 08f49f689323..a512fdf828b3 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
+
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
@@ -43,28 +44,19 @@ import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
-import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Binder;
import android.os.Debug;
import android.os.Trace;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseIntArray;
import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
@@ -414,7 +406,6 @@ class WindowSurfacePlacer {
}
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
-
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
mService.openSurfaceTransaction();
@@ -435,6 +426,8 @@ class WindowSurfacePlacer {
}
if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
wtoken.attachThumbnailAnimation();
+ } else if (mService.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
+ wtoken.attachCrossProfileAppsThumbnailAnimation();
}
}
return topOpeningApp;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 11fce4d7101c..f0681e9eb32e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7190,13 +7190,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
- final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- if (!isUserAffiliatedWithDeviceLocked(userId)) {
- throw new SecurityException("Admin " + who +
- " is neither the device owner or affiliated user's profile owner.");
- }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
long token = mInjector.binderClearCallingIdentity();
try {
mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
@@ -9663,6 +9658,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
" is neither the device owner or affiliated user's profile owner.");
}
}
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable keyguard");
+ }
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -9689,6 +9687,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException("Admin " + who +
" is neither the device owner or affiliated user's profile owner.");
}
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable status bar");
+ }
DevicePolicyData policy = getUserData(userId);
if (policy.mStatusBarDisabled != disabled) {
boolean isLockTaskMode = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 49601c32cdc2..32b0b266bafc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -34,6 +34,7 @@ import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
+import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -261,13 +262,14 @@ public class PackageParserTest {
assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
assertEquals(a.mVersionName, b.mVersionName);
assertEquals(a.mSharedUserId, b.mSharedUserId);
- assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures));
+ assertTrue(Arrays.equals(a.mSignatures, b.mSignatures));
+ assertTrue(Arrays.equals(a.mCertificates, b.mCertificates));
assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
assertEquals(a.mExtras, b.mExtras);
assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
assertEquals(a.mOverlayTarget, b.mOverlayTarget);
- assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
+ assertEquals(a.mSigningKeys, b.mSigningKeys);
assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
assertEquals(a.mKeySetMapping, b.mKeySetMapping);
assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
@@ -493,16 +495,14 @@ public class PackageParserTest {
pkg.mAppMetaData = new Bundle();
pkg.mVersionName = "foo17";
pkg.mSharedUserId = "foo18";
- pkg.mSigningDetails =
- new PackageParser.SigningDetails(
- new Signature[] { new Signature(new byte[16]) },
- 2,
- new ArraySet<>());
+ pkg.mSignatures = new Signature[] { new Signature(new byte[16]) };
+ pkg.mCertificates = new Certificate[][] { new Certificate[] { null }};
pkg.mExtras = new Bundle();
pkg.mRestrictedAccountType = "foo19";
pkg.mRequiredAccountType = "foo20";
pkg.mOverlayTarget = "foo21";
pkg.mOverlayPriority = 100;
+ pkg.mSigningKeys = new ArraySet<>();
pkg.mUpgradeKeySets = new ArraySet<>();
pkg.mKeySetMapping = new ArrayMap<>();
pkg.cpuAbiOverride = "foo22";
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 4831fcd67314..b36c7d91c807 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -34,8 +34,10 @@ import android.animation.ValueAnimator;
import android.graphics.Matrix;
import android.graphics.Point;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
import android.view.Choreographer;
import android.view.Choreographer.FrameCallback;
import android.view.SurfaceControl;
@@ -135,6 +137,7 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
assertFinishCallbackNotCalled();
}
+ @FlakyTest(bugId = 71719744)
@Test
public void testCancel_sneakyCancelBeforeUpdate() throws Exception {
mSurfaceAnimationRunner = new SurfaceAnimationRunner(null, () -> new ValueAnimator() {
@@ -157,8 +160,12 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
when(mMockAnimationSpec.getDuration()).thenReturn(200L);
mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
this::finishedCallback);
+
+ // We need to wait for two frames: The first frame starts the animation, the second frame
+ // actually cancels the animation.
waitUntilNextFrame();
- assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+ waitUntilNextFrame();
+ assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 463ceeb9f2a2..64c303700639 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -75,10 +75,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
mAnimatable2 = new MyAnimatable();
}
- // TODO: Tests are flaky, and timeout after 5 minutes. Instead of wasting everybody's time we
- // mark them as ignore.
@Test
- @Ignore
public void testRunAnimation() throws Exception {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -88,17 +85,13 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec);
- waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
- // TODO: Tests are flaky, and timeout after 5 minutes. Instead of wasting everybody's time we
- // mark them as ignore.
@Test
- @Ignore
public void testOverrideAnimation() throws Exception {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final SurfaceControl firstLeash = mAnimatable.mLeash;
@@ -114,13 +107,11 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
// First animation was finished, but this shouldn't cancel the second animation
callbackCaptor.getValue().onAnimationFinished(mSpec);
- waitUntilPrepareSurfaces();
assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
// Second animation was finished
verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec2);
- waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
}
@@ -157,10 +148,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
}
- // TODO: Tests are flaky, and timeout after 5 minutes. Instead of wasting everybody's time we
- // mark them as ignore.
@Test
- @Ignore
public void testTransferAnimation() throws Exception {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
@@ -175,7 +163,6 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
- waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
@@ -191,14 +178,6 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertNull(animatable.mSurfaceAnimator.getAnimation());
}
- private void waitUntilPrepareSurfaces() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- synchronized (sWm.mWindowMap) {
- sWm.mAnimator.addAfterPrepareSurfacesRunnable(latch::countDown);
- }
- latch.await();
- }
-
private class MyAnimatable implements Animatable {
final SurfaceControl mParent;
@@ -219,7 +198,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index ff840f3aeea9..c699a94db279 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -103,7 +103,6 @@ class WindowTestsBase {
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
- sWm.mAnimator.mInitialized = true;
sWm.mDisplayEnabled = true;
sWm.mDisplayReady = true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index bcc9a1cbab7d..6468763440a5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -21,12 +21,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -76,11 +74,11 @@ public class ZOrderingTests extends WindowTestsBase {
return super.setRelativeLayer(sc, relativeTo, layer);
}
- private int getLayer(SurfaceControl sc) {
+ int getLayer(SurfaceControl sc) {
return mLayersForControl.getOrDefault(sc, 0);
}
- private SurfaceControl getRelativeLayer(SurfaceControl sc) {
+ SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
};
@@ -148,9 +146,8 @@ public class ZOrderingTests extends WindowTestsBase {
return p;
}
-
- void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
- SurfaceControl right) throws Exception {
+ void assertZOrderGreaterThan(LayerRecordingTransaction t,
+ SurfaceControl left, SurfaceControl right) throws Exception {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
@@ -174,12 +171,9 @@ public class ZOrderingTests extends WindowTestsBase {
}
}
- void assertWindowHigher(WindowState left, WindowState right) throws Exception {
- assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
- }
-
- WindowState createWindow(String name) {
- return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
+ void assertWindowLayerGreaterThan(LayerRecordingTransaction t,
+ WindowState left, WindowState right) throws Exception {
+ assertZOrderGreaterThan(t, left.getSurfaceControl(), right.getSurfaceControl());
}
@Test
@@ -190,37 +184,38 @@ public class ZOrderingTests extends WindowTestsBase {
// The Ime has an higher base layer than app windows and lower base layer than system
// windows, so it should be above app windows and below system windows if there isn't an IME
// target.
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mNavBarWindow, mImeWindow);
- assertWindowHigher(mStatusBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
- final WindowState imeAppTarget = createWindow("imeAppTarget");
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
sWm.mInputMethodTarget = imeAppTarget;
-
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows and below system windows if it is targeting an app
// window.
- assertWindowHigher(mImeWindow, imeAppTarget);
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mNavBarWindow, mImeWindow);
- assertWindowHigher(mStatusBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
- final WindowState imeAppTarget = createWindow("imeAppTarget");
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
"imeAppTargetChildAboveWindow");
@@ -233,38 +228,41 @@ public class ZOrderingTests extends WindowTestsBase {
// Ime should be above all app windows except for child windows that are z-ordered above it
// and below system windows if it is targeting an app window.
- assertWindowHigher(mImeWindow, imeAppTarget);
- assertWindowHigher(imeAppTargetChildAboveWindow, mImeWindow);
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mNavBarWindow, mImeWindow);
- assertWindowHigher(mStatusBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+ assertWindowLayerGreaterThan(mTransaction, imeAppTargetChildAboveWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
- final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
- final WindowState imeAppTarget = createWindow("imeAppTarget");
- final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
+ final WindowState appBelowImeTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appBelowImeTarget");
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+ final WindowState appAboveImeTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appAboveImeTarget");
sWm.mInputMethodTarget = imeAppTarget;
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows except for non-fullscreen app window above it and
// below system windows if it is targeting an app window.
- assertWindowHigher(mImeWindow, imeAppTarget);
- assertWindowHigher(mImeWindow, appBelowImeTarget);
- assertWindowHigher(appAboveImeTarget, mImeWindow);
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mNavBarWindow, mImeWindow);
- assertWindowHigher(mStatusBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, appBelowImeTarget);
+ assertWindowLayerGreaterThan(mTransaction, appAboveImeTarget, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
@@ -278,20 +276,20 @@ public class ZOrderingTests extends WindowTestsBase {
// The IME target base layer is higher than all window except for the nav bar window, so the
// IME should be above all windows except for the nav bar.
- assertWindowHigher(mImeWindow, imeSystemOverlayTarget);
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mImeWindow, mDockedDividerWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeSystemOverlayTarget);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
// The IME has a higher base layer than the status bar so we may expect it to go
// above the status bar once they are both in the Non-App layer, as past versions of this
// test enforced. However this seems like the wrong behavior unless the status bar is the
// IME target.
- assertWindowHigher(mNavBarWindow, mImeWindow);
- assertWindowHigher(mStatusBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
@@ -299,18 +297,17 @@ public class ZOrderingTests extends WindowTestsBase {
sWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowHigher(mImeWindow, mChildAppWindowAbove);
- assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mImeWindow, mDockedDividerWindow);
- assertWindowHigher(mImeWindow, mStatusBarWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeWindow, mStatusBarWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowHigher(mImeDialogWindow, mImeWindow);
+ assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
}
@Test
public void testStackLayers() throws Exception {
- final WindowState anyWindow1 = createWindow("anyWindow");
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
@@ -320,17 +317,12 @@ public class ZOrderingTests extends WindowTestsBase {
final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
- final WindowState anyWindow2 = createWindow("anyWindow2");
mDisplayContent.assignChildLayers(mTransaction);
- // We compare the split-screen windowing mode to two different normal windowing
- // mode windows added before and after it to ensure the correct Z ordering irrespective
- // of ordering in the child list.
- assertWindowHigher(dockedStackWindow, anyWindow1);
- assertWindowHigher(dockedStackWindow, anyWindow2);
- assertWindowHigher(assistantStackWindow, dockedStackWindow);
- assertWindowHigher(pinnedStackWindow, assistantStackWindow);
+ assertWindowLayerGreaterThan(mTransaction, dockedStackWindow, mAppWindow);
+ assertWindowLayerGreaterThan(mTransaction, assistantStackWindow, dockedStackWindow);
+ assertWindowLayerGreaterThan(mTransaction, pinnedStackWindow, assistantStackWindow);
}
@Test
@@ -345,9 +337,9 @@ public class ZOrderingTests extends WindowTestsBase {
// Ime should be above all app windows and below system windows if it is targeting an app
// window.
- assertWindowHigher(navBarPanel, mNavBarWindow);
- assertWindowHigher(statusBarPanel, mStatusBarWindow);
- assertWindowHigher(statusBarSubPanel, statusBarPanel);
+ assertWindowLayerGreaterThan(mTransaction, navBarPanel, mNavBarWindow);
+ assertWindowLayerGreaterThan(mTransaction, statusBarPanel, mStatusBarWindow);
+ assertWindowLayerGreaterThan(mTransaction, statusBarSubPanel, statusBarPanel);
}
@Test
@@ -355,7 +347,8 @@ public class ZOrderingTests extends WindowTestsBase {
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side.
- final WindowState anyWindow = createWindow("anyWindow");
+ final WindowState anyWindow =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "anyWindow");
final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
"TypeApplicationMediaChild");
final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
@@ -363,32 +356,7 @@ public class ZOrderingTests extends WindowTestsBase {
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowHigher(anyWindow, mediaOverlayChild);
- assertWindowHigher(mediaOverlayChild, child);
- }
-
- @Test
- public void testDockedDividerPosition() throws Exception {
- final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
- ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
- "pinnedStackWindow");
- final WindowState splitScreenWindow = createWindowOnStack(null,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
- mDisplayContent, "splitScreenWindow");
- final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
- TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
- final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
- mDisplayContent, "assistantStackWindow");
- final WindowState dockedDividerWindow = createWindow(null, TYPE_DOCK_DIVIDER,
- mDisplayContent, "dockedDivider");
-
- mDisplayContent.assignChildLayers(mTransaction);
-
- assertWindowHigher(dockedDividerWindow, splitScreenWindow);
- assertWindowHigher(dockedDividerWindow, splitScreenSecondaryWindow);
- assertWindowHigher(assistantStackWindow, dockedDividerWindow);
- assertWindowHigher(pinnedStackWindow, dockedDividerWindow);
+ assertWindowLayerGreaterThan(mTransaction, anyWindow, mediaOverlayChild);
+ assertWindowLayerGreaterThan(mTransaction, mediaOverlayChild, child);
}
}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 3361b5b6e777..83ca4702287d 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -340,24 +340,6 @@ public class Log {
return sSessionManager;
}
- private static MessageDigest sMessageDigest;
-
- public static void initMd5Sum() {
- new AsyncTask<Void, Void, Void>() {
- @Override
- public Void doInBackground(Void... args) {
- MessageDigest md;
- try {
- md = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- md = null;
- }
- sMessageDigest = md;
- return null;
- }
- }.execute();
- }
-
public static void setTag(String tag) {
TAG = tag;
DEBUG = isLoggable(android.util.Log.DEBUG);
@@ -425,44 +407,13 @@ public class Log {
/**
* Redact personally identifiable information for production users.
* If we are running in verbose mode, return the original string,
- * and return "****" if we are running on the user build, otherwise
- * return a SHA-1 hash of the input string.
+ * and return "***" otherwise.
*/
public static String pii(Object pii) {
if (pii == null || VERBOSE) {
return String.valueOf(pii);
}
- return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
- }
-
- private static String secureHash(byte[] input) {
- // Refrain from logging user personal information in user build.
- if (USER_BUILD) {
- return "****";
- }
-
- if (sMessageDigest != null) {
- sMessageDigest.reset();
- sMessageDigest.update(input);
- byte[] result = sMessageDigest.digest();
- return encodeHex(result);
- } else {
- return "Uninitialized SHA1";
- }
- }
-
- private static String encodeHex(byte[] bytes) {
- StringBuffer hex = new StringBuffer(bytes.length * 2);
-
- for (int i = 0; i < bytes.length; i++) {
- int byteIntValue = bytes[i] & 0xff;
- if (byteIntValue < 0x10) {
- hex.append("0");
- }
- hex.append(Integer.toString(byteIntValue, 16));
- }
-
- return hex.toString();
+ return "***";
}
private static String getPrefixFromObject(Object obj) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 15355ac745a4..2d1fe50e11d9 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -653,7 +653,6 @@ public class TelecomManager {
mContext = context;
}
mTelecomServiceOverride = telecomServiceImpl;
- android.telecom.Log.initMd5Sum();
}
/**
diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 5f5dd82eed61..fc814be1b464 100644
--- a/telephony/java/android/telephony/RadioNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -17,23 +17,23 @@
package android.telephony;
/**
- * Contains radio access network related constants.
+ * Contains access network related constants.
*/
-public final class RadioNetworkConstants {
+public final class AccessNetworkConstants {
- public static final class RadioAccessNetworks {
+ public static final class AccessNetworkType {
public static final int GERAN = 1;
public static final int UTRAN = 2;
public static final int EUTRAN = 3;
- /** @hide */
public static final int CDMA2000 = 4;
+ public static final int IWLAN = 5;
}
/**
* Frenquency bands for GERAN.
* http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
*/
- public static final class GeranBands {
+ public static final class GeranBand {
public static final int BAND_T380 = 1;
public static final int BAND_T410 = 2;
public static final int BAND_450 = 3;
@@ -54,7 +54,7 @@ public final class RadioNetworkConstants {
* Frenquency bands for UTRAN.
* http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
*/
- public static final class UtranBands {
+ public static final class UtranBand {
public static final int BAND_1 = 1;
public static final int BAND_2 = 2;
public static final int BAND_3 = 3;
@@ -83,7 +83,7 @@ public final class RadioNetworkConstants {
* Frenquency bands for EUTRAN.
* http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
*/
- public static final class EutranBands {
+ public static final class EutranBand {
public static final int BAND_1 = 1;
public static final int BAND_2 = 2;
public static final int BAND_3 = 3;
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java
index 5412c6172ba3..85a4ed8e465e 100644
--- a/telephony/java/android/telephony/RadioAccessSpecifier.java
+++ b/telephony/java/android/telephony/RadioAccessSpecifier.java
@@ -33,7 +33,7 @@ public final class RadioAccessSpecifier implements Parcelable {
*
* This parameter must be provided or else the scan will be rejected.
*
- * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+ * See {@link AccessNetworkConstants.AccessNetworkType} for details.
*/
private int mRadioAccessNetwork;
@@ -43,7 +43,7 @@ public final class RadioAccessSpecifier implements Parcelable {
* When no specific bands are specified (empty array or null), all the frequency bands
* supported by the modem will be scanned.
*
- * See {@link RadioNetworkConstants} for details.
+ * See {@link AccessNetworkConstants} for details.
*/
private int[] mBands;
@@ -56,7 +56,7 @@ public final class RadioAccessSpecifier implements Parcelable {
* When no specific channels are specified (empty array or null), all the frequency channels
* supported by the modem will be scanned.
*
- * See {@link RadioNetworkConstants} for details.
+ * See {@link AccessNetworkConstants} for details.
*/
private int[] mChannels;
@@ -79,7 +79,7 @@ public final class RadioAccessSpecifier implements Parcelable {
/**
* Returns the radio access network that needs to be scanned.
*
- * The returned value is define in {@link RadioNetworkConstants.RadioAccessNetworks};
+ * The returned value is define in {@link AccessNetworkConstants.AccessNetworkType};
*/
public int getRadioAccessNetwork() {
return mRadioAccessNetwork;
@@ -88,8 +88,8 @@ public final class RadioAccessSpecifier implements Parcelable {
/**
* Returns the frequency bands that need to be scanned.
*
- * The returned value is defined in either of {@link RadioNetworkConstants.GeranBands},
- * {@link RadioNetworkConstants.UtranBands} and {@link RadioNetworkConstants.EutranBands}, and
+ * The returned value is defined in either of {@link AccessNetworkConstants.GeranBand},
+ * {@link AccessNetworkConstants.UtranBand} and {@link AccessNetworkConstants.EutranBand}, and
* it depends on the returned value of {@link #getRadioAccessNetwork()}.
*/
public int[] getBands() {
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 80e42a33b3cc..2282c1319a9a 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -348,64 +348,6 @@ public class IpSecServiceParameterizedTest {
}
@Test
- public void testCreateInvalidConfigAeadWithAuth() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
-
- for (int direction : DIRECTIONS) {
- ipSecConfig.setAuthentication(direction, AUTH_ALGO);
- ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
- }
-
- try {
- mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
- fail(
- "IpSecService should have thrown an error on authentication being"
- + " enabled with authenticated encryption");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testCreateInvalidConfigAeadWithCrypt() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
-
- for (int direction : DIRECTIONS) {
- ipSecConfig.setEncryption(direction, CRYPT_ALGO);
- ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
- }
-
- try {
- mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
- fail(
- "IpSecService should have thrown an error on encryption being"
- + " enabled with authenticated encryption");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testCreateInvalidConfigAeadWithAuthAndCrypt() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
-
- for (int direction : DIRECTIONS) {
- ipSecConfig.setAuthentication(direction, AUTH_ALGO);
- ipSecConfig.setEncryption(direction, CRYPT_ALGO);
- ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
- }
-
- try {
- mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
- fail(
- "IpSecService should have thrown an error on authentication and encryption being"
- + " enabled with authenticated encryption");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
public void testDeleteTransportModeTransform() throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 5d1e10eab572..0467989d8984 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -35,6 +35,8 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.INetd;
+import android.net.IpSecAlgorithm;
+import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecTransform;
@@ -76,6 +78,36 @@ public class IpSecServiceTest {
private static final InetAddress INADDR_ANY;
+ private static final byte[] AEAD_KEY = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x73, 0x61, 0x6C, 0x74
+ };
+ private static final byte[] CRYPT_KEY = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ private static final byte[] AUTH_KEY = {
+ 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
+ 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
+ };
+
+ private static final IpSecAlgorithm AUTH_ALGO =
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
+ private static final IpSecAlgorithm CRYPT_ALGO =
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
+ private static final IpSecAlgorithm AEAD_ALGO =
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
+
+ private static final int[] DIRECTIONS =
+ new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
+
static {
try {
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -270,6 +302,127 @@ public class IpSecServiceTest {
}
@Test
+ public void testValidateAlgorithmsAuth() {
+ for (int direction : DIRECTIONS) {
+ // Validate that correct algorithm type succeeds
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthentication(direction, AUTH_ALGO);
+ mIpSecService.validateAlgorithms(config, direction);
+
+ // Validate that incorrect algorithm types fails
+ for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
+ try {
+ config = new IpSecConfig();
+ config.setAuthentication(direction, algo);
+ mIpSecService.validateAlgorithms(config, direction);
+ fail("Did not throw exception on invalid algorithm type");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsCrypt() {
+ for (int direction : DIRECTIONS) {
+ // Validate that correct algorithm type succeeds
+ IpSecConfig config = new IpSecConfig();
+ config.setEncryption(direction, CRYPT_ALGO);
+ mIpSecService.validateAlgorithms(config, direction);
+
+ // Validate that incorrect algorithm types fails
+ for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
+ try {
+ config = new IpSecConfig();
+ config.setEncryption(direction, algo);
+ mIpSecService.validateAlgorithms(config, direction);
+ fail("Did not throw exception on invalid algorithm type");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsAead() {
+ for (int direction : DIRECTIONS) {
+ // Validate that correct algorithm type succeeds
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthenticatedEncryption(direction, AEAD_ALGO);
+ mIpSecService.validateAlgorithms(config, direction);
+
+ // Validate that incorrect algorithm types fails
+ for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
+ try {
+ config = new IpSecConfig();
+ config.setAuthenticatedEncryption(direction, algo);
+ mIpSecService.validateAlgorithms(config, direction);
+ fail("Did not throw exception on invalid algorithm type");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsAuthCrypt() {
+ for (int direction : DIRECTIONS) {
+ // Validate that correct algorithm type succeeds
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthentication(direction, AUTH_ALGO);
+ config.setEncryption(direction, CRYPT_ALGO);
+ mIpSecService.validateAlgorithms(config, direction);
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsNoAlgorithms() {
+ IpSecConfig config = new IpSecConfig();
+ try {
+ mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
+ fail("Expected exception; no algorithms specified");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsAeadWithAuth() {
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
+ config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO);
+ try {
+ mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
+ fail("Expected exception; both AEAD and auth algorithm specified");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsAeadWithCrypt() {
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
+ config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO);
+ try {
+ mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
+ fail("Expected exception; both AEAD and crypt algorithm specified");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
+ IpSecConfig config = new IpSecConfig();
+ config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
+ config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO);
+ config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO);
+ try {
+ mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
+ fail("Expected exception; AEAD, auth and crypt algorithm specified");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
public void testDeleteInvalidTransportModeTransform() throws Exception {
try {
mIpSecService.deleteTransportModeTransform(1);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 3700bdbd8329..3b9121132f0b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1615,53 +1615,6 @@ public class WifiManager {
}
/**
- * startLocationRestrictedScan()
- * Trigger a scan which will not make use of DFS channels and is thus not suitable for
- * establishing wifi connection.
- * @deprecated This API is nolonger supported.
- * Use {@link android.net.wifi.WifiScanner} API
- * @hide
- * @removed
- */
- @Deprecated
- @SystemApi
- @SuppressLint("Doclava125")
- public boolean startLocationRestrictedScan(WorkSource workSource) {
- return false;
- }
-
- /**
- * Check if the Batched Scan feature is supported.
- *
- * @return false if not supported.
- * @deprecated This API is nolonger supported.
- * Use {@link android.net.wifi.WifiScanner} API
- * @hide
- * @removed
- */
- @Deprecated
- @SystemApi
- @SuppressLint("Doclava125")
- public boolean isBatchedScanSupported() {
- return false;
- }
-
- /**
- * Retrieve the latest batched scan result. This should be called immediately after
- * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
- * @deprecated This API is nolonger supported.
- * Use {@link android.net.wifi.WifiScanner} API
- * @hide
- * @removed
- */
- @Deprecated
- @SystemApi
- @SuppressLint("Doclava125")
- public List<BatchedScanResult> getBatchedScanResults() {
- return null;
- }
-
- /**
* Creates a configuration token describing the current network of MIME type
* application/vnd.wfa.wsc. Can be used to configure WiFi networks via NFC.
*
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index b4e3097a56a7..32f21b9cbc79 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -17,6 +17,7 @@
package android.net.wifi.rtt;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.aware.AttachCallback;
@@ -41,8 +42,6 @@ import java.util.StringJoiner;
* The ranging request is a batch request - specifying a set of devices (specified using
* {@link RangingRequest.Builder#addAccessPoint(ScanResult)} and
* {@link RangingRequest.Builder#addAccessPoints(List)}).
- *
- * @hide RTT_API
*/
public final class RangingRequest implements Parcelable {
private static final int MAX_PEERS = 10;
@@ -198,7 +197,7 @@ public final class RangingRequest implements Parcelable {
return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle));
}
- /*
+ /**
* Add the Responder device specified by the {@link ResponderConfig} to the list of devices
* with which to measure range. The total number of peers added to the request cannot exceed
* the limit specified by {@link #getMaxPeers()}.
@@ -206,8 +205,9 @@ public final class RangingRequest implements Parcelable {
* @param responder Information on the RTT Responder.
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
*
- * @hide (SystemApi)
+ * @hide
*/
+ @SystemApi
public Builder addResponder(@NonNull ResponderConfig responder) {
if (responder == null) {
throw new IllegalArgumentException("Null Responder!");
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index a380fae7141a..d5ca8f7f9fb0 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -18,6 +18,7 @@ package android.net.wifi.rtt;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.net.MacAddress;
import android.net.wifi.aware.PeerHandle;
import android.os.Handler;
@@ -36,8 +37,6 @@ import java.util.Objects;
* <p>
* A ranging result is the distance measurement result for a single device specified in the
* {@link RangingRequest}.
- *
- * @hide RTT_API
*/
public final class RangingResult implements Parcelable {
private static final String TAG = "RangingResult";
@@ -108,6 +107,7 @@ public final class RangingResult implements Parcelable {
* Will return a {@code null} for results corresponding to requests issued using a {@code
* PeerHandle}, i.e. using the {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)} API.
*/
+ @Nullable
public MacAddress getMacAddress() {
return mMac;
}
@@ -119,7 +119,7 @@ public final class RangingResult implements Parcelable {
* <p>
* Will return a {@code null} for results corresponding to requests issued using a MAC address.
*/
- public PeerHandle getPeerHandle() {
+ @Nullable public PeerHandle getPeerHandle() {
return mPeerHandle;
}
@@ -182,13 +182,11 @@ public final class RangingResult implements Parcelable {
return mTimestamp;
}
- /** @hide */
@Override
public int describeContents() {
return 0;
}
- /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mStatus);
@@ -210,7 +208,6 @@ public final class RangingResult implements Parcelable {
dest.writeLong(mTimestamp);
}
- /** @hide */
public static final Creator<RangingResult> CREATOR = new Creator<RangingResult>() {
@Override
public RangingResult[] newArray(int size) {
diff --git a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
index c8aea3c4aa62..9639dc803a7d 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
@@ -17,6 +17,7 @@
package android.net.wifi.rtt;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Handler;
import java.lang.annotation.Retention;
@@ -31,8 +32,6 @@ import java.util.List;
* peers then the {@link #onRangingResults(List)} will be called with the set of results (@link
* {@link RangingResult}, each of which has its own success/failure code
* {@link RangingResult#getStatus()}.
- *
- * @hide RTT_API
*/
public abstract class RangingResultCallback {
/** @hide */
@@ -68,5 +67,5 @@ public abstract class RangingResultCallback {
*
* @param results List of range measurements, one per requested device.
*/
- public abstract void onRangingResults(List<RangingResult> results);
+ public abstract void onRangingResults(@NonNull List<RangingResult> results);
}
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
index c3e10074c56c..fb723c594e15 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderConfig.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
@@ -18,6 +18,7 @@ package android.net.wifi.rtt;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.aware.PeerHandle;
@@ -35,8 +36,9 @@ import java.util.Objects;
* A Responder configuration may be constructed from a {@link ScanResult} or manually (with the
* data obtained out-of-band from a peer).
*
- * @hide (@SystemApi)
+ * @hide
*/
+@SystemApi
public final class ResponderConfig implements Parcelable {
private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437;
@@ -290,7 +292,7 @@ public final class ResponderConfig implements Parcelable {
MacAddress macAddress = MacAddress.fromString(scanResult.BSSID);
int responderType = RESPONDER_AP;
boolean supports80211mc = scanResult.is80211mcResponder();
- int channelWidth = translcateScanResultChannelWidth(scanResult.channelWidth);
+ int channelWidth = translateScanResultChannelWidth(scanResult.channelWidth);
int frequency = scanResult.frequency;
int centerFreq0 = scanResult.centerFreq0;
int centerFreq1 = scanResult.centerFreq1;
@@ -454,7 +456,7 @@ public final class ResponderConfig implements Parcelable {
}
/** @hide */
- static int translcateScanResultChannelWidth(int scanResultChannelWidth) {
+ static int translateScanResultChannelWidth(int scanResultChannelWidth) {
switch (scanResultChannelWidth) {
case ScanResult.CHANNEL_WIDTH_20MHZ:
return CHANNEL_WIDTH_20MHZ;
@@ -468,7 +470,7 @@ public final class ResponderConfig implements Parcelable {
return CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
default:
throw new IllegalArgumentException(
- "translcateScanResultChannelWidth: bad " + scanResultChannelWidth);
+ "translateScanResultChannelWidth: bad " + scanResultChannelWidth);
}
}
}
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 240b3c1e3b51..ec6c46ec4a7d 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.wifi.rtt;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
@@ -5,6 +21,7 @@ import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static android.Manifest.permission.CHANGE_WIFI_STATE;
import static android.Manifest.permission.LOCATION_HARDWARE;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -38,8 +55,6 @@ import java.util.List;
* changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED}
* broadcast. Note that this broadcast is not sticky - you should register for it and then
* check the above API to avoid a race condition.
- *
- * @hide RTT_API
*/
@SystemService(Context.WIFI_RTT_RANGING_SERVICE)
public class WifiRttManager {
@@ -71,6 +86,8 @@ public class WifiRttManager {
* Returns the current status of RTT API: whether or not RTT is available. To track
* changes in the state of RTT API register for the
* {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast.
+ * <p>Note: availability of RTT does not mean that the app can use the API. The app's
+ * permissions and platform Location Mode are validated at run-time.
*
* @return A boolean indicating whether the app can use the RTT API at this time (true) or
* not (false).
@@ -95,8 +112,8 @@ public class WifiRttManager {
* will be used.
*/
@RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
- public void startRanging(RangingRequest request, RangingResultCallback callback,
- @Nullable Handler handler) {
+ public void startRanging(@NonNull RangingRequest request,
+ @NonNull RangingResultCallback callback, @Nullable Handler handler) {
startRanging(null, request, callback, handler);
}
@@ -112,12 +129,13 @@ public class WifiRttManager {
* callback} object. If a null is provided then the application's main thread
* will be used.
*
- * @hide (@SystemApi)
+ * @hide
*/
+ @SystemApi
@RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE,
ACCESS_WIFI_STATE})
- public void startRanging(@Nullable WorkSource workSource, RangingRequest request,
- RangingResultCallback callback, @Nullable Handler handler) {
+ public void startRanging(@Nullable WorkSource workSource, @NonNull RangingRequest request,
+ @NonNull RangingResultCallback callback, @Nullable Handler handler) {
if (VDBG) {
Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
+ ", callback=" + callback + ", handler=" + handler);
@@ -143,10 +161,11 @@ public class WifiRttManager {
*
* @param workSource The work-sources of the requesters.
*
- * @hide (@SystemApi)
+ * @hide
*/
+ @SystemApi
@RequiresPermission(allOf = {LOCATION_HARDWARE})
- public void cancelRanging(WorkSource workSource) {
+ public void cancelRanging(@Nullable WorkSource workSource) {
if (VDBG) {
Log.v(TAG, "cancelRanging: workSource=" + workSource);
}
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index a0d407a927a2..11ac05800a7c 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -13,6 +13,8 @@
<li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
<li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
</ul>
+<p>Usage of the API is also gated by the device's Location Mode: whether it permits Wi-Fi based
+location to be queried.</p>
<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi RTT
functionality.