diff options
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. |