Merge "hostapd: add 60GHz(WiGig) support"
diff --git a/audio/7.0/config/Android.bp b/audio/7.0/config/Android.bp
index 015c424..f67cc7c 100644
--- a/audio/7.0/config/Android.bp
+++ b/audio/7.0/config/Android.bp
@@ -1,5 +1,6 @@
xsd_config {
name: "audio_policy_configuration_V7_0",
srcs: ["audio_policy_configuration.xsd"],
- package_name: "audio.policy.configuration.V7_0",
+ package_name: "android.audio.policy.configuration.V7_0",
+ nullability: true,
}
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
index 453ed16..0b2e4a4 100644
--- a/audio/7.0/config/api/current.txt
+++ b/audio/7.0/config/api/current.txt
@@ -1,571 +1,572 @@
// Signature format: 2.0
-package audio.policy.configuration.V7_0 {
+package android.audio.policy.configuration.V7_0 {
public class AttachedDevices {
ctor public AttachedDevices();
- method public java.util.List<java.lang.String> getItem();
+ method @Nullable public java.util.List<java.lang.String> getItem();
}
public enum AudioChannelMask {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_6;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_NONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_TRI;
- enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_6;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_NONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_TRI;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
}
public enum AudioContentType {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
- enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
}
public enum AudioDevice {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLE_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_IP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LINE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_STUB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_NONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLE_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLE_SPEAKER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_FM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_IP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_IP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_NONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLE_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
}
public enum AudioFormat {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC3;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC4;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_ALAC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_NB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_HD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_CELT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DSD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS_HD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCNW;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCWB;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_FLAC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_IEC61937;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LC3;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LDAC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP2;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP3;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_OPUS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_QCELP;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_SBC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_VORBIS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA;
- enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC3;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_ALAC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DSD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_FLAC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_IEC61937;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LC3;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP2;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP3;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_OPUS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_QCELP;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_SBC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_VORBIS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
}
public enum AudioGainMode {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_CHANNELS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_JOINT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_RAMP;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_CHANNELS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_JOINT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioGainMode AUDIO_GAIN_MODE_RAMP;
}
public enum AudioInOutFlag {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_NONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_NONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
}
public class AudioPolicyConfiguration {
ctor public AudioPolicyConfiguration();
- method public audio.policy.configuration.V7_0.GlobalConfiguration getGlobalConfiguration();
- method public java.util.List<audio.policy.configuration.V7_0.Modules> getModules();
- method public audio.policy.configuration.V7_0.SurroundSound getSurroundSound();
- method public audio.policy.configuration.V7_0.Version getVersion();
- method public java.util.List<audio.policy.configuration.V7_0.Volumes> getVolumes();
- method public void setGlobalConfiguration(audio.policy.configuration.V7_0.GlobalConfiguration);
- method public void setSurroundSound(audio.policy.configuration.V7_0.SurroundSound);
- method public void setVersion(audio.policy.configuration.V7_0.Version);
+ method @Nullable public android.audio.policy.configuration.V7_0.GlobalConfiguration getGlobalConfiguration();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Modules> getModules();
+ method @Nullable public android.audio.policy.configuration.V7_0.SurroundSound getSurroundSound();
+ method @Nullable public android.audio.policy.configuration.V7_0.Version getVersion();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Volumes> getVolumes();
+ method public void setGlobalConfiguration(@Nullable android.audio.policy.configuration.V7_0.GlobalConfiguration);
+ method public void setSurroundSound(@Nullable android.audio.policy.configuration.V7_0.SurroundSound);
+ method public void setVersion(@Nullable android.audio.policy.configuration.V7_0.Version);
}
public enum AudioSource {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_CAMCORDER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_DEFAULT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_FM_TUNER;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_HOTWORD;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_MIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_UNPROCESSED;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_CALL;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_CAMCORDER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_MIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_UNPROCESSED;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
}
public enum AudioStreamType {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ALARM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ASSISTANT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_CALL_ASSISTANT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_DTMF;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_MUSIC;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_NOTIFICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_PATCH;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_REROUTING;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_RING;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_SYSTEM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_TTS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_VOICE_CALL;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ALARM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_DTMF;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_PATCH;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_REROUTING;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_RING;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_SYSTEM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_TTS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_VOICE_CALL;
}
public enum AudioUsage {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ALARM;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_EMERGENCY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_GAME;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_MEDIA;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_SAFETY;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_UNKNOWN;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
- enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_EMERGENCY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_GAME;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_SAFETY;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
}
public enum DeviceCategory {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
- enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
- enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
- enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
- enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
}
public class DevicePorts {
ctor public DevicePorts();
- method public java.util.List<audio.policy.configuration.V7_0.DevicePorts.DevicePort> getDevicePort();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.DevicePorts.DevicePort> getDevicePort();
}
public static class DevicePorts.DevicePort {
ctor public DevicePorts.DevicePort();
- method public String getAddress();
- method public java.util.List<audio.policy.configuration.V7_0.AudioFormat> getEncodedFormats();
- method public audio.policy.configuration.V7_0.Gains getGains();
- method public java.util.List<audio.policy.configuration.V7_0.Profile> getProfile();
- method public audio.policy.configuration.V7_0.Role getRole();
- method public String getTagName();
- method public String getType();
- method public boolean get_default();
- method public void setAddress(String);
- method public void setEncodedFormats(java.util.List<audio.policy.configuration.V7_0.AudioFormat>);
- method public void setGains(audio.policy.configuration.V7_0.Gains);
- method public void setRole(audio.policy.configuration.V7_0.Role);
- method public void setTagName(String);
- method public void setType(String);
- method public void set_default(boolean);
+ method @Nullable public String getAddress();
+ method @Nullable public java.util.List<java.lang.String> getEncodedFormats();
+ method @Nullable public android.audio.policy.configuration.V7_0.Gains getGains();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Profile> getProfile();
+ method @Nullable public android.audio.policy.configuration.V7_0.Role getRole();
+ method @Nullable public String getTagName();
+ method @Nullable public String getType();
+ method @Nullable public boolean get_default();
+ method public void setAddress(@Nullable String);
+ method public void setEncodedFormats(@Nullable java.util.List<java.lang.String>);
+ method public void setGains(@Nullable android.audio.policy.configuration.V7_0.Gains);
+ method public void setRole(@Nullable android.audio.policy.configuration.V7_0.Role);
+ method public void setTagName(@Nullable String);
+ method public void setType(@Nullable String);
+ method public void set_default(@Nullable boolean);
}
public enum EngineSuffix {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.EngineSuffix _default;
- enum_constant public static final audio.policy.configuration.V7_0.EngineSuffix configurable;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.EngineSuffix _default;
+ enum_constant public static final android.audio.policy.configuration.V7_0.EngineSuffix configurable;
}
public class Gains {
ctor public Gains();
- method public java.util.List<audio.policy.configuration.V7_0.Gains.Gain> getGain();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Gains.Gain> getGain();
}
public static class Gains.Gain {
ctor public Gains.Gain();
- method public audio.policy.configuration.V7_0.AudioChannelMask getChannel_mask();
- method public int getDefaultValueMB();
- method public int getMaxRampMs();
- method public int getMaxValueMB();
- method public int getMinRampMs();
- method public int getMinValueMB();
- method public java.util.List<audio.policy.configuration.V7_0.AudioGainMode> getMode();
- method public String getName();
- method public int getStepValueMB();
- method public boolean getUseForVolume();
- method public void setChannel_mask(audio.policy.configuration.V7_0.AudioChannelMask);
- method public void setDefaultValueMB(int);
- method public void setMaxRampMs(int);
- method public void setMaxValueMB(int);
- method public void setMinRampMs(int);
- method public void setMinValueMB(int);
- method public void setMode(java.util.List<audio.policy.configuration.V7_0.AudioGainMode>);
- method public void setName(String);
- method public void setStepValueMB(int);
- method public void setUseForVolume(boolean);
+ method @Nullable public android.audio.policy.configuration.V7_0.AudioChannelMask getChannel_mask();
+ method @Nullable public int getDefaultValueMB();
+ method @Nullable public int getMaxRampMs();
+ method @Nullable public int getMaxValueMB();
+ method @Nullable public int getMinRampMs();
+ method @Nullable public int getMinValueMB();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioGainMode> getMode();
+ method @Nullable public String getName();
+ method @Nullable public int getStepValueMB();
+ method @Nullable public boolean getUseForVolume();
+ method public void setChannel_mask(@Nullable android.audio.policy.configuration.V7_0.AudioChannelMask);
+ method public void setDefaultValueMB(@Nullable int);
+ method public void setMaxRampMs(@Nullable int);
+ method public void setMaxValueMB(@Nullable int);
+ method public void setMinRampMs(@Nullable int);
+ method public void setMinValueMB(@Nullable int);
+ method public void setMode(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioGainMode>);
+ method public void setName(@Nullable String);
+ method public void setStepValueMB(@Nullable int);
+ method public void setUseForVolume(@Nullable boolean);
}
public class GlobalConfiguration {
ctor public GlobalConfiguration();
- method public boolean getCall_screen_mode_supported();
- method public audio.policy.configuration.V7_0.EngineSuffix getEngine_library();
- method public boolean getSpeaker_drc_enabled();
- method public void setCall_screen_mode_supported(boolean);
- method public void setEngine_library(audio.policy.configuration.V7_0.EngineSuffix);
- method public void setSpeaker_drc_enabled(boolean);
+ method @Nullable public boolean getCall_screen_mode_supported();
+ method @Nullable public android.audio.policy.configuration.V7_0.EngineSuffix getEngine_library();
+ method @Nullable public boolean getSpeaker_drc_enabled();
+ method public void setCall_screen_mode_supported(@Nullable boolean);
+ method public void setEngine_library(@Nullable android.audio.policy.configuration.V7_0.EngineSuffix);
+ method public void setSpeaker_drc_enabled(@Nullable boolean);
}
public enum HalVersion {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.HalVersion _2_0;
- enum_constant public static final audio.policy.configuration.V7_0.HalVersion _3_0;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.HalVersion _2_0;
+ enum_constant public static final android.audio.policy.configuration.V7_0.HalVersion _3_0;
}
public class MixPorts {
ctor public MixPorts();
- method public java.util.List<audio.policy.configuration.V7_0.MixPorts.MixPort> getMixPort();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.MixPorts.MixPort> getMixPort();
}
public static class MixPorts.MixPort {
ctor public MixPorts.MixPort();
- method public java.util.List<audio.policy.configuration.V7_0.AudioInOutFlag> getFlags();
- method public audio.policy.configuration.V7_0.Gains getGains();
- method public long getMaxActiveCount();
- method public long getMaxOpenCount();
- method public String getName();
- method public java.util.List<audio.policy.configuration.V7_0.AudioUsage> getPreferredUsage();
- method public java.util.List<audio.policy.configuration.V7_0.Profile> getProfile();
- method public audio.policy.configuration.V7_0.Role getRole();
- method public void setFlags(java.util.List<audio.policy.configuration.V7_0.AudioInOutFlag>);
- method public void setGains(audio.policy.configuration.V7_0.Gains);
- method public void setMaxActiveCount(long);
- method public void setMaxOpenCount(long);
- method public void setName(String);
- method public void setPreferredUsage(java.util.List<audio.policy.configuration.V7_0.AudioUsage>);
- method public void setRole(audio.policy.configuration.V7_0.Role);
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioInOutFlag> getFlags();
+ method @Nullable public android.audio.policy.configuration.V7_0.Gains getGains();
+ method @Nullable public long getMaxActiveCount();
+ method @Nullable public long getMaxOpenCount();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioUsage> getPreferredUsage();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Profile> getProfile();
+ method @Nullable public android.audio.policy.configuration.V7_0.Role getRole();
+ method public void setFlags(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioInOutFlag>);
+ method public void setGains(@Nullable android.audio.policy.configuration.V7_0.Gains);
+ method public void setMaxActiveCount(@Nullable long);
+ method public void setMaxOpenCount(@Nullable long);
+ method public void setName(@Nullable String);
+ method public void setPreferredUsage(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioUsage>);
+ method public void setRole(@Nullable android.audio.policy.configuration.V7_0.Role);
}
public enum MixType {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.MixType mix;
- enum_constant public static final audio.policy.configuration.V7_0.MixType mux;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.MixType mix;
+ enum_constant public static final android.audio.policy.configuration.V7_0.MixType mux;
}
public class Modules {
ctor public Modules();
- method public java.util.List<audio.policy.configuration.V7_0.Modules.Module> getModule();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Modules.Module> getModule();
}
public static class Modules.Module {
ctor public Modules.Module();
- method public audio.policy.configuration.V7_0.AttachedDevices getAttachedDevices();
- method public String getDefaultOutputDevice();
- method public audio.policy.configuration.V7_0.DevicePorts getDevicePorts();
- method public audio.policy.configuration.V7_0.HalVersion getHalVersion();
- method public audio.policy.configuration.V7_0.MixPorts getMixPorts();
- method public String getName();
- method public audio.policy.configuration.V7_0.Routes getRoutes();
- method public void setAttachedDevices(audio.policy.configuration.V7_0.AttachedDevices);
- method public void setDefaultOutputDevice(String);
- method public void setDevicePorts(audio.policy.configuration.V7_0.DevicePorts);
- method public void setHalVersion(audio.policy.configuration.V7_0.HalVersion);
- method public void setMixPorts(audio.policy.configuration.V7_0.MixPorts);
- method public void setName(String);
- method public void setRoutes(audio.policy.configuration.V7_0.Routes);
+ method @Nullable public android.audio.policy.configuration.V7_0.AttachedDevices getAttachedDevices();
+ method @Nullable public String getDefaultOutputDevice();
+ method @Nullable public android.audio.policy.configuration.V7_0.DevicePorts getDevicePorts();
+ method @Nullable public android.audio.policy.configuration.V7_0.HalVersion getHalVersion();
+ method @Nullable public android.audio.policy.configuration.V7_0.MixPorts getMixPorts();
+ method @Nullable public String getName();
+ method @Nullable public android.audio.policy.configuration.V7_0.Routes getRoutes();
+ method public void setAttachedDevices(@Nullable android.audio.policy.configuration.V7_0.AttachedDevices);
+ method public void setDefaultOutputDevice(@Nullable String);
+ method public void setDevicePorts(@Nullable android.audio.policy.configuration.V7_0.DevicePorts);
+ method public void setHalVersion(@Nullable android.audio.policy.configuration.V7_0.HalVersion);
+ method public void setMixPorts(@Nullable android.audio.policy.configuration.V7_0.MixPorts);
+ method public void setName(@Nullable String);
+ method public void setRoutes(@Nullable android.audio.policy.configuration.V7_0.Routes);
}
public class Profile {
ctor public Profile();
- method public java.util.List<audio.policy.configuration.V7_0.AudioChannelMask> getChannelMasks();
- method public String getFormat();
- method public String getName();
- method public java.util.List<java.math.BigInteger> getSamplingRates();
- method public void setChannelMasks(java.util.List<audio.policy.configuration.V7_0.AudioChannelMask>);
- method public void setFormat(String);
- method public void setName(String);
- method public void setSamplingRates(java.util.List<java.math.BigInteger>);
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioChannelMask> getChannelMasks();
+ method @Nullable public String getFormat();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
+ method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioChannelMask>);
+ method public void setFormat(@Nullable String);
+ method public void setName(@Nullable String);
+ method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
}
public class Reference {
ctor public Reference();
- method public String getName();
- method public java.util.List<java.lang.String> getPoint();
- method public void setName(String);
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method public void setName(@Nullable String);
}
public enum Role {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.Role sink;
- enum_constant public static final audio.policy.configuration.V7_0.Role source;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.Role sink;
+ enum_constant public static final android.audio.policy.configuration.V7_0.Role source;
}
public class Routes {
ctor public Routes();
- method public java.util.List<audio.policy.configuration.V7_0.Routes.Route> getRoute();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Routes.Route> getRoute();
}
public static class Routes.Route {
ctor public Routes.Route();
- method public String getSink();
- method public String getSources();
- method public audio.policy.configuration.V7_0.MixType getType();
- method public void setSink(String);
- method public void setSources(String);
- method public void setType(audio.policy.configuration.V7_0.MixType);
+ method @Nullable public String getSink();
+ method @Nullable public String getSources();
+ method @Nullable public android.audio.policy.configuration.V7_0.MixType getType();
+ method public void setSink(@Nullable String);
+ method public void setSources(@Nullable String);
+ method public void setType(@Nullable android.audio.policy.configuration.V7_0.MixType);
}
public class SurroundFormats {
ctor public SurroundFormats();
- method public java.util.List<audio.policy.configuration.V7_0.SurroundFormats.Format> getFormat();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.SurroundFormats.Format> getFormat();
}
public static class SurroundFormats.Format {
ctor public SurroundFormats.Format();
- method public audio.policy.configuration.V7_0.AudioFormat getName();
- method public java.util.List<audio.policy.configuration.V7_0.AudioFormat> getSubformats();
- method public void setName(audio.policy.configuration.V7_0.AudioFormat);
- method public void setSubformats(java.util.List<audio.policy.configuration.V7_0.AudioFormat>);
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getSubformats();
+ method public void setName(@Nullable String);
+ method public void setSubformats(@Nullable java.util.List<java.lang.String>);
}
public class SurroundSound {
ctor public SurroundSound();
- method public audio.policy.configuration.V7_0.SurroundFormats getFormats();
- method public void setFormats(audio.policy.configuration.V7_0.SurroundFormats);
+ method @Nullable public android.audio.policy.configuration.V7_0.SurroundFormats getFormats();
+ method public void setFormats(@Nullable android.audio.policy.configuration.V7_0.SurroundFormats);
}
public enum Version {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.Version _1_0;
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.V7_0.Version _1_0;
}
public class Volume {
ctor public Volume();
- method public audio.policy.configuration.V7_0.DeviceCategory getDeviceCategory();
- method public java.util.List<java.lang.String> getPoint();
- method public String getRef();
- method public audio.policy.configuration.V7_0.AudioStreamType getStream();
- method public void setDeviceCategory(audio.policy.configuration.V7_0.DeviceCategory);
- method public void setRef(String);
- method public void setStream(audio.policy.configuration.V7_0.AudioStreamType);
+ method @Nullable public android.audio.policy.configuration.V7_0.DeviceCategory getDeviceCategory();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method @Nullable public String getRef();
+ method @Nullable public android.audio.policy.configuration.V7_0.AudioStreamType getStream();
+ method public void setDeviceCategory(@Nullable android.audio.policy.configuration.V7_0.DeviceCategory);
+ method public void setRef(@Nullable String);
+ method public void setStream(@Nullable android.audio.policy.configuration.V7_0.AudioStreamType);
}
public class Volumes {
ctor public Volumes();
- method public java.util.List<audio.policy.configuration.V7_0.Reference> getReference();
- method public java.util.List<audio.policy.configuration.V7_0.Volume> getVolume();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Reference> getReference();
+ method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Volume> getVolume();
}
public class XmlParser {
ctor public XmlParser();
- method public static audio.policy.configuration.V7_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static android.audio.policy.configuration.V7_0.AudioPolicyConfiguration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
}
}
diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd
index 6784828..a735c6d 100644
--- a/audio/7.0/config/audio_policy_configuration.xsd
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -181,6 +181,7 @@
<xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
<xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
<xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
<xs:enumeration value="AUDIO_INPUT_FLAG_NONE" />
<xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
<xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
@@ -774,13 +775,13 @@
</xs:sequence>
</xs:complexType>
<xs:simpleType name="audioFormatsList">
- <xs:list itemType="audioFormat" />
+ <xs:list itemType="extendableAudioFormat" />
</xs:simpleType>
<xs:complexType name="surroundFormats">
<xs:sequence>
<xs:element name="format" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
- <xs:attribute name="name" type="audioFormat" use="required"/>
+ <xs:attribute name="name" type="extendableAudioFormat" use="required"/>
<xs:attribute name="subformats" type="audioFormatsList" />
</xs:complexType>
</xs:element>
diff --git a/audio/7.0/types.hal b/audio/7.0/types.hal
index 6cac9c9..2d42129 100644
--- a/audio/7.0/types.hal
+++ b/audio/7.0/types.hal
@@ -44,8 +44,10 @@
* A substitute for POSIX timespec.
*/
struct TimeSpec {
- uint64_t tvSec; // seconds
- uint64_t tvNSec; // nanoseconds
+ /** Seconds. */
+ uint64_t tvSec;
+ /** Nanoseconds. */
+ uint64_t tvNSec;
};
struct ParameterValue {
@@ -85,8 +87,10 @@
* Used by streams opened in mmap mode.
*/
struct MmapPosition {
- int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
- int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called
+ /** Timestamp in ns, CLOCK_MONOTONIC. */
+ int64_t timeNanoseconds;
+ /** Increasing 32 bit frame count reset when IStream.stop() is called. */
+ int32_t positionFrames;
};
/**
@@ -128,9 +132,12 @@
*/
@export(name="audio_microphone_channel_mapping_t", value_prefix="AUDIO_MICROPHONE_CHANNEL_MAPPING_")
enum AudioMicrophoneChannelMapping : uint32_t {
- UNUSED = 0, /* Channel not used */
- DIRECT = 1, /* Channel used and signal not processed */
- PROCESSED = 2, /* Channel used and signal has some processing */
+ /** Channel not used. */
+ UNUSED = 0,
+ /** Channel used and signal not processed. */
+ DIRECT = 1,
+ /** Channel used and signal has some processing. */
+ PROCESSED = 2,
};
/**
@@ -179,7 +186,8 @@
* Used by StreamIn and Device
*/
struct MicrophoneInfo {
- /** Unique alphanumeric id for microphone. Guaranteed to be the same
+ /**
+ * Unique alphanumeric id for microphone. Guaranteed to be the same
* even after rebooting.
*/
string deviceId;
@@ -187,18 +195,21 @@
* Device specific information
*/
DeviceAddress deviceAddress;
- /** Each element of the vector must describe the channel with the same
- * index.
+ /**
+ * Each element of the vector must describe the channel with the same
+ * index.
*/
vec<AudioMicrophoneChannelMapping> channelMapping;
/** Location of the microphone in regard to the body of the device */
AudioMicrophoneLocation location;
- /** Identifier to help group related microphones together
- * e.g. microphone arrays should belong to the same group
+ /**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
*/
AudioMicrophoneGroup group;
- /** Index of this microphone within the group.
- * (group, index) must be unique within the same device.
+ /**
+ * Index of this microphone within the group.
+ * (group, index) must be unique within the same device.
*/
uint32_t indexInTheGroup;
/** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
@@ -209,17 +220,20 @@
float minSpl;
/** Standard polar pattern of the microphone */
AudioMicrophoneDirectionality directionality;
- /** Vector with ordered frequency responses (from low to high frequencies)
- * with the frequency response of the microphone.
- * Levels are in dB, relative to level at 1000 Hz
+ /**
+ * Vector with ordered frequency responses (from low to high frequencies)
+ * with the frequency response of the microphone.
+ * Levels are in dB, relative to level at 1000 Hz
*/
vec<AudioFrequencyResponsePoint> frequencyResponse;
- /** Position of the microphone's capsule in meters, from the
- * bottom-left-back corner of the bounding box of device.
+ /**
+ * Position of the microphone's capsule in meters, from the
+ * bottom-left-back corner of the bounding box of device.
*/
AudioMicrophoneCoordinate position;
- /** Normalized point to signal the main orientation of the microphone's
- * capsule. sqrt(x^2 + y^2 + z^2) = 1
+ /**
+ * Normalized point to signal the main orientation of the microphone's
+ * capsule. sqrt(x^2 + y^2 + z^2) = 1
*/
AudioMicrophoneCoordinate orientation;
};
@@ -262,7 +276,6 @@
// frameworks/base/media/java/android/media/AudioTrack.java
/**
* Disable any Dual Mono presentation effect.
- *
*/
OFF = 0,
/**
diff --git a/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
similarity index 83%
rename from audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
rename to audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
index cedcab3..414eede 100644
--- a/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
+++ b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
-#define AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+#ifndef ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+#define ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
#include <sys/types.h>
+#include <algorithm>
+#include <cctype>
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0.h>
-namespace audio::policy::configuration::V7_0 {
+namespace android::audio::policy::configuration::V7_0 {
static inline size_t getChannelCount(AudioChannelMask mask) {
switch (mask) {
@@ -210,6 +212,43 @@
return isOutputDevice(stringToAudioDevice(device));
}
-} // namespace audio::policy::configuration::V7_0
+static inline bool isVendorExtension(const std::string& device) {
+ // Must match the "vendorExtension" rule from the XSD file.
+ static const std::string vendorPrefix = "VX_";
+ return device.size() > vendorPrefix.size() &&
+ device.substr(0, vendorPrefix.size()) == vendorPrefix &&
+ std::all_of(device.begin() + vendorPrefix.size(), device.end(),
+ [](unsigned char c) { return c == '_' || std::isalnum(c); });
+}
-#endif // AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+static inline bool isUnknownAudioChannelMask(const std::string& mask) {
+ return stringToAudioChannelMask(mask) == AudioChannelMask::UNKNOWN;
+}
+
+static inline bool isUnknownAudioDevice(const std::string& device) {
+ return stringToAudioDevice(device) == AudioDevice::UNKNOWN && !isVendorExtension(device);
+}
+
+static inline bool isUnknownAudioFormat(const std::string& format) {
+ return stringToAudioFormat(format) == AudioFormat::UNKNOWN && !isVendorExtension(format);
+}
+
+static inline bool isUnknownAudioGainMode(const std::string& mode) {
+ return stringToAudioGainMode(mode) == AudioGainMode::UNKNOWN;
+}
+
+static inline bool isUnknownAudioSource(const std::string& source) {
+ return stringToAudioSource(source) == AudioSource::UNKNOWN;
+}
+
+static inline bool isUnknownAudioStreamType(const std::string& streamType) {
+ return stringToAudioStreamType(streamType) == AudioStreamType::UNKNOWN;
+}
+
+static inline bool isUnknownAudioUsage(const std::string& usage) {
+ return stringToAudioUsage(usage) == AudioUsage::UNKNOWN;
+}
+
+} // namespace android::audio::policy::configuration::V7_0
+
+#endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
diff --git a/audio/common/7.0/example/Effect.cpp b/audio/common/7.0/example/Effect.cpp
index 423754d..9d5ab31 100644
--- a/audio/common/7.0/example/Effect.cpp
+++ b/audio/common/7.0/example/Effect.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "EffectsFactory7.0"
#include <log/log.h>
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0.h>
#include "Effect.h"
@@ -28,7 +28,7 @@
using namespace ::android::hardware::audio::common::V7_0;
// Make an alias for enumerations generated from the APM config XSD.
namespace xsd {
-using namespace ::audio::policy::configuration::V7_0;
+using namespace ::android::audio::policy::configuration::V7_0;
}
namespace android::hardware::audio::effect::V7_0::implementation {
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
index 631d524..ed56c73 100644
--- a/audio/common/7.0/types.hal
+++ b/audio/common/7.0/types.hal
@@ -118,9 +118,9 @@
* Base configuration attributes applicable to any stream of audio.
*/
struct AudioConfigBase {
- AudioFormat format; // 'DEFAULT' means 'unspecified'
+ AudioFormat format; // empty means 'unspecified'
uint32_t sampleRateHz; // 0 means 'unspecified'
- vec<AudioChannelMask> channelMask; // empty means 'unspecified'
+ AudioChannelMask channelMask; // empty means 'unspecified'
};
/**
@@ -167,10 +167,18 @@
AudioDevice deviceType;
safe_union Address {
/**
- * The address may be left unspecified if 'device' specifies
- * a physical device unambiguously.
+ * String uniquely identifying the device among other devices
+ * of the same type. Can be empty in case there is only one device
+ * of this type.
+ *
+ * Depending on the device type, its id may be assigned by the framework
+ * (this is done for REMOTE_SUBMIX), or specified in the audio policy
+ * configuration file (typically done for BUS devices), or assigned
+ * by the HAL service. In any case, both framework and HAL must
+ * never attempt to parse the value of the id. If the address must
+ * be parsed, one of the members below must be used instead of 'id'.
*/
- Monostate unspecified;
+ string id;
/** IEEE 802 MAC address. Set for Bluetooth devices. */
uint8_t[6] mac;
/** IPv4 Address. Set for IPv4 devices. */
@@ -182,10 +190,6 @@
int32_t card;
int32_t device;
} alsa;
- /** Arbitrary BUS device unique address. Not interpreted by the framework. */
- string bus;
- /** Arbitrary REMOTE_SUBMIX device unique address. Not interpreted by the HAL. */
- string rSubmix;
} address;
};
@@ -328,14 +332,22 @@
* A gain stage is always attached to an audio port.
*/
struct AudioGain {
- vec<AudioGainMode> mode; // modes of operation
- AudioChannelMask channelMask; // channels which gain can be controlled
- int32_t minValue; // minimum gain value in millibels
- int32_t maxValue; // maximum gain value in millibels
- int32_t defaultValue; // default gain value in millibels
- uint32_t stepValue; // gain step in millibels
- uint32_t minRampMs; // minimum ramp duration in ms
- uint32_t maxRampMs; // maximum ramp duration in ms
+ /** Modes of operation. */
+ vec<AudioGainMode> mode;
+ /** Channels which gain can be controlled. */
+ AudioChannelMask channelMask;
+ /** Minimum gain value in millibels. */
+ int32_t minValue;
+ /** Maximum gain value in millibels. */
+ int32_t maxValue;
+ /** Default gain value in millibels. */
+ int32_t defaultValue;
+ /** Gain step in millibels. */
+ uint32_t stepValue;
+ /** Ramp duration in ms. */
+ uint32_t minRampMs;
+ /** Maximum ramp duration in ms. */
+ uint32_t maxRampMs;
};
/**
@@ -343,16 +355,20 @@
* given port.
*/
struct AudioGainConfig {
- int32_t index; // index of the corresponding AudioGain in AudioPort.gains
- vec<AudioGainMode> mode; // modes of operation
- AudioChannelMask channelMask; // channels which gain value follows
+ /** Index of the corresponding AudioGain in AudioPort.gains. */
+ int32_t index;
+ /** Modes of operation. */
+ vec<AudioGainMode> mode;
+ /** Channels which gain value follows. */
+ AudioChannelMask channelMask;
/**
* Gain values in millibels for each channel ordered from LSb to MSb in
* channel mask. The number of values is 1 in joint mode or
- * popcount(channel_mask).
+ * the number of channels in the channel mask.
*/
- int32_t[4 * 8] values;
- uint32_t rampDurationMs; // ramp duration in ms
+ vec<int32_t> values;
+ /** Ramp duration in ms. */
+ uint32_t rampDurationMs;
};
@@ -409,7 +425,7 @@
* parameters (or none) may be set. See the documentation of the
* AudioConfigBase struct.
*/
- AudioConfigBase config;
+ AudioConfigBase base;
/** Associated gain control. */
safe_union OptionalGain {
Monostate unspecified;
@@ -439,6 +455,8 @@
vec<AudioProfile> profiles;
/** List of gain controls attached to the port. */
vec<AudioGain> gains;
+ /** Parameters that depend on the actual port role. */
+ AudioPortExtendedInfo ext;
/**
* Current configuration of the audio port, may have all the fields left
* unspecified.
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
new file mode 100644
index 0000000..1a66282
--- /dev/null
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define LOG_TAG "HidlUtils"
+#include <log/log.h>
+
+#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <common/all-versions/VersionUtils.h>
+
+#include "HidlUtils.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace CPP_VERSION {
+namespace implementation {
+
+namespace xsd {
+using namespace ::android::audio::policy::configuration::V7_0;
+}
+
+#define CONVERT_CHECKED(expr, result) \
+ if (status_t status = (expr); status != NO_ERROR) { \
+ result = status; \
+ }
+
+status_t HidlUtils::audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask) {
+ *channelMask = audio_channel_index_mask_to_string(halChannelMask);
+ if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown index channel mask value 0x%X", halChannelMask);
+ *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioInputChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask) {
+ *channelMask = audio_channel_in_mask_to_string(halChannelMask);
+ if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown input channel mask value 0x%X", halChannelMask);
+ *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioOutputChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask) {
+ *channelMask = audio_channel_out_mask_to_string(halChannelMask);
+ if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown output channel mask value 0x%X", halChannelMask);
+ *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioChannelMaskFromHal(audio_channel_mask_t halChannelMask, bool isInput,
+ AudioChannelMask* channelMask) {
+ if (halChannelMask != AUDIO_CHANNEL_NONE) {
+ if (audio_channel_mask_is_valid(halChannelMask)) {
+ switch (audio_channel_mask_get_representation(halChannelMask)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ return isInput ? audioInputChannelMaskFromHal(halChannelMask, channelMask)
+ : audioOutputChannelMaskFromHal(halChannelMask, channelMask);
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ // Index masks do not have direction.
+ return audioIndexChannelMaskFromHal(halChannelMask, channelMask);
+ // no default
+ }
+ }
+ *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
+ return BAD_VALUE;
+ }
+ *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
+ return NO_ERROR;
+}
+
+status_t HidlUtils::audioChannelMaskToHal(const AudioChannelMask& channelMask,
+ audio_channel_mask_t* halChannelMask) {
+ if (!xsd::isUnknownAudioChannelMask(channelMask) &&
+ audio_channel_mask_from_string(channelMask.c_str(), halChannelMask)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown channel mask \"%s\"", channelMask.c_str());
+ *halChannelMask = AUDIO_CHANNEL_NONE;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioConfigBaseFromHal(const audio_config_base_t& halConfigBase, bool isInput,
+ AudioConfigBase* configBase) {
+ status_t result = NO_ERROR;
+ configBase->sampleRateHz = halConfigBase.sample_rate;
+ CONVERT_CHECKED(
+ audioChannelMaskFromHal(halConfigBase.channel_mask, isInput, &configBase->channelMask),
+ result);
+ CONVERT_CHECKED(audioFormatFromHal(halConfigBase.format, &configBase->format), result);
+ return result;
+}
+
+status_t HidlUtils::audioConfigBaseToHal(const AudioConfigBase& configBase,
+ audio_config_base_t* halConfigBase) {
+ status_t result = NO_ERROR;
+ halConfigBase->sample_rate = configBase.sampleRateHz;
+ CONVERT_CHECKED(audioChannelMaskToHal(configBase.channelMask, &halConfigBase->channel_mask),
+ result);
+ CONVERT_CHECKED(audioFormatToHal(configBase.format, &halConfigBase->format), result);
+ return result;
+}
+
+status_t HidlUtils::audioDeviceTypeFromHal(audio_devices_t halDevice, AudioDevice* device) {
+ *device = audio_device_to_string(halDevice);
+ if (!device->empty() && !xsd::isUnknownAudioDevice(*device)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio device value 0x%X", halDevice);
+ *device = toString(xsd::AudioDevice::AUDIO_DEVICE_NONE);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioDeviceTypeToHal(const AudioDevice& device, audio_devices_t* halDevice) {
+ if (!xsd::isUnknownAudioDevice(device) && audio_device_from_string(device.c_str(), halDevice)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio device \"%s\"", device.c_str());
+ *halDevice = AUDIO_DEVICE_NONE;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioFormatFromHal(audio_format_t halFormat, AudioFormat* format) {
+ *format = audio_format_to_string(halFormat);
+ if (!format->empty() && !xsd::isUnknownAudioFormat(*format)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio format value 0x%X", halFormat);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioFormatToHal(const AudioFormat& format, audio_format_t* halFormat) {
+ if (!xsd::isUnknownAudioFormat(format) && audio_format_from_string(format.c_str(), halFormat)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio format \"%s\"", format.c_str());
+ *halFormat = AUDIO_FORMAT_DEFAULT;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask,
+ hidl_vec<AudioGainMode>* gainModeMask) {
+ status_t status = NO_ERROR;
+ std::vector<AudioGainMode> result;
+ for (uint32_t bit = 0; bit < sizeof(audio_gain_mode_t) * 8; ++bit) {
+ audio_gain_mode_t flag = static_cast<audio_gain_mode_t>(1u << bit);
+ if ((flag & halGainModeMask) == flag) {
+ AudioGainMode flagStr = audio_gain_mode_to_string(flag);
+ if (!flagStr.empty() && !xsd::isUnknownAudioGainMode(flagStr)) {
+ result.push_back(flagStr);
+ } else {
+ ALOGE("Unknown audio gain mode value 0x%X", flag);
+ status = BAD_VALUE;
+ }
+ }
+ }
+ *gainModeMask = result;
+ return status;
+}
+
+status_t HidlUtils::audioGainModeMaskToHal(const hidl_vec<AudioGainMode>& gainModeMask,
+ audio_gain_mode_t* halGainModeMask) {
+ status_t status = NO_ERROR;
+ *halGainModeMask = {};
+ for (const auto& gainMode : gainModeMask) {
+ audio_gain_mode_t halGainMode;
+ if (!xsd::isUnknownAudioGainMode(gainMode) &&
+ audio_gain_mode_from_string(gainMode.c_str(), &halGainMode)) {
+ *halGainModeMask = static_cast<audio_gain_mode_t>(*halGainModeMask | halGainMode);
+ } else {
+ ALOGE("Unknown audio gain mode \"%s\"", gainMode.c_str());
+ status = BAD_VALUE;
+ }
+ }
+ return status;
+}
+
+status_t HidlUtils::audioSourceFromHal(audio_source_t halSource, AudioSource* source) {
+ *source = audio_source_to_string(halSource);
+ if (!source->empty() && !xsd::isUnknownAudioSource(*source)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio source value 0x%X", halSource);
+ *source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioSourceToHal(const AudioSource& source, audio_source_t* halSource) {
+ if (!xsd::isUnknownAudioSource(source) && audio_source_from_string(source.c_str(), halSource)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio source \"%s\"", source.c_str());
+ *halSource = AUDIO_SOURCE_DEFAULT;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioStreamTypeFromHal(audio_stream_type_t halStreamType,
+ AudioStreamType* streamType) {
+ *streamType = audio_stream_type_to_string(halStreamType);
+ if (!streamType->empty() && !xsd::isUnknownAudioStreamType(*streamType)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio stream type value 0x%X", halStreamType);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioStreamTypeToHal(const AudioStreamType& streamType,
+ audio_stream_type_t* halStreamType) {
+ if (!xsd::isUnknownAudioStreamType(streamType) &&
+ audio_stream_type_from_string(streamType.c_str(), halStreamType)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio stream type \"%s\"", streamType.c_str());
+ *halStreamType = AUDIO_STREAM_DEFAULT;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, bool isInput,
+ AudioConfig* config) {
+ status_t result = NO_ERROR;
+ audio_config_base_t halConfigBase = {halConfig.sample_rate, halConfig.channel_mask,
+ halConfig.format};
+ CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, isInput, &config->base), result);
+ CONVERT_CHECKED(audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo), result);
+ config->frameCount = halConfig.frame_count;
+ return result;
+}
+
+status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
+ status_t result = NO_ERROR;
+ *halConfig = AUDIO_CONFIG_INITIALIZER;
+ audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER;
+ CONVERT_CHECKED(audioConfigBaseToHal(config.base, &halConfigBase), result);
+ halConfig->sample_rate = halConfigBase.sample_rate;
+ halConfig->channel_mask = halConfigBase.channel_mask;
+ halConfig->format = halConfigBase.format;
+ CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info), result);
+ halConfig->frame_count = config.frameCount;
+ return result;
+}
+
+status_t HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig, bool isInput,
+ AudioGainConfig* config) {
+ status_t result = NO_ERROR;
+ config->index = halConfig.index;
+ CONVERT_CHECKED(audioGainModeMaskFromHal(halConfig.mode, &config->mode), result);
+ CONVERT_CHECKED(audioChannelMaskFromHal(halConfig.channel_mask, isInput, &config->channelMask),
+ result);
+ if (halConfig.mode & AUDIO_GAIN_MODE_JOINT) {
+ config->values.resize(1);
+ config->values[0] = halConfig.values[0];
+ }
+ if (halConfig.mode & (AUDIO_GAIN_MODE_CHANNELS | AUDIO_GAIN_MODE_RAMP)) {
+ config->values.resize(__builtin_popcount(halConfig.channel_mask));
+ for (size_t i = 0; i < config->values.size(); ++i) {
+ config->values[i] = halConfig.values[i];
+ }
+ }
+ config->rampDurationMs = halConfig.ramp_duration_ms;
+ return result;
+}
+
+status_t HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
+ struct audio_gain_config* halConfig) {
+ status_t result = NO_ERROR;
+ halConfig->index = config.index;
+ CONVERT_CHECKED(audioGainModeMaskToHal(config.mode, &halConfig->mode), result);
+ CONVERT_CHECKED(audioChannelMaskToHal(config.channelMask, &halConfig->channel_mask), result);
+ memset(halConfig->values, 0, sizeof(halConfig->values));
+ if (halConfig->mode & AUDIO_GAIN_MODE_JOINT) {
+ if (config.values.size() > 0) {
+ halConfig->values[0] = config.values[0];
+ } else {
+ ALOGE("Empty values vector in AudioGainConfig");
+ result = BAD_VALUE;
+ }
+ }
+ if (halConfig->mode & (AUDIO_GAIN_MODE_CHANNELS | AUDIO_GAIN_MODE_RAMP)) {
+ size_t channelCount = __builtin_popcount(halConfig->channel_mask);
+ size_t valuesCount = config.values.size();
+ if (channelCount != valuesCount) {
+ ALOGE("Wrong number of values in AudioGainConfig, expected: %zu, found: %zu",
+ channelCount, valuesCount);
+ result = BAD_VALUE;
+ if (channelCount < valuesCount) {
+ valuesCount = channelCount;
+ }
+ }
+ for (size_t i = 0; i < valuesCount; ++i) {
+ halConfig->values[i] = config.values[i];
+ }
+ }
+ halConfig->ramp_duration_ms = config.rampDurationMs;
+ return result;
+}
+
+status_t HidlUtils::audioGainFromHal(const struct audio_gain& halGain, bool isInput,
+ AudioGain* gain) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioGainModeMaskFromHal(halGain.mode, &gain->mode), result);
+ CONVERT_CHECKED(audioChannelMaskFromHal(halGain.channel_mask, isInput, &gain->channelMask),
+ result);
+ gain->minValue = halGain.min_value;
+ gain->maxValue = halGain.max_value;
+ gain->defaultValue = halGain.default_value;
+ gain->stepValue = halGain.step_value;
+ gain->minRampMs = halGain.min_ramp_ms;
+ gain->maxRampMs = halGain.max_ramp_ms;
+ return result;
+}
+
+status_t HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioGainModeMaskToHal(gain.mode, &halGain->mode), result);
+ CONVERT_CHECKED(audioChannelMaskToHal(gain.channelMask, &halGain->channel_mask), result);
+ halGain->min_value = gain.minValue;
+ halGain->max_value = gain.maxValue;
+ halGain->default_value = gain.defaultValue;
+ halGain->step_value = gain.stepValue;
+ halGain->min_ramp_ms = gain.minRampMs;
+ halGain->max_ramp_ms = gain.maxRampMs;
+ return result;
+}
+
+status_t HidlUtils::audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage) {
+ if (halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST ||
+ halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT ||
+ halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED ||
+ halUsage == AUDIO_USAGE_NOTIFICATION_EVENT) {
+ halUsage = AUDIO_USAGE_NOTIFICATION;
+ }
+ *usage = audio_usage_to_string(halUsage);
+ if (!usage->empty() && !xsd::isUnknownAudioUsage(*usage)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio usage %d", halUsage);
+ *usage = toString(xsd::AudioUsage::AUDIO_USAGE_UNKNOWN);
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage) {
+ if (!xsd::isUnknownAudioUsage(usage) && audio_usage_from_string(usage.c_str(), halUsage)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio usage \"%s\"", usage.c_str());
+ *halUsage = AUDIO_USAGE_UNKNOWN;
+ return BAD_VALUE;
+}
+
+status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
+ AudioOffloadInfo* offload) {
+ status_t result = NO_ERROR;
+ audio_config_base_t halConfigBase = {halOffload.sample_rate, halOffload.channel_mask,
+ halOffload.format};
+ CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, false /*isInput*/, &offload->base),
+ result);
+ CONVERT_CHECKED(audioStreamTypeFromHal(halOffload.stream_type, &offload->streamType), result);
+ offload->bitRatePerSecond = halOffload.bit_rate;
+ offload->durationMicroseconds = halOffload.duration_us;
+ offload->hasVideo = halOffload.has_video;
+ offload->isStreaming = halOffload.is_streaming;
+ offload->bitWidth = halOffload.bit_width;
+ offload->bufferSize = halOffload.offload_buffer_size;
+ CONVERT_CHECKED(audioUsageFromHal(halOffload.usage, &offload->usage), result);
+ if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) {
+ offload->encapsulationMode =
+ static_cast<AudioEncapsulationMode>(halOffload.encapsulation_mode);
+ offload->contentId = halOffload.content_id;
+ offload->syncId = halOffload.sync_id;
+ } else {
+ offload->encapsulationMode = AudioEncapsulationMode::NONE;
+ offload->contentId = 0;
+ offload->syncId = 0;
+ }
+ return result;
+}
+
+status_t HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
+ audio_offload_info_t* halOffload) {
+ status_t result = NO_ERROR;
+ *halOffload = AUDIO_INFO_INITIALIZER;
+ audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER;
+ CONVERT_CHECKED(audioConfigBaseToHal(offload.base, &halConfigBase), result);
+ halOffload->sample_rate = halConfigBase.sample_rate;
+ halOffload->channel_mask = halConfigBase.channel_mask;
+ halOffload->format = halConfigBase.format;
+ CONVERT_CHECKED(audioStreamTypeToHal(offload.streamType, &halOffload->stream_type), result);
+ halOffload->bit_rate = offload.bitRatePerSecond;
+ halOffload->duration_us = offload.durationMicroseconds;
+ halOffload->has_video = offload.hasVideo;
+ halOffload->is_streaming = offload.isStreaming;
+ halOffload->bit_width = offload.bitWidth;
+ halOffload->offload_buffer_size = offload.bufferSize;
+ CONVERT_CHECKED(audioUsageToHal(offload.usage, &halOffload->usage), result);
+ halOffload->encapsulation_mode =
+ static_cast<audio_encapsulation_mode_t>(offload.encapsulationMode);
+ halOffload->content_id = offload.contentId;
+ halOffload->sync_id = offload.syncId;
+ return result;
+}
+
+status_t HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
+ AudioPortConfig* config) {
+ status_t result = NO_ERROR;
+ bool isInput = false;
+ config->id = halConfig.id;
+ CONVERT_CHECKED(audioPortExtendedInfoFromHal(halConfig.role, halConfig.type,
+ halConfig.ext.device, halConfig.ext.mix,
+ halConfig.ext.session, &config->ext, &isInput),
+ result);
+ if (audio_port_config_has_input_direction(&halConfig) != isInput) {
+ ALOGE("Inconsistent port config direction data, is input: %d (hal) != %d (converter)",
+ audio_port_config_has_input_direction(&halConfig), isInput);
+ result = BAD_VALUE;
+ }
+ if (halConfig.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+ config->base.sampleRateHz = halConfig.sample_rate;
+ } else {
+ config->base.sampleRateHz = {};
+ }
+ if (halConfig.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+ CONVERT_CHECKED(
+ audioChannelMaskFromHal(halConfig.channel_mask, isInput, &config->base.channelMask),
+ result);
+ } else {
+ config->base.channelMask = {};
+ }
+ if (halConfig.config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+ CONVERT_CHECKED(audioFormatFromHal(halConfig.format, &config->base.format), result);
+ } else {
+ config->base.format = {};
+ }
+ if (halConfig.config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ config->gain.config({});
+ CONVERT_CHECKED(audioGainConfigFromHal(halConfig.gain, isInput, &config->gain.config()),
+ result);
+ } else {
+ config->gain.unspecified({});
+ }
+ return result;
+}
+
+status_t HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
+ struct audio_port_config* halConfig) {
+ status_t result = NO_ERROR;
+ memset(halConfig, 0, sizeof(audio_port_config));
+ halConfig->id = config.id;
+ halConfig->config_mask = {};
+ if (config.base.sampleRateHz != 0) {
+ halConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+ halConfig->sample_rate = config.base.sampleRateHz;
+ }
+ if (!config.base.channelMask.empty()) {
+ halConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ CONVERT_CHECKED(audioChannelMaskToHal(config.base.channelMask, &halConfig->channel_mask),
+ result);
+ }
+ if (!config.base.format.empty()) {
+ halConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+ CONVERT_CHECKED(audioFormatToHal(config.base.format, &halConfig->format), result);
+ }
+ if (config.gain.getDiscriminator() ==
+ AudioPortConfig::OptionalGain::hidl_discriminator::config) {
+ halConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+ CONVERT_CHECKED(audioGainConfigToHal(config.gain.config(), &halConfig->gain), result);
+ }
+ CONVERT_CHECKED(audioPortExtendedInfoToHal(config.ext, &halConfig->role, &halConfig->type,
+ &halConfig->ext.device, &halConfig->ext.mix,
+ &halConfig->ext.session),
+ result);
+ return result;
+}
+
+status_t HidlUtils::audioPortExtendedInfoFromHal(
+ audio_port_role_t role, audio_port_type_t type,
+ const struct audio_port_config_device_ext& device,
+ const struct audio_port_config_mix_ext& mix,
+ const struct audio_port_config_session_ext& session, AudioPortExtendedInfo* ext,
+ bool* isInput) {
+ status_t result = NO_ERROR;
+ *isInput = false;
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ ext->unspecified({});
+ break;
+ case AUDIO_PORT_TYPE_DEVICE: {
+ *isInput = role == AUDIO_PORT_ROLE_SOURCE;
+ ext->device({});
+ CONVERT_CHECKED(deviceAddressFromHal(device.type, device.address, &ext->device()),
+ result);
+ break;
+ }
+ case AUDIO_PORT_TYPE_MIX: {
+ *isInput = role == AUDIO_PORT_ROLE_SINK;
+ ext->mix({});
+ ext->mix().ioHandle = mix.handle;
+ if (role == AUDIO_PORT_ROLE_SOURCE) {
+ ext->mix().useCase.stream({});
+ CONVERT_CHECKED(
+ audioStreamTypeFromHal(mix.usecase.stream, &ext->mix().useCase.stream()),
+ result);
+ } else if (role == AUDIO_PORT_ROLE_SINK) {
+ ext->mix().useCase.source({});
+ CONVERT_CHECKED(
+ audioSourceFromHal(mix.usecase.source, &ext->mix().useCase.source()),
+ result);
+ }
+ break;
+ }
+ case AUDIO_PORT_TYPE_SESSION: {
+ ext->session(session.session);
+ break;
+ }
+ }
+ return result;
+}
+
+status_t HidlUtils::audioPortExtendedInfoToHal(const AudioPortExtendedInfo& ext,
+ audio_port_role_t* role, audio_port_type_t* type,
+ struct audio_port_config_device_ext* device,
+ struct audio_port_config_mix_ext* mix,
+ struct audio_port_config_session_ext* session) {
+ status_t result = NO_ERROR;
+ switch (ext.getDiscriminator()) {
+ case AudioPortExtendedInfo::hidl_discriminator::unspecified:
+ *role = AUDIO_PORT_ROLE_NONE;
+ *type = AUDIO_PORT_TYPE_NONE;
+ break;
+ case AudioPortExtendedInfo::hidl_discriminator::device:
+ *role = xsd::isOutputDevice(ext.device().deviceType) ? AUDIO_PORT_ROLE_SINK
+ : AUDIO_PORT_ROLE_SOURCE;
+ *type = AUDIO_PORT_TYPE_DEVICE;
+ CONVERT_CHECKED(deviceAddressToHal(ext.device(), &device->type, device->address),
+ result);
+ break;
+ case AudioPortExtendedInfo::hidl_discriminator::mix:
+ *type = AUDIO_PORT_TYPE_MIX;
+ switch (ext.mix().useCase.getDiscriminator()) {
+ case AudioPortExtendedInfo::AudioPortMixExt::UseCase::hidl_discriminator::stream:
+ *role = AUDIO_PORT_ROLE_SOURCE;
+ CONVERT_CHECKED(
+ audioStreamTypeToHal(ext.mix().useCase.stream(), &mix->usecase.stream),
+ result);
+ break;
+ case AudioPortExtendedInfo::AudioPortMixExt::UseCase::hidl_discriminator::source:
+ *role = AUDIO_PORT_ROLE_SINK;
+ CONVERT_CHECKED(
+ audioSourceToHal(ext.mix().useCase.source(), &mix->usecase.source),
+ result);
+ break;
+ }
+ mix->handle = ext.mix().ioHandle;
+ break;
+ case AudioPortExtendedInfo::hidl_discriminator::session:
+ *role = AUDIO_PORT_ROLE_NONE;
+ *type = AUDIO_PORT_TYPE_SESSION;
+ session->session = static_cast<audio_session_t>(ext.session());
+ break;
+ }
+ return result;
+}
+
+status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
+ struct audio_port_v7 halPortV7 = {};
+ audio_populate_audio_port_v7(&halPort, &halPortV7);
+ return audioPortFromHal(halPortV7, port);
+}
+
+status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
+ status_t result = NO_ERROR;
+ struct audio_port_v7 halPortV7 = {};
+ CONVERT_CHECKED(audioPortToHal(port, &halPortV7), result);
+ if (!audio_populate_audio_port(&halPortV7, halPort)) {
+ result = BAD_VALUE;
+ }
+ return result;
+}
+
+status_t HidlUtils::audioPortFromHal(const struct audio_port_v7& halPort, AudioPort* port) {
+ status_t result = NO_ERROR;
+ bool isInput = false;
+ port->id = halPort.id;
+ port->name.setToExternal(halPort.name, strlen(halPort.name));
+ // HAL uses slightly different but convertible structures for the extended info in port
+ // and port config structures.
+ struct audio_port_config_device_ext halDevice = {};
+ struct audio_port_config_mix_ext halMix = {};
+ struct audio_port_config_session_ext halSession = {};
+ switch (halPort.type) {
+ case AUDIO_PORT_TYPE_NONE:
+ break;
+ case AUDIO_PORT_TYPE_DEVICE:
+ halDevice.type = halPort.ext.device.type;
+ memcpy(halDevice.address, halPort.ext.device.address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ halMix.handle = halPort.ext.mix.handle;
+ break;
+ case AUDIO_PORT_TYPE_SESSION:
+ halSession.session = halPort.ext.session.session;
+ break;
+ }
+ CONVERT_CHECKED(audioPortExtendedInfoFromHal(halPort.role, halPort.type, halDevice, halMix,
+ halSession, &port->ext, &isInput),
+ result);
+ port->profiles.resize(halPort.num_audio_profiles);
+ for (size_t i = 0; i < halPort.num_audio_profiles; ++i) {
+ CONVERT_CHECKED(audioProfileFromHal(halPort.audio_profiles[i], isInput, &port->profiles[i]),
+ result);
+ }
+ port->gains.resize(halPort.num_gains);
+ for (size_t i = 0; i < halPort.num_gains; ++i) {
+ CONVERT_CHECKED(audioGainFromHal(halPort.gains[i], isInput, &port->gains[i]), result);
+ }
+ CONVERT_CHECKED(audioPortConfigFromHal(halPort.active_config, &port->activeConfig), result);
+ return result;
+}
+
+status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port_v7* halPort) {
+ status_t result = NO_ERROR;
+ halPort->id = port.id;
+ strncpy(halPort->name, port.name.c_str(), AUDIO_PORT_MAX_NAME_LEN);
+ halPort->name[AUDIO_PORT_MAX_NAME_LEN - 1] = '\0';
+ if (port.name.size() >= AUDIO_PORT_MAX_NAME_LEN) {
+ ALOGE("HIDL Audio Port name is too long: %zu", port.name.size());
+ result = BAD_VALUE;
+ }
+ halPort->num_audio_profiles = port.profiles.size();
+ if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) {
+ ALOGE("HIDL Audio Port has too many profiles: %u", halPort->num_audio_profiles);
+ halPort->num_audio_profiles = AUDIO_PORT_MAX_AUDIO_PROFILES;
+ result = BAD_VALUE;
+ }
+ for (size_t i = 0; i < halPort->num_audio_profiles; ++i) {
+ CONVERT_CHECKED(audioProfileToHal(port.profiles[i], &halPort->audio_profiles[i]), result);
+ }
+ halPort->num_gains = port.gains.size();
+ if (halPort->num_gains > AUDIO_PORT_MAX_GAINS) {
+ ALOGE("HIDL Audio Port has too many gains: %u", halPort->num_gains);
+ halPort->num_gains = AUDIO_PORT_MAX_GAINS;
+ result = BAD_VALUE;
+ }
+ for (size_t i = 0; i < halPort->num_gains; ++i) {
+ CONVERT_CHECKED(audioGainToHal(port.gains[i], &halPort->gains[i]), result);
+ }
+ // HAL uses slightly different but convertible structures for the extended info in port
+ // and port config structures.
+ struct audio_port_config_device_ext halDevice = {};
+ struct audio_port_config_mix_ext halMix = {};
+ struct audio_port_config_session_ext halSession = {};
+ CONVERT_CHECKED(audioPortExtendedInfoToHal(port.ext, &halPort->role, &halPort->type, &halDevice,
+ &halMix, &halSession),
+ result);
+ switch (halPort->type) {
+ case AUDIO_PORT_TYPE_NONE:
+ break;
+ case AUDIO_PORT_TYPE_DEVICE:
+ halPort->ext.device.type = halDevice.type;
+ memcpy(halPort->ext.device.address, halDevice.address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ halPort->ext.mix.handle = halMix.handle;
+ break;
+ case AUDIO_PORT_TYPE_SESSION:
+ halPort->ext.session.session = halSession.session;
+ break;
+ }
+ CONVERT_CHECKED(audioPortConfigToHal(port.activeConfig, &halPort->active_config), result);
+ return result;
+}
+
+status_t HidlUtils::audioProfileFromHal(const struct audio_profile& halProfile, bool isInput,
+ AudioProfile* profile) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioFormatFromHal(halProfile.format, &profile->format), result);
+ profile->sampleRates.resize(halProfile.num_sample_rates);
+ for (size_t i = 0; i < halProfile.num_sample_rates; ++i) {
+ profile->sampleRates[i] = halProfile.sample_rates[i];
+ }
+ profile->channelMasks.resize(halProfile.num_channel_masks);
+ for (size_t i = 0; i < halProfile.num_channel_masks; ++i) {
+ CONVERT_CHECKED(audioChannelMaskFromHal(halProfile.channel_masks[i], isInput,
+ &profile->channelMasks[i]),
+ result);
+ }
+ return result;
+}
+
+status_t HidlUtils::audioProfileToHal(const AudioProfile& profile,
+ struct audio_profile* halProfile) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioFormatToHal(profile.format, &halProfile->format), result);
+ memset(halProfile->sample_rates, 0, sizeof(halProfile->sample_rates));
+ halProfile->num_sample_rates = profile.sampleRates.size();
+ if (halProfile->num_sample_rates > AUDIO_PORT_MAX_SAMPLING_RATES) {
+ ALOGE("HIDL Audio profile has too many sample rates: %u", halProfile->num_sample_rates);
+ halProfile->num_sample_rates = AUDIO_PORT_MAX_SAMPLING_RATES;
+ result = BAD_VALUE;
+ }
+ for (size_t i = 0; i < halProfile->num_sample_rates; ++i) {
+ halProfile->sample_rates[i] = profile.sampleRates[i];
+ }
+ memset(halProfile->channel_masks, 0, sizeof(halProfile->channel_masks));
+ halProfile->num_channel_masks = profile.channelMasks.size();
+ if (halProfile->num_channel_masks > AUDIO_PORT_MAX_CHANNEL_MASKS) {
+ ALOGE("HIDL Audio profile has too many channel masks: %u", halProfile->num_channel_masks);
+ halProfile->num_channel_masks = AUDIO_PORT_MAX_CHANNEL_MASKS;
+ result = BAD_VALUE;
+ }
+ for (size_t i = 0; i < halProfile->num_channel_masks; ++i) {
+ CONVERT_CHECKED(
+ audioChannelMaskToHal(profile.channelMasks[i], &halProfile->channel_masks[i]),
+ status);
+ }
+ return result;
+}
+
+status_t HidlUtils::deviceAddressFromHal(audio_devices_t halDeviceType,
+ const char* halDeviceAddress, DeviceAddress* device) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioDeviceTypeFromHal(halDeviceType, &device->deviceType), result);
+ if (audio_is_a2dp_out_device(halDeviceType) || audio_is_a2dp_in_device(halDeviceType)) {
+ device->address.mac({});
+ if (halDeviceAddress != nullptr) {
+ auto& mac = device->address.mac();
+ int status = sscanf(halDeviceAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &mac[0], &mac[1],
+ &mac[2], &mac[3], &mac[4], &mac[5]);
+ if (status != 6) {
+ ALOGE("BT A2DP device \"%s\" MAC address \"%s\" is invalid",
+ device->deviceType.c_str(), halDeviceAddress);
+ result = BAD_VALUE;
+ }
+ } else {
+ ALOGE("BT A2DP device \"%s\" does not have a MAC address", halDeviceAddress);
+ result = BAD_VALUE;
+ }
+ } else if (halDeviceType == AUDIO_DEVICE_OUT_IP || halDeviceType == AUDIO_DEVICE_IN_IP) {
+ device->address.ipv4({});
+ if (halDeviceAddress != nullptr) {
+ auto& ipv4 = device->address.ipv4();
+ int status = sscanf(halDeviceAddress, "%hhu.%hhu.%hhu.%hhu", &ipv4[0], &ipv4[1],
+ &ipv4[2], &ipv4[3]);
+ if (status != 4) {
+ ALOGE("IP device \"%s\" IPv4 address \"%s\" is invalid", device->deviceType.c_str(),
+ halDeviceAddress);
+ result = BAD_VALUE;
+ }
+ } else {
+ ALOGE("IP device \"%s\" does not have an IPv4 address", device->deviceType.c_str());
+ result = BAD_VALUE;
+ }
+ } else if (audio_is_usb_out_device(halDeviceType) || audio_is_usb_in_device(halDeviceType)) {
+ device->address.alsa({});
+ if (halDeviceAddress != nullptr) {
+ auto& alsa = device->address.alsa();
+ int status = sscanf(halDeviceAddress, "card=%d;device=%d", &alsa.card, &alsa.device);
+ if (status != 2) {
+ ALOGE("USB device \"%s\" ALSA address \"%s\" is invalid",
+ device->deviceType.c_str(), halDeviceAddress);
+ result = BAD_VALUE;
+ }
+ } else {
+ ALOGE("USB device \"%s\" does not have ALSA address", device->deviceType.c_str());
+ result = BAD_VALUE;
+ }
+ } else {
+ // Any other device type uses the 'id' field.
+ device->address.id(halDeviceAddress != nullptr ? halDeviceAddress : "");
+ }
+ return result;
+}
+
+status_t HidlUtils::deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
+ char* halDeviceAddress) {
+ status_t result = NO_ERROR;
+ CONVERT_CHECKED(audioDeviceTypeToHal(device.deviceType, halDeviceType), result);
+ memset(halDeviceAddress, 0, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ if (audio_is_a2dp_out_device(*halDeviceType) || audio_is_a2dp_in_device(*halDeviceType)) {
+ if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::mac) {
+ const auto& mac = device.address.mac();
+ snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+ "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4],
+ mac[5]);
+ } else {
+ ALOGE("BT A2DP device \"%s\" does not have MAC address set", device.deviceType.c_str());
+ result = BAD_VALUE;
+ }
+ } else if (*halDeviceType == AUDIO_DEVICE_OUT_IP || *halDeviceType == AUDIO_DEVICE_IN_IP) {
+ if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::ipv4) {
+ const auto& ipv4 = device.address.ipv4();
+ snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%d.%d.%d.%d", ipv4[0],
+ ipv4[1], ipv4[2], ipv4[3]);
+ } else {
+ ALOGE("IP device \"%s\" does not have IPv4 address set", device.deviceType.c_str());
+ result = BAD_VALUE;
+ }
+ } else if (audio_is_usb_out_device(*halDeviceType) || audio_is_usb_in_device(*halDeviceType)) {
+ if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::alsa) {
+ const auto& alsa = device.address.alsa();
+ snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "card=%d;device=%d", alsa.card,
+ alsa.device);
+ } else {
+ ALOGE("USB device \"%s\" does not have ALSA address set", device.deviceType.c_str());
+ result = BAD_VALUE;
+ }
+ } else {
+ // Any other device type uses the 'id' field.
+ if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::id) {
+ snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s",
+ device.address.id().c_str());
+ }
+ }
+ return result;
+}
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace common
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index a72c8dc..b83a58a 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -39,14 +39,19 @@
],
}
+filegroup {
+ name: "android.hardware.audio.common-util@2-6",
+ srcs: [
+ "HidlUtils.cpp",
+ "UuidUtils.cpp",
+ ],
+}
+
cc_defaults {
name: "android.hardware.audio.common-util_default",
defaults: ["hidl_defaults"],
vendor_available: true,
- srcs: [
- "HidlUtils.cpp",
- ],
export_include_dirs: ["."],
@@ -69,6 +74,7 @@
cc_library_shared {
name: "android.hardware.audio.common@2.0-util",
defaults: ["android.hardware.audio.common-util_default"],
+ srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [
"android.hardware.audio.common@2.0",
],
@@ -82,6 +88,7 @@
cc_library_shared {
name: "android.hardware.audio.common@4.0-util",
defaults: ["android.hardware.audio.common-util_default"],
+ srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [
"android.hardware.audio.common@4.0",
],
@@ -95,6 +102,7 @@
cc_library_shared {
name: "android.hardware.audio.common@5.0-util",
defaults: ["android.hardware.audio.common-util_default"],
+ srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [
"android.hardware.audio.common@5.0",
],
@@ -108,6 +116,7 @@
cc_library_shared {
name: "android.hardware.audio.common@6.0-util",
defaults: ["android.hardware.audio.common-util_default"],
+ srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [
"android.hardware.audio.common@6.0",
],
@@ -118,12 +127,18 @@
],
}
-cc_library_shared {
- enabled: false,
+cc_library {
name: "android.hardware.audio.common@7.0-util",
defaults: ["android.hardware.audio.common-util_default"],
+ srcs: [
+ "7.0/HidlUtils.cpp",
+ "UuidUtils.cpp",
+ ],
shared_libs: [
"android.hardware.audio.common@7.0",
+ "android.hardware.audio.common@7.0-enums",
+ "libbase",
+ "libxml2",
],
cflags: [
"-DMAJOR_VERSION=7",
@@ -131,3 +146,35 @@
"-include common/all-versions/VersionMacro.h",
],
}
+
+// Note: this isn't a VTS test, but rather a unit test
+// to verify correctness of conversion utilities.
+cc_test {
+ name: "android.hardware.audio.common@7.0-util_tests",
+ defaults: ["android.hardware.audio.common-util_default"],
+
+ srcs: ["tests/hidlutils_tests.cpp"],
+
+ // Use static linking to allow running in presubmit on
+ // targets that don't have HAL V7.
+ static_libs: [
+ "android.hardware.audio.common@7.0-enums",
+ "android.hardware.audio.common@7.0-util",
+ "android.hardware.audio.common@7.0",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libxml2",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-DMAJOR_VERSION=7",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/audio/common/all-versions/default/HidlUtils.cpp b/audio/common/all-versions/default/HidlUtils.cpp
index a470c9c..ab3c1c7 100644
--- a/audio/common/all-versions/default/HidlUtils.cpp
+++ b/audio/common/all-versions/default/HidlUtils.cpp
@@ -37,13 +37,14 @@
return status;
}
-void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
+status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
memset(halConfig, 0, sizeof(audio_config_t));
halConfig->sample_rate = config.sampleRateHz;
halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
halConfig->format = static_cast<audio_format_t>(config.format);
audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info);
halConfig->frame_count = config.frameCount;
+ return NO_ERROR;
}
void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig,
@@ -57,8 +58,8 @@
config->rampDurationMs = halConfig.ramp_duration_ms;
}
-void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
- struct audio_gain_config* halConfig) {
+status_t HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
+ struct audio_gain_config* halConfig) {
halConfig->index = config.index;
halConfig->mode = static_cast<audio_gain_mode_t>(config.mode);
halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
@@ -67,6 +68,7 @@
halConfig->values[i] = config.values[i];
}
halConfig->ramp_duration_ms = config.rampDurationMs;
+ return NO_ERROR;
}
void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) {
@@ -80,7 +82,7 @@
gain->maxRampMs = halGain.max_ramp_ms;
}
-void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
+status_t HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
halGain->mode = static_cast<audio_gain_mode_t>(gain.mode);
halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask);
halGain->min_value = gain.minValue;
@@ -89,22 +91,26 @@
halGain->step_value = gain.stepValue;
halGain->min_ramp_ms = gain.minRampMs;
halGain->max_ramp_ms = gain.maxRampMs;
+ return NO_ERROR;
}
-AudioUsage HidlUtils::audioUsageFromHal(const audio_usage_t halUsage) {
+status_t HidlUtils::audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage) {
switch (halUsage) {
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case AUDIO_USAGE_NOTIFICATION_EVENT:
- return AudioUsage::NOTIFICATION;
+ *usage = AudioUsage::NOTIFICATION;
+ break;
default:
- return static_cast<AudioUsage>(halUsage);
+ *usage = static_cast<AudioUsage>(halUsage);
}
+ return NO_ERROR;
}
-audio_usage_t HidlUtils::audioUsageToHal(const AudioUsage usage) {
- return static_cast<audio_usage_t>(usage);
+status_t HidlUtils::audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage) {
+ *halUsage = static_cast<audio_usage_t>(usage);
+ return NO_ERROR;
}
status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
@@ -119,7 +125,7 @@
offload->isStreaming = halOffload.is_streaming;
offload->bitWidth = halOffload.bit_width;
offload->bufferSize = halOffload.offload_buffer_size;
- offload->usage = audioUsageFromHal(halOffload.usage);
+ audioUsageFromHal(halOffload.usage, &offload->usage);
#if MAJOR_VERSION >= 6
if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) {
offload->encapsulationMode =
@@ -139,11 +145,11 @@
return BAD_VALUE;
}
#endif
- return OK;
+ return NO_ERROR;
}
-void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
- audio_offload_info_t* halOffload) {
+status_t HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
+ audio_offload_info_t* halOffload) {
*halOffload = AUDIO_INFO_INITIALIZER;
halOffload->sample_rate = offload.sampleRateHz;
halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask);
@@ -155,7 +161,7 @@
halOffload->is_streaming = offload.isStreaming;
halOffload->bit_width = offload.bitWidth;
halOffload->offload_buffer_size = offload.bufferSize;
- halOffload->usage = audioUsageToHal(offload.usage);
+ audioUsageToHal(offload.usage, &halOffload->usage);
#if MAJOR_VERSION >= 6
halOffload->encapsulation_mode =
static_cast<audio_encapsulation_mode_t>(offload.encapsulationMode);
@@ -164,10 +170,11 @@
#else
// offload doesn't contain encapsulationMode, contentId, syncId, so this is OK.
#endif
+ return NO_ERROR;
}
-void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
- AudioPortConfig* config) {
+status_t HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
+ AudioPortConfig* config) {
config->id = halConfig.id;
config->role = AudioPortRole(halConfig.role);
config->type = AudioPortType(halConfig.type);
@@ -201,10 +208,11 @@
break;
}
}
+ return NO_ERROR;
}
-void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
- struct audio_port_config* halConfig) {
+status_t HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
+ struct audio_port_config* halConfig) {
memset(halConfig, 0, sizeof(audio_port_config));
halConfig->id = config.id;
halConfig->role = static_cast<audio_port_role_t>(config.role);
@@ -242,27 +250,10 @@
break;
}
}
+ return NO_ERROR;
}
-void HidlUtils::audioPortConfigsFromHal(unsigned int numHalConfigs,
- const struct audio_port_config* halConfigs,
- hidl_vec<AudioPortConfig>* configs) {
- configs->resize(numHalConfigs);
- for (unsigned int i = 0; i < numHalConfigs; ++i) {
- audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
- }
-}
-
-std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal(
- const hidl_vec<AudioPortConfig>& configs) {
- std::unique_ptr<audio_port_config[]> halConfigs(new audio_port_config[configs.size()]);
- for (size_t i = 0; i < configs.size(); ++i) {
- audioPortConfigToHal(configs[i], &halConfigs[i]);
- }
- return halConfigs;
-}
-
-void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
+status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
port->id = halPort.id;
port->role = AudioPortRole(halPort.role);
port->type = AudioPortType(halPort.type);
@@ -305,9 +296,10 @@
break;
}
}
+ return NO_ERROR;
}
-void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
+status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
memset(halPort, 0, sizeof(audio_port));
halPort->id = port.id;
halPort->role = static_cast<audio_port_role_t>(port.role);
@@ -356,22 +348,7 @@
break;
}
}
-}
-
-void HidlUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) {
- uuid->timeLow = halUuid.timeLow;
- uuid->timeMid = halUuid.timeMid;
- uuid->versionAndTimeHigh = halUuid.timeHiAndVersion;
- uuid->variantAndClockSeqHigh = halUuid.clockSeq;
- memcpy(uuid->node.data(), halUuid.node, uuid->node.size());
-}
-
-void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) {
- halUuid->timeLow = uuid.timeLow;
- halUuid->timeMid = uuid.timeMid;
- halUuid->timeHiAndVersion = uuid.versionAndTimeHigh;
- halUuid->clockSeq = uuid.variantAndClockSeqHigh;
- memcpy(halUuid->node, uuid.node.data(), uuid.node.size());
+ return NO_ERROR;
}
} // namespace implementation
diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h
index ef6dee3..4e609ca 100644
--- a/audio/common/all-versions/default/HidlUtils.h
+++ b/audio/common/all-versions/default/HidlUtils.h
@@ -34,40 +34,123 @@
using namespace ::android::hardware::audio::common::CPP_VERSION;
-class HidlUtils {
- public:
- // A failure here indicates a platform config that is incompatible with
- // the compiled HIDL interface version.
+struct HidlUtils {
+#if MAJOR_VERSION < 7
static status_t audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
-
- static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
static void audioGainConfigFromHal(const struct audio_gain_config& halConfig,
AudioGainConfig* config);
- static void audioGainConfigToHal(const AudioGainConfig& config,
- struct audio_gain_config* halConfig);
static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain);
- static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
- static AudioUsage audioUsageFromHal(const audio_usage_t halUsage);
- static audio_usage_t audioUsageToHal(const AudioUsage usage);
- // A failure here indicates a platform offload info that is incompatible with
- // the compiled HIDL interface version.
+#else
+ static status_t audioConfigFromHal(const audio_config_t& halConfig, bool isInput,
+ AudioConfig* config);
+ static status_t audioGainConfigFromHal(const struct audio_gain_config& halConfig, bool isInput,
+ AudioGainConfig* config);
+ static status_t audioGainFromHal(const struct audio_gain& halGain, bool isInput,
+ AudioGain* gain);
+#endif
+ static status_t audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
+ static status_t audioGainConfigToHal(const AudioGainConfig& config,
+ struct audio_gain_config* halConfig);
+ static status_t audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
+ static status_t audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage);
+ static status_t audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage);
static status_t audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
AudioOffloadInfo* offload);
- static void audioOffloadInfoToHal(const AudioOffloadInfo& offload,
- audio_offload_info_t* halOffload);
- static void audioPortConfigFromHal(const struct audio_port_config& halConfig,
- AudioPortConfig* config);
- static void audioPortConfigToHal(const AudioPortConfig& config,
- struct audio_port_config* halConfig);
- static void audioPortConfigsFromHal(unsigned int numHalConfigs,
- const struct audio_port_config* halConfigs,
- hidl_vec<AudioPortConfig>* configs);
+ static status_t audioOffloadInfoToHal(const AudioOffloadInfo& offload,
+ audio_offload_info_t* halOffload);
+ static status_t audioPortConfigFromHal(const struct audio_port_config& halConfig,
+ AudioPortConfig* config);
+ static status_t audioPortConfigToHal(const AudioPortConfig& config,
+ struct audio_port_config* halConfig);
+ static status_t audioPortConfigsFromHal(unsigned int numHalConfigs,
+ const struct audio_port_config* halConfigs,
+ hidl_vec<AudioPortConfig>* configs) {
+ status_t result = NO_ERROR;
+ configs->resize(numHalConfigs);
+ for (unsigned int i = 0; i < numHalConfigs; ++i) {
+ if (status_t status = audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
+ status != NO_ERROR) {
+ result = status;
+ }
+ }
+ return result;
+ }
+ static status_t audioPortConfigsToHal(const hidl_vec<AudioPortConfig>& configs,
+ std::unique_ptr<audio_port_config[]>* halConfigs) {
+ status_t result = NO_ERROR;
+ halConfigs->reset(new audio_port_config[configs.size()]);
+ for (size_t i = 0; i < configs.size(); ++i) {
+ if (status_t status = audioPortConfigToHal(configs[i], &(*halConfigs)[i]);
+ status != NO_ERROR) {
+ result = status;
+ }
+ }
+ return result;
+ }
+
+ // PLEASE DO NOT USE, will be removed in a couple of days
static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
- const hidl_vec<AudioPortConfig>& configs);
- static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
- static void audioPortToHal(const AudioPort& port, struct audio_port* halPort);
- static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
- static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid);
+ const hidl_vec<AudioPortConfig>& configs) {
+ std::unique_ptr<audio_port_config[]> halConfigs;
+ (void)audioPortConfigsToHal(configs, &halConfigs);
+ return halConfigs;
+ }
+
+ static status_t audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
+ static status_t audioPortToHal(const AudioPort& port, struct audio_port* halPort);
+#if MAJOR_VERSION >= 7
+ static status_t audioChannelMaskFromHal(audio_channel_mask_t halChannelMask, bool isInput,
+ AudioChannelMask* channelMask);
+ static status_t audioChannelMaskToHal(const AudioChannelMask& channelMask,
+ audio_channel_mask_t* halChannelMask);
+ static status_t audioConfigBaseFromHal(const audio_config_base_t& halConfigBase, bool isInput,
+ AudioConfigBase* configBase);
+ static status_t audioConfigBaseToHal(const AudioConfigBase& configBase,
+ audio_config_base_t* halConfigBase);
+ static status_t audioDeviceTypeFromHal(audio_devices_t halDevice, AudioDevice* device);
+ static status_t audioDeviceTypeToHal(const AudioDevice& device, audio_devices_t* halDevice);
+ static status_t audioFormatFromHal(audio_format_t halFormat, AudioFormat* format);
+ static status_t audioFormatToHal(const AudioFormat& format, audio_format_t* halFormat);
+ static status_t audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask,
+ hidl_vec<AudioGainMode>* gainModeMask);
+ static status_t audioGainModeMaskToHal(const hidl_vec<AudioGainMode>& gainModeMask,
+ audio_gain_mode_t* halGainModeMask);
+ static status_t audioPortFromHal(const struct audio_port_v7& halPort, AudioPort* port);
+ static status_t audioPortToHal(const AudioPort& port, struct audio_port_v7* halPort);
+ static status_t audioProfileFromHal(const struct audio_profile& halProfile, bool isInput,
+ AudioProfile* profile);
+ static status_t audioProfileToHal(const AudioProfile& profile,
+ struct audio_profile* halProfile);
+ static status_t audioSourceFromHal(audio_source_t halSource, AudioSource* source);
+ static status_t audioSourceToHal(const AudioSource& source, audio_source_t* halSource);
+ static status_t audioStreamTypeFromHal(audio_stream_type_t halStreamType,
+ AudioStreamType* streamType);
+ static status_t audioStreamTypeToHal(const AudioStreamType& streamType,
+ audio_stream_type_t* halStreamType);
+ static status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
+ char* halDeviceAddress);
+ static status_t deviceAddressFromHal(audio_devices_t halDeviceType,
+ const char* halDeviceAddress, DeviceAddress* device);
+
+ private:
+ static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask);
+ static status_t audioInputChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask);
+ static status_t audioOutputChannelMaskFromHal(audio_channel_mask_t halChannelMask,
+ AudioChannelMask* channelMask);
+ static status_t audioPortExtendedInfoFromHal(
+ audio_port_role_t role, audio_port_type_t type,
+ const struct audio_port_config_device_ext& device,
+ const struct audio_port_config_mix_ext& mix,
+ const struct audio_port_config_session_ext& session, AudioPortExtendedInfo* ext,
+ bool* isInput);
+ static status_t audioPortExtendedInfoToHal(const AudioPortExtendedInfo& ext,
+ audio_port_role_t* role, audio_port_type_t* type,
+ struct audio_port_config_device_ext* device,
+ struct audio_port_config_mix_ext* mix,
+ struct audio_port_config_session_ext* session);
+#endif
};
} // namespace implementation
diff --git a/audio/common/all-versions/default/TEST_MAPPING b/audio/common/all-versions/default/TEST_MAPPING
new file mode 100644
index 0000000..4316ccf
--- /dev/null
+++ b/audio/common/all-versions/default/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "android.hardware.audio.common@7.0-util_tests"
+ }
+ ]
+}
diff --git a/audio/common/all-versions/default/UuidUtils.cpp b/audio/common/all-versions/default/UuidUtils.cpp
new file mode 100644
index 0000000..85edc7b
--- /dev/null
+++ b/audio/common/all-versions/default/UuidUtils.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "UuidUtils.h"
+
+#include <common/all-versions/VersionUtils.h>
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace CPP_VERSION {
+namespace implementation {
+
+void UuidUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) {
+ uuid->timeLow = halUuid.timeLow;
+ uuid->timeMid = halUuid.timeMid;
+ uuid->versionAndTimeHigh = halUuid.timeHiAndVersion;
+ uuid->variantAndClockSeqHigh = halUuid.clockSeq;
+ memcpy(uuid->node.data(), halUuid.node, uuid->node.size());
+}
+
+void UuidUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) {
+ halUuid->timeLow = uuid.timeLow;
+ halUuid->timeMid = uuid.timeMid;
+ halUuid->timeHiAndVersion = uuid.versionAndTimeHigh;
+ halUuid->clockSeq = uuid.variantAndClockSeqHigh;
+ memcpy(halUuid->node, uuid.node.data(), uuid.node.size());
+}
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace common
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/common/all-versions/default/UuidUtils.h b/audio/common/all-versions/default/UuidUtils.h
new file mode 100644
index 0000000..38db48a
--- /dev/null
+++ b/audio/common/all-versions/default/UuidUtils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef android_hardware_audio_Uuid_Utils_H_
+#define android_hardware_audio_Uuid_Utils_H_
+
+// clang-format off
+#include PATH(android/hardware/audio/common/FILE_VERSION/types.h)
+// clang-format on
+
+#include <system/audio.h>
+
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace CPP_VERSION {
+namespace implementation {
+
+using namespace ::android::hardware::audio::common::CPP_VERSION;
+
+class UuidUtils {
+ public:
+ static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
+ static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid);
+};
+
+} // namespace implementation
+} // namespace CPP_VERSION
+} // namespace common
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_audio_Uuid_Utils_H_
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
new file mode 100644
index 0000000..bfc99e6
--- /dev/null
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <array>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#define LOG_TAG "HidlUtils_Test"
+#include <log/log.h>
+
+#include <HidlUtils.h>
+#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <system/audio.h>
+#include <xsdc/XsdcSupport.h>
+
+using namespace android;
+using namespace ::android::hardware::audio::common::CPP_VERSION;
+using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+namespace xsd {
+using namespace ::android::audio::policy::configuration::V7_0;
+}
+
+static constexpr audio_channel_mask_t kInvalidHalChannelMask =
+ static_cast<audio_channel_mask_t>(0xFFFFFFFFU);
+static constexpr audio_devices_t kInvalidHalDevice = static_cast<audio_devices_t>(0xFFFFFFFFU);
+static constexpr audio_format_t kInvalidHalFormat = static_cast<audio_format_t>(0xFFFFFFFFU);
+static constexpr audio_gain_mode_t kInvalidHalGainMode =
+ static_cast<audio_gain_mode_t>(0xFFFFFFFFU);
+static constexpr audio_source_t kInvalidHalSource = static_cast<audio_source_t>(0xFFFFFFFFU);
+static constexpr audio_stream_type_t kInvalidHalStreamType =
+ static_cast<audio_stream_type_t>(0xFFFFFFFFU);
+static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(0xFFFFFFFFU);
+
+TEST(HidlUtils, ConvertInvalidChannelMask) {
+ AudioChannelMask invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(AUDIO_CHANNEL_INVALID,
+ false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(AUDIO_CHANNEL_INVALID, true /*isInput*/,
+ &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(kInvalidHalChannelMask,
+ false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(kInvalidHalChannelMask,
+ true /*isInput*/, &invalid));
+ audio_channel_mask_t halInvalid;
+ // INVALID channel mask is not in XSD thus it's not allowed for transfer over HIDL.
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskToHal("AUDIO_CHANNEL_INVALID", &halInvalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskToHal("random string", &halInvalid));
+}
+
+// Might move these to the audio_policy_configuration_V7_0-enums library
+// if there would be usages in the default wrapper code. In that case,
+// it would be better to reimplement these methods using a proper switch statement
+// over all known enum values.
+static bool isInputChannelMask(xsd::AudioChannelMask channelMask) {
+ return toString(channelMask).find("_CHANNEL_IN_") != std::string::npos;
+}
+
+static bool isOutputChannelMask(xsd::AudioChannelMask channelMask) {
+ return toString(channelMask).find("_CHANNEL_OUT_") != std::string::npos;
+}
+
+static bool isIndexChannelMask(xsd::AudioChannelMask channelMask) {
+ return toString(channelMask).find("_CHANNEL_INDEX_") != std::string::npos;
+}
+
+TEST(HidlUtils, ConvertChannelMask) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioChannelMask>{}) {
+ const AudioChannelMask channelMask = toString(enumVal);
+ audio_channel_mask_t halChannelMask, halChannelMaskBack;
+ AudioChannelMask channelMaskBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskToHal(channelMask, &halChannelMask))
+ << "Conversion of \"" << channelMask << "\" failed";
+ EXPECT_EQ(enumVal != xsd::AudioChannelMask::AUDIO_CHANNEL_NONE,
+ audio_channel_mask_is_valid(halChannelMask))
+ << "Validity of \"" << channelMask << "\" is not as expected";
+ if (bool isInput = isInputChannelMask(enumVal); isInput || isOutputChannelMask(enumVal)) {
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioChannelMaskFromHal(halChannelMask, isInput, &channelMaskBack))
+ << "Conversion of " << (isInput ? "input" : "output") << " channel mask "
+ << halChannelMask << " failed";
+ // Due to aliased values, the result of 'fromHal' might not be the same
+ // as 'channelMask', thus we need to compare the results of 'toHal' conversion instead.
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioChannelMaskToHal(channelMaskBack, &halChannelMaskBack))
+ << "Conversion of \"" << channelMaskBack << "\" failed";
+ EXPECT_EQ(halChannelMask, halChannelMaskBack);
+ } else if (isIndexChannelMask(enumVal) ||
+ enumVal == xsd::AudioChannelMask::AUDIO_CHANNEL_NONE) {
+ // Conversions for indexed masks and "none" must not depend on the provided direction.
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskFromHal(halChannelMask, true /*isInput*/,
+ &channelMaskBack))
+ << "Conversion of indexed / none channel mask " << halChannelMask
+ << " failed (as input channel mask)";
+ EXPECT_EQ(channelMask, channelMaskBack);
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskFromHal(
+ halChannelMask, false /*isInput*/, &channelMaskBack))
+ << "Conversion of indexed / none channel mask " << halChannelMask
+ << " failed (as output channel mask)";
+ EXPECT_EQ(channelMask, channelMaskBack);
+ } else {
+ FAIL() << "Unrecognized channel mask \"" << channelMask << "\"";
+ }
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidConfigBase) {
+ AudioConfigBase invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseFromHal({.sample_rate = 0,
+ .channel_mask = kInvalidHalChannelMask,
+ .format = kInvalidHalFormat},
+ false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseFromHal({.sample_rate = 0,
+ .channel_mask = kInvalidHalChannelMask,
+ .format = kInvalidHalFormat},
+ true /*isInput*/, &invalid));
+ audio_config_base_t halInvalid;
+ invalid.sampleRateHz = 0;
+ invalid.channelMask = "random string";
+ invalid.format = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertConfigBase) {
+ AudioConfigBase configBase;
+ configBase.sampleRateHz = 44100;
+ configBase.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ configBase.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ audio_config_base_t halConfigBase;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigBaseToHal(configBase, &halConfigBase));
+ AudioConfigBase configBaseBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioConfigBaseFromHal(halConfigBase, false /*isInput*/, &configBaseBack));
+ EXPECT_EQ(configBase, configBaseBack);
+}
+
+TEST(HidlUtils, ConvertInvalidDeviceType) {
+ AudioDevice invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioDeviceTypeFromHal(kInvalidHalDevice, &invalid));
+ audio_devices_t halInvalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioDeviceTypeToHal("random string", &halInvalid));
+}
+
+TEST(HidlUtils, ConvertDeviceType) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioDevice>{}) {
+ const AudioDevice deviceType = toString(enumVal);
+ audio_devices_t halDeviceType, halDeviceTypeBack;
+ AudioDevice deviceTypeBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeToHal(deviceType, &halDeviceType))
+ << "Conversion of \"" << deviceType << "\" failed";
+ if (enumVal != xsd::AudioDevice::AUDIO_DEVICE_NONE) {
+ EXPECT_TRUE(audio_is_input_device(halDeviceType) ||
+ audio_is_output_device(halDeviceType))
+ << "Device \"" << deviceType << "\" is neither input, nor output device";
+ } else {
+ EXPECT_FALSE(audio_is_input_device(halDeviceType));
+ EXPECT_FALSE(audio_is_output_device(halDeviceType));
+ }
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeFromHal(halDeviceType, &deviceTypeBack))
+ << "Conversion of device type " << halDeviceType << " failed";
+ // Due to aliased values, the result of 'fromHal' might not be the same
+ // as 'deviceType', thus we need to compare the results of 'toHal' conversion instead.
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeToHal(deviceTypeBack, &halDeviceTypeBack))
+ << "Conversion of \"" << deviceTypeBack << "\" failed";
+ EXPECT_EQ(halDeviceType, halDeviceTypeBack);
+ }
+}
+
+// The enums module is too small to have unit tests on its own.
+TEST(HidlUtils, VendorExtension) {
+ EXPECT_TRUE(xsd::isVendorExtension("VX_GOOGLE_VR_42"));
+ EXPECT_FALSE(xsd::isVendorExtension("random string"));
+ EXPECT_FALSE(xsd::isVendorExtension("VX_"));
+ EXPECT_FALSE(xsd::isVendorExtension("VX_GOOGLE_$$"));
+}
+
+TEST(HidlUtils, ConvertInvalidDeviceAddress) {
+ DeviceAddress invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
+ nullptr, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
+ "", &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_IP, nullptr, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_IP, "", &invalid));
+ EXPECT_EQ(BAD_VALUE,
+ HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_USB_HEADSET, nullptr, &invalid));
+ EXPECT_EQ(BAD_VALUE,
+ HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_USB_HEADSET, "", &invalid));
+
+ audio_devices_t halInvalid;
+ char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {};
+ invalid = {};
+ invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress));
+ invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_IP);
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress));
+ invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET);
+ EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress));
+}
+
+static void ConvertDeviceAddress(const DeviceAddress& device) {
+ audio_devices_t halDeviceType;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {};
+ EXPECT_EQ(NO_ERROR, HidlUtils::deviceAddressToHal(device, &halDeviceType, halDeviceAddress));
+ DeviceAddress deviceBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, &deviceBack));
+ EXPECT_EQ(device, deviceBack);
+}
+
+TEST(HidlUtils, ConvertUniqueDeviceAddress) {
+ DeviceAddress speaker;
+ speaker.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER);
+ ConvertDeviceAddress(speaker);
+}
+
+TEST(HidlUtils, ConvertA2dpDeviceAddress) {
+ DeviceAddress a2dpSpeaker;
+ a2dpSpeaker.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ a2dpSpeaker.address.mac(std::array<uint8_t, 6>{1, 2, 3, 4, 5, 6});
+ ConvertDeviceAddress(a2dpSpeaker);
+}
+
+TEST(HidlUtils, ConvertIpv4DeviceAddress) {
+ DeviceAddress ipv4;
+ ipv4.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_IP);
+ ipv4.address.ipv4(std::array<uint8_t, 4>{1, 2, 3, 4});
+ ConvertDeviceAddress(ipv4);
+}
+
+TEST(HidlUtils, ConvertUsbDeviceAddress) {
+ DeviceAddress usbHeadset;
+ usbHeadset.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET);
+ usbHeadset.address.alsa({1, 2});
+ ConvertDeviceAddress(usbHeadset);
+}
+
+TEST(HidlUtils, ConvertBusDeviceAddress) {
+ DeviceAddress bus;
+ bus.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS);
+ bus.address.id("bus_device");
+ ConvertDeviceAddress(bus);
+}
+
+TEST(HidlUtils, ConvertRSubmixDeviceAddress) {
+ DeviceAddress rSubmix;
+ rSubmix.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_REMOTE_SUBMIX);
+ rSubmix.address.id(AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ ConvertDeviceAddress(rSubmix);
+}
+
+TEST(HidlUtils, ConvertVendorDeviceAddress) {
+ // The address part is not mandatory, both cases must work.
+ {
+ DeviceAddress vendor;
+ vendor.deviceType = "VX_GOOGLE_VR";
+ audio_devices_t halDeviceType;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {};
+ // Ignore the result. Vendors will also add the extended device into
+ // the list of devices in audio-hal-enums.h. Without that, the conversion
+ // officially fails, but it still maps the device type to NONE.
+ (void)HidlUtils::deviceAddressToHal(vendor, &halDeviceType, halDeviceAddress);
+ EXPECT_EQ(AUDIO_DEVICE_NONE, halDeviceType);
+ EXPECT_EQ(0, strnlen(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN));
+ }
+ {
+ DeviceAddress vendor;
+ vendor.deviceType = "VX_GOOGLE_VR";
+ vendor.address.id("vr1");
+ audio_devices_t halDeviceType;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {};
+ // Ignore the result. Vendors will also add the extended device into
+ // the list of devices in audio-hal-enums.h. Without that, the conversion
+ // officially fails, but it still maps the device type to NONE and converts
+ // the address.
+ (void)HidlUtils::deviceAddressToHal(vendor, &halDeviceType, halDeviceAddress);
+ EXPECT_EQ(AUDIO_DEVICE_NONE, halDeviceType);
+ EXPECT_EQ(0, strncmp("vr1", halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN));
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidFormat) {
+ AudioFormat invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioFormatFromHal(kInvalidHalFormat, &invalid));
+ audio_format_t halInvalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioFormatToHal("random string", &halInvalid));
+}
+
+TEST(HidlUtils, ConvertFormat) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioFormat>{}) {
+ const AudioFormat format = toString(enumVal);
+ audio_format_t halFormat;
+ AudioFormat formatBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioFormatToHal(format, &halFormat))
+ << "Conversion of \"" << format << "\" failed";
+ EXPECT_TRUE(audio_is_valid_format(halFormat))
+ << "Converted format \"" << format << "\" is invalid";
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioFormatFromHal(halFormat, &formatBack))
+ << "Conversion of format " << halFormat << " failed";
+ EXPECT_EQ(format, formatBack);
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidGainModeMask) {
+ hidl_vec<AudioGainMode> invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainModeMaskFromHal(kInvalidHalGainMode, &invalid));
+ audio_gain_mode_t halInvalid;
+ invalid.resize(1);
+ invalid[0] = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainModeMaskToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertGainModeMask) {
+ hidl_vec<AudioGainMode> emptyGainModes;
+ audio_gain_mode_t halEmptyGainModes;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskToHal(emptyGainModes, &halEmptyGainModes));
+ hidl_vec<AudioGainMode> emptyGainModesBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioGainModeMaskFromHal(halEmptyGainModes, &emptyGainModesBack));
+ EXPECT_EQ(emptyGainModes, emptyGainModesBack);
+
+ std::vector<std::string> allEnumValues;
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioGainMode>{}) {
+ allEnumValues.push_back(toString(enumVal));
+ }
+ hidl_vec<AudioGainMode> allGainModes;
+ allGainModes.resize(allEnumValues.size());
+ for (size_t i = 0; i < allEnumValues.size(); ++i) {
+ allGainModes[i] = allEnumValues[i];
+ }
+ audio_gain_mode_t halAllGainModes;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskToHal(allGainModes, &halAllGainModes));
+ hidl_vec<AudioGainMode> allGainModesBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskFromHal(halAllGainModes, &allGainModesBack));
+ EXPECT_EQ(allGainModes, allGainModesBack);
+}
+
+TEST(HidlUtils, ConvertInvalidSource) {
+ AudioSource invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioSourceFromHal(kInvalidHalSource, &invalid));
+ audio_source_t halInvalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioSourceToHal("random string", &halInvalid));
+}
+
+TEST(HidlUtils, ConvertSource) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioSource>{}) {
+ const AudioSource source = toString(enumVal);
+ audio_source_t halSource;
+ AudioSource sourceBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioSourceToHal(source, &halSource))
+ << "Conversion of \"" << source << "\" failed";
+ EXPECT_EQ(enumVal != xsd::AudioSource::AUDIO_SOURCE_DEFAULT,
+ audio_is_valid_audio_source(halSource))
+ << "Validity of \"" << source << "\" is not as expected";
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioSourceFromHal(halSource, &sourceBack))
+ << "Conversion of source " << halSource << " failed";
+ EXPECT_EQ(source, sourceBack);
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidStreamType) {
+ AudioStreamType invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeFromHal(kInvalidHalStreamType, &invalid));
+ audio_stream_type_t halInvalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeToHal("random string", &halInvalid));
+}
+
+TEST(HidlUtils, ConvertStreamType) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioStreamType>{}) {
+ const AudioStreamType streamType = toString(enumVal);
+ audio_stream_type_t halStreamType;
+ AudioStreamType streamTypeBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeToHal(streamType, &halStreamType))
+ << "Conversion of \"" << streamType << "\" failed";
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeFromHal(halStreamType, &streamTypeBack))
+ << "Conversion of stream type " << halStreamType << " failed";
+ EXPECT_EQ(streamType, streamTypeBack);
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidGain) {
+ AudioGain invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainFromHal({.mode = kInvalidHalGainMode},
+ false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainFromHal({.mode = kInvalidHalGainMode},
+ true /*isInput*/, &invalid));
+ struct audio_gain halInvalid;
+ invalid.mode.resize(1);
+ invalid.mode[0] = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertGain) {
+ AudioGain gain = {};
+ gain.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ struct audio_gain halGain;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainToHal(gain, &halGain));
+ AudioGain gainBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainFromHal(halGain, false /*isInput*/, &gainBack));
+ EXPECT_EQ(gain, gainBack);
+ struct audio_gain halGainBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainToHal(gainBack, &halGainBack));
+ EXPECT_TRUE(audio_gains_are_equal(&halGain, &halGainBack));
+}
+
+TEST(HidlUtils, ConvertInvalidGainConfig) {
+ AudioGainConfig invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigFromHal({.mode = kInvalidHalGainMode},
+ false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigFromHal({.mode = kInvalidHalGainMode},
+ true /*isInput*/, &invalid));
+ struct audio_gain_config halInvalid;
+ invalid.mode.resize(1);
+ invalid.mode[0] = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertGainConfig) {
+ AudioGainConfig gainConfig = {};
+ gainConfig.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ struct audio_gain_config halGainConfig;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainConfigToHal(gainConfig, &halGainConfig));
+ AudioGainConfig gainConfigBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioGainConfigFromHal(halGainConfig, false /*isInput*/, &gainConfigBack));
+ EXPECT_EQ(gainConfig, gainConfigBack);
+ struct audio_gain_config halGainConfigBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioGainConfigToHal(gainConfigBack, &halGainConfigBack));
+ EXPECT_TRUE(audio_gain_config_are_equal(&halGainConfig, &halGainConfigBack));
+}
+
+TEST(HidlUtils, ConvertInvalidUsage) {
+ AudioUsage invalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioUsageFromHal(kInvalidHalUsage, &invalid));
+ audio_usage_t halInvalid;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioUsageToHal("random string", &halInvalid));
+}
+
+TEST(HidlUtils, ConvertUsage) {
+ for (const auto enumVal : xsdc_enum_range<xsd::AudioUsage>{}) {
+ const AudioUsage usage = toString(enumVal);
+ audio_usage_t halUsage;
+ AudioUsage usageBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioUsageToHal(usage, &halUsage))
+ << "Conversion of \"" << usage << "\" failed";
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioUsageFromHal(halUsage, &usageBack))
+ << "Conversion of usage " << halUsage << " failed";
+ EXPECT_EQ(usage, usageBack);
+ }
+}
+
+TEST(HidlUtils, ConvertInvalidOffloadInfo) {
+ AudioOffloadInfo invalid;
+ audio_offload_info_t halInvalid = AUDIO_INFO_INITIALIZER;
+ halInvalid.channel_mask = AUDIO_CHANNEL_INVALID;
+ halInvalid.format = kInvalidHalFormat;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioOffloadInfoFromHal(halInvalid, &invalid));
+ invalid.base.channelMask = "random string";
+ invalid.base.format = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioOffloadInfoToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertOffloadInfo) {
+ AudioOffloadInfo offloadInfo = {};
+ offloadInfo.base.sampleRateHz = 44100;
+ offloadInfo.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ offloadInfo.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
+ offloadInfo.bitRatePerSecond = 320;
+ offloadInfo.durationMicroseconds = -1;
+ offloadInfo.bitWidth = 16;
+ offloadInfo.bufferSize = 1024;
+ offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
+ offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM;
+ offloadInfo.contentId = 42;
+ offloadInfo.syncId = 13;
+ audio_offload_info_t halOffloadInfo;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioOffloadInfoToHal(offloadInfo, &halOffloadInfo));
+ AudioOffloadInfo offloadInfoBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioOffloadInfoFromHal(halOffloadInfo, &offloadInfoBack));
+ EXPECT_EQ(offloadInfo, offloadInfoBack);
+}
+
+TEST(HidlUtils, ConvertInvalidConfig) {
+ AudioConfig invalid;
+ audio_config_t halInvalid = AUDIO_CONFIG_INITIALIZER;
+ halInvalid.channel_mask = AUDIO_CHANNEL_INVALID;
+ halInvalid.format = kInvalidHalFormat;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigFromHal(halInvalid, false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigFromHal(halInvalid, true /*isInput*/, &invalid));
+ invalid.base.channelMask = "random string";
+ invalid.base.format = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertConfig) {
+ AudioConfig config = {};
+ config.base.sampleRateHz = 44100;
+ config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ config.offloadInfo.base = config.base;
+ config.offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
+ config.offloadInfo.bitRatePerSecond = 320;
+ config.offloadInfo.durationMicroseconds = -1;
+ config.offloadInfo.bitWidth = 16;
+ config.offloadInfo.bufferSize = 1024;
+ config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
+ config.offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM;
+ config.offloadInfo.contentId = 42;
+ config.offloadInfo.syncId = 13;
+ audio_config_t halConfig;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig));
+ AudioConfig configBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, &configBack));
+ EXPECT_EQ(config, configBack);
+}
+
+TEST(HidlUtils, ConvertInvalidAudioProfile) {
+ AudioProfile invalid;
+ struct audio_profile halInvalid = {};
+ halInvalid.format = kInvalidHalFormat;
+ halInvalid.num_sample_rates = 0;
+ halInvalid.num_channel_masks = 1;
+ halInvalid.channel_masks[0] = kInvalidHalChannelMask;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileFromHal(halInvalid, false /*isInput*/, &invalid));
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileFromHal(halInvalid, true /*isInput*/, &invalid));
+ invalid.format = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertAudioProfile) {
+ AudioProfile profile = {};
+ profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ profile.sampleRates.resize(2);
+ profile.sampleRates[0] = 44100;
+ profile.sampleRates[1] = 48000;
+ profile.channelMasks.resize(2);
+ profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
+ profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ struct audio_profile halProfile;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioProfileToHal(profile, &halProfile));
+ AudioProfile profileBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::audioProfileFromHal(halProfile, false /*isInput*/, &profileBack));
+ EXPECT_EQ(profile, profileBack);
+}
+
+TEST(HidlUtils, ConvertInvalidAudioPortConfig) {
+ AudioPortConfig invalid;
+ struct audio_port_config halInvalid = {};
+ halInvalid.type = AUDIO_PORT_TYPE_MIX;
+ halInvalid.role = AUDIO_PORT_ROLE_NONE; // note: this is valid.
+ halInvalid.config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ halInvalid.channel_mask = AUDIO_CHANNEL_INVALID;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortConfigFromHal(halInvalid, &invalid));
+ invalid.base.channelMask = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortConfigToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertAudioPortConfig) {
+ AudioPortConfig config = {};
+ config.id = 42;
+ config.base.sampleRateHz = 44100;
+ config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ config.gain.config({});
+ config.gain.config().channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ config.ext.device({});
+ config.ext.device().deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER);
+ struct audio_port_config halConfig;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigToHal(config, &halConfig));
+ AudioPortConfig configBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigFromHal(halConfig, &configBack));
+ EXPECT_EQ(config, configBack);
+ struct audio_port_config halConfigBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigToHal(configBack, &halConfigBack));
+ EXPECT_TRUE(audio_port_configs_are_equal(&halConfig, &halConfigBack));
+}
+
+TEST(HidlUtils, ConvertInvalidAudioPort) {
+ AudioPort invalid;
+ struct audio_port_v7 halInvalid = {};
+ halInvalid.type = AUDIO_PORT_TYPE_MIX;
+ halInvalid.role = AUDIO_PORT_ROLE_NONE; // note: this is valid.
+ halInvalid.num_audio_profiles = 1;
+ halInvalid.audio_profiles[0].format = kInvalidHalFormat;
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortFromHal(halInvalid, &invalid));
+ invalid.profiles.resize(1);
+ invalid.profiles[0].format = "random string";
+ EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertAudioPort) {
+ AudioPort port = {};
+ port.id = 42;
+ port.name = "test";
+ port.profiles.resize(1);
+ port.profiles[0].format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ port.profiles[0].sampleRates.resize(2);
+ port.profiles[0].sampleRates[0] = 44100;
+ port.profiles[0].sampleRates[1] = 48000;
+ port.profiles[0].channelMasks.resize(2);
+ port.profiles[0].channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
+ port.profiles[0].channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ port.gains.resize(1);
+ port.gains[0].channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+ port.ext.device({});
+ port.ext.device().deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER);
+ // active config left unspecified.
+ struct audio_port_v7 halPort;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(port, &halPort));
+ AudioPort portBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortFromHal(halPort, &portBack));
+ EXPECT_EQ(port, portBack);
+ struct audio_port_v7 halPortBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(portBack, &halPortBack));
+ EXPECT_TRUE(audio_ports_v7_are_equal(&halPort, &halPortBack));
+}
diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index 0db210a..28d8f78 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -27,6 +27,7 @@
namespace CPP_VERSION {
namespace implementation {
+// TODO(mnaganov): Use method from HidlUtils for V7
std::string deviceAddressToHal(const DeviceAddress& address) {
// HAL assumes that the address is NUL-terminated.
char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 6260ba1..3c28159 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -283,8 +283,10 @@
const hidl_vec<AudioPortConfig>& sinks) {
Result retval(Result::NOT_SUPPORTED);
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
- std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
- std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
+ std::unique_ptr<audio_port_config[]> halSources;
+ HidlUtils::audioPortConfigsToHal(sources, &halSources);
+ std::unique_ptr<audio_port_config[]> halSinks;
+ HidlUtils::audioPortConfigsToHal(sinks, &halSinks);
audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
retval = analyzeStatus("create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 2466fd1..1612d3c 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -17,7 +17,7 @@
#include "AudioPrimaryHidlHalTest.h"
#if MAJOR_VERSION >= 7
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0.h>
#include <xsdc/XsdcSupport.h>
using android::xsdc_enum_range;
@@ -67,8 +67,7 @@
auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
#elif MAJOR_VERSION >= 7
- config.base.channelMask.resize(1);
- config.base.channelMask[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO);
+ config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO);
config.base.sampleRateHz = 8000;
config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
hidl_vec<hidl_string> flags;
@@ -236,7 +235,7 @@
#if MAJOR_VERSION <= 6
hidl_enum_range<AudioSource> range;
#elif MAJOR_VERSION >= 7
- xsdc_enum_range<audio::policy::configuration::V7_0::AudioSource> range;
+ xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range;
#endif
// Test all possible track configuration
for (auto source : range) {
@@ -272,8 +271,8 @@
hidl_enum_range<AudioUsage> usageRange;
hidl_enum_range<AudioContentType> contentRange;
#elif MAJOR_VERSION >= 7
- xsdc_enum_range<audio::policy::configuration::V7_0::AudioUsage> usageRange;
- xsdc_enum_range<audio::policy::configuration::V7_0::AudioContentType> contentRange;
+ xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange;
+ xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange;
#endif
// Test all possible track configuration
for (auto usage : usageRange) {
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 63eaea8..941c4bd 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -26,8 +26,7 @@
for (auto sampleRate : sampleRates) {
AudioConfig config{};
// leave offloadInfo to 0
- config.base.channelMask.resize(1);
- config.base.channelMask[0] = toString(channelMask);
+ config.base.channelMask = toString(channelMask);
config.base.sampleRateHz = sampleRate;
config.base.format = format;
configs.push_back(config);
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index c7bfe08..a809a92 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -22,6 +22,8 @@
"libxml2",
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "libaudioclient_aidl_conversion",
"libbinder",
"libfmq",
],
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 0a9d5ee..1ead47c 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -43,8 +43,8 @@
#include PATH(android/hardware/audio/FILE_VERSION/types.h)
#include PATH(android/hardware/audio/common/FILE_VERSION/types.h)
#if MAJOR_VERSION >= 7
-#include <audio_policy_configuration_V7_0-enums.h>
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <android_audio_policy_configuration_V7_0.h>
#endif
#include <fmq/EventFlag.h>
@@ -91,7 +91,7 @@
#if MAJOR_VERSION >= 7
// Make an alias for enumerations generated from the APM config XSD.
namespace xsd {
-using namespace ::audio::policy::configuration::CPP_VERSION;
+using namespace ::android::audio::policy::configuration::CPP_VERSION;
}
#endif
diff --git a/audio/effect/7.0/types.hal b/audio/effect/7.0/types.hal
index fe4ee51..b0a0709 100644
--- a/audio/effect/7.0/types.hal
+++ b/audio/effect/7.0/types.hal
@@ -202,16 +202,26 @@
* enumeration of the effect engines present in a library.
*/
struct EffectDescriptor {
- Uuid type; // UUID of to the OpenSL ES interface implemented
- // by this effect
- Uuid uuid; // UUID for this particular implementation
- bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
- uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units
- // as estimated on an ARM9E core (ARMv5TE) with 0 WS
- uint16_t memoryUsage; // data memory usage expressed in KB and includes
- // only dynamically allocated memory
- uint8_t[64] name; // human readable effect name
- uint8_t[64] implementor; // human readable effect implementor name
+ /** UUID of to the OpenSL ES interface implemented by this effect. */
+ Uuid type;
+ /** UUID for this particular implementation. */
+ Uuid uuid;
+ /** Effect engine capabilities/requirements flags. */
+ bitfield<EffectFlags> flags;
+ /**
+ * CPU load indication expressed in 0.1 MIPS units as estimated on
+ * an ARM9E core (ARMv5TE) with 0 WS.
+ */
+ uint16_t cpuLoad;
+ /**
+ * Data memory usage expressed in KB and includes only dynamically
+ * allocated memory.
+ */
+ uint16_t memoryUsage;
+ /** Human readable effect name. */
+ uint8_t[64] name;
+ /** Human readable effect implementor name. */
+ uint8_t[64] implementor;
};
/**
@@ -242,11 +252,16 @@
*/
@export(name="", value_prefix="EFFECT_CONFIG_")
enum EffectConfigParameters : int32_t {
- BUFFER = 0x0001, // buffer field
- SMP_RATE = 0x0002, // samplingRate
- CHANNELS = 0x0004, // channels
- FORMAT = 0x0008, // format
- ACC_MODE = 0x0010, // accessMode
+ /** Buffer field. */
+ BUFFER = 0x0001,
+ /** Sampling rate. */
+ SMP_RATE = 0x0002,
+ /** Channels. */
+ CHANNELS = 0x0004,
+ /** Format. */
+ FORMAT = 0x0008,
+ /** Access mode. */
+ ACC_MODE = 0x0010,
// Note that the 2.0 ALL have been moved to an helper function
};
@@ -270,21 +285,23 @@
@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
enum EffectFeature : int32_t {
- AUX_CHANNELS, // supports auxiliary channels
- // (e.g. dual mic noise suppressor)
+ /** Supports auxiliary channels (e.g. dual mic noise suppressor). */
+ AUX_CHANNELS,
CNT
};
struct EffectAuxChannelsConfig {
- vec<AudioChannelMask> mainChannels; // channel mask for main channels
- vec<AudioChannelMask> auxChannels; // channel mask for auxiliary channels
+ /** Channel mask for main channels. */
+ vec<AudioChannelMask> mainChannels;
+ /** Channel mask for auxiliary channels. */
+ vec<AudioChannelMask> auxChannels;
};
struct EffectOffloadParameter {
- bool isOffload; // true if the playback thread the effect
- // is attached to is offloaded
- AudioIoHandle ioHandle; // io handle of the playback thread
- // the effect is attached to
+ /** True if the playback thread the effect is attached to is offloaded. */
+ bool isOffload;
+ /** I/O handle of the playback thread the effect is attached to. */
+ AudioIoHandle ioHandle;
};
/**
diff --git a/audio/effect/all-versions/default/Conversions.cpp b/audio/effect/all-versions/default/Conversions.cpp
index b1c0b0d..0cc8767 100644
--- a/audio/effect/all-versions/default/Conversions.cpp
+++ b/audio/effect/all-versions/default/Conversions.cpp
@@ -15,7 +15,7 @@
*/
#include "Conversions.h"
-#include "HidlUtils.h"
+#include "UuidUtils.h"
#include <memory.h>
#include <stdio.h>
@@ -31,12 +31,12 @@
namespace CPP_VERSION {
namespace implementation {
-using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+using ::android::hardware::audio::common::CPP_VERSION::implementation::UuidUtils;
void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor,
EffectDescriptor* descriptor) {
- HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
- HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
+ UuidUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
+ UuidUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
descriptor->flags = EnumBitfield<EffectFlags>(halDescriptor.flags);
descriptor->cpuLoad = halDescriptor.cpuLoad;
descriptor->memoryUsage = halDescriptor.memoryUsage;
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index acce7de..b265d3d 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -24,10 +24,10 @@
#include "Effect.h"
#include "EnvironmentalReverbEffect.h"
#include "EqualizerEffect.h"
-#include "HidlUtils.h"
#include "LoudnessEnhancerEffect.h"
#include "NoiseSuppressionEffect.h"
#include "PresetReverbEffect.h"
+#include "UuidUtils.h"
#include "VirtualizerEffect.h"
#include "VisualizerEffect.h"
#include "common/all-versions/default/EffectMap.h"
@@ -53,7 +53,7 @@
namespace CPP_VERSION {
namespace implementation {
-using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+using ::android::hardware::audio::common::CPP_VERSION::implementation::UuidUtils;
// static
sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor,
@@ -135,7 +135,7 @@
Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) {
effect_uuid_t halUuid;
- HidlUtils::uuidToHal(uuid, &halUuid);
+ UuidUtils::uuidToHal(uuid, &halUuid);
effect_descriptor_t halDescriptor;
status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
EffectDescriptor descriptor;
@@ -170,7 +170,7 @@
Return<void> EffectsFactory::createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle,
int32_t device, createEffect_cb _hidl_cb) {
effect_uuid_t halUuid;
- HidlUtils::uuidToHal(uuid, &halUuid);
+ UuidUtils::uuidToHal(uuid, &halUuid);
effect_handle_t handle;
Result retval(Result::OK);
status_t status;
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index b64f105..199a8a5 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -28,8 +28,8 @@
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#if MAJOR_VERSION >= 7
-#include <audio_policy_configuration_V7_0-enums.h>
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <android_audio_policy_configuration_V7_0.h>
#endif
#include <common/all-versions/VersionUtils.h>
@@ -54,7 +54,7 @@
#if MAJOR_VERSION >= 7
// Make an alias for enumerations generated from the APM config XSD.
namespace xsd {
-using namespace ::audio::policy::configuration::CPP_VERSION;
+using namespace ::android::audio::policy::configuration::CPP_VERSION;
}
#endif
@@ -262,8 +262,8 @@
*channelCount = audio_channel_count_from_out_mask(
static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
#else
- *channelCount =
- audio::policy::configuration::V7_0::getChannelCount(currentConfig.outputCfg.channels);
+ *channelCount = android::audio::policy::configuration::V7_0::getChannelCount(
+ currentConfig.outputCfg.channels);
ASSERT_NE(*channelCount, 0);
#endif
}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
index fc35fa9..98fa4e8 100644
--- a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
@@ -27,7 +27,7 @@
GAIN_TRANSIENT = 2,
GAIN_TRANSIENT_MAY_DUCK = 3,
GAIN_TRANSIENT_EXCLUSIVE = 4,
- LOSS = -1, // -1 * GAIN,
- LOSS_TRANSIENT = -2, // -1 * GAIN_TRANSIENT,
- LOSS_TRANSIENT_CAN_DUCK = -3, // -1 * GAIN_TRANSIENT_MAY_DUCK,
+ LOSS = -1 * GAIN,
+ LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
+ LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
}
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index b637310..5e09b4f 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -23,7 +23,7 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
-#include <audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -35,7 +35,7 @@
using ::std::string;
namespace xsd {
-using namespace audio::policy::configuration::V7_0;
+using namespace ::android::audio::policy::configuration::V7_0;
}
namespace {
diff --git a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
index c734e29..f33b8a5 100644
--- a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
+++ b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
@@ -33,10 +33,10 @@
using android::hardware::automotive::audiocontrol::BnFocusListener;
using android::hardware::automotive::audiocontrol::IAudioControl;
-#include "audio_policy_configuration_V7_0.h"
+#include "android_audio_policy_configuration_V7_0.h"
namespace xsd {
-using namespace audio::policy::configuration::V7_0;
+using namespace android::audio::policy::configuration::V7_0;
}
class AudioControlAidl : public testing::TestWithParam<std::string> {
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
index 4042b16..90e1002 100644
--- a/automotive/can/1.0/default/libnl++/Android.bp
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -25,6 +25,7 @@
"protocols/generic/Generic.cpp",
"protocols/generic/GenericMessageBase.cpp",
"protocols/generic/Unknown.cpp",
+ "protocols/generic/families/Nl80211.cpp",
"protocols/route/Link.cpp",
"protocols/route/Route.cpp",
"protocols/route/structs.cpp",
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
index e6cada2..f08897e 100644
--- a/automotive/can/1.0/default/libnl++/printer.cpp
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -51,24 +51,24 @@
printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
switch (genre) {
- case protocols::MessageGenre::UNKNOWN:
+ case protocols::MessageGenre::Unknown:
break;
- case protocols::MessageGenre::GET:
+ case protocols::MessageGenre::Get:
printFlag(NLM_F_DUMP, "DUMP"); // ROOT | MATCH
printFlag(NLM_F_ROOT, "ROOT");
printFlag(NLM_F_MATCH, "MATCH");
printFlag(NLM_F_ATOMIC, "ATOMIC");
break;
- case protocols::MessageGenre::NEW:
+ case protocols::MessageGenre::New:
printFlag(NLM_F_REPLACE, "REPLACE");
printFlag(NLM_F_EXCL, "EXCL");
printFlag(NLM_F_CREATE, "CREATE");
printFlag(NLM_F_APPEND, "APPEND");
break;
- case protocols::MessageGenre::DELETE:
+ case protocols::MessageGenre::Delete:
printFlag(NLM_F_NONREC, "NONREC");
break;
- case protocols::MessageGenre::ACK:
+ case protocols::MessageGenre::Ack:
printFlag(NLM_F_CAPPED, "CAPPED");
printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
break;
@@ -99,11 +99,25 @@
static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
const protocols::AttributeMap& attrMap) {
using DataType = protocols::AttributeDefinition::DataType;
+ using Flags = protocols::AttributeDefinition::Flags;
const auto attrtype = attrMap[attr->nla_type];
- ss << attrtype.name << ": ";
+ ss << attrtype.name;
+
+ if (attrtype.dataType == DataType::Flag && attr.data<uint8_t>().getRaw().len() == 0) return;
+ ss << ": ";
+
+ if (attrtype.flags == Flags::Verbose) {
+ const auto raw = attr.data<uint8_t>();
+ ss << "{len=" << raw.getRaw().len();
+ ss << ", crc=" << std::hex << std::setw(4) << crc16(raw) << std::dec;
+ ss << "}";
+ return;
+ }
+
switch (attrtype.dataType) {
case DataType::Raw:
+ case DataType::Flag:
toStream(ss, attr.data<uint8_t>());
break;
case DataType::Nested: {
@@ -117,13 +131,19 @@
ss << '}';
break;
}
+ case DataType::StringNul:
case DataType::String: {
const auto str = attr.data<char>().getRaw();
- ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
+ auto len = str.len();
+ if (attrtype.dataType == DataType::StringNul && len > 0 && str.ptr()[len - 1] == '\0') {
+ len--;
+ }
+
+ ss << '"' << printableOnly({str.ptr(), len}) << '"';
break;
}
case DataType::Uint:
- ss << attr.data<uint32_t>().copyFirst();
+ ss << attr.data<uint64_t>().copyFirst();
break;
case DataType::Struct: {
const auto structToStream =
@@ -147,10 +167,12 @@
}
protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
- const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
+ auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
const auto msgDetails =
protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
+ if (msgDescMaybe.has_value()) msgDescMaybe->get().track(hdr);
+
ss << "nlmsg{" << protocolDescr.getName() << " ";
ss << "hdr={";
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
index c93d865..aaf24a5 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
@@ -56,15 +56,17 @@
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(nlmsgtype_t msgtype) const {
const auto it = mMessageDetails.find(msgtype);
- if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::UNKNOWN};
+ if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::Unknown};
return it->second;
}
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
- const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
nlmsgtype_t msgtype) {
if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
- return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
+ return {std::to_string(msgtype), protocols::MessageGenre::Unknown};
}
+void MessageDescriptor::track(const Buffer<nlmsghdr> /* hdr */) {}
+
} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
index bd0e60f..8bed5e7 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -54,17 +54,64 @@
*/
struct AttributeDefinition {
enum class DataType : uint8_t {
+ /**
+ * Binary blob (or attribute of unknown type).
+ */
Raw,
+
+ /**
+ * Nested attribute (with or without NLA_F_NESTED).
+ */
Nested,
+
+ /**
+ * Non-null terminated string.
+ *
+ * The length of the string is determined by the size of an attribute.
+ */
String,
+
+ /**
+ * Null terminated string.
+ */
+ StringNul,
+
+ /**
+ * Unsigned integer of size 8, 16, 32 or 64 bits.
+ */
Uint,
+
+ /**
+ * Structure which printer is defined in ops ToStream variant.
+ */
Struct,
+
+ /**
+ * Flag attribute.
+ *
+ * The attribute doesn't have any contents. The flag is set when the attribute is present,
+ * it's not when it's absent from attribute list.
+ */
+ Flag,
+ };
+ enum class Flags : uint8_t {
+ Verbose = (1 << 0),
};
using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
std::string name;
DataType dataType = DataType::Raw;
std::variant<AttributeMap, ToStream> ops = AttributeMap{};
+
+ /**
+ * Attribute flags.
+ *
+ * It's not really a bitmask flag set (since you are not supposed to compare enum class by
+ * bitmask), but std::set<Flags> bumps compile time from 16s to 3m. Let's leave it as-is for
+ * now and revisit if we get some flags that can be used in pairs. When it happens, review all
+ * uses of the flags field to include the "&" operator and not "==".
+ */
+ Flags flags = {};
};
/**
@@ -74,11 +121,11 @@
* section in linux/netlink.h.
*/
enum class MessageGenre {
- UNKNOWN,
- GET,
- NEW,
- DELETE,
- ACK,
+ Unknown,
+ Get,
+ New,
+ Delete,
+ Ack,
};
/**
@@ -103,8 +150,15 @@
MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
+ /**
+ * Message tracking for stateful protocols (such as NETLINK_GENERIC).
+ *
+ * \param hdr Message to track
+ */
+ virtual void track(const Buffer<nlmsghdr> hdr);
+
static MessageDetails getMessageDetails(
- const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
nlmsgtype_t msgtype);
protected:
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
index cd2e8c6..16208ab 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -32,7 +32,7 @@
return mName;
}
-const std::optional<std::reference_wrapper<const MessageDescriptor>>
+const std::optional<std::reference_wrapper<MessageDescriptor>>
NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
return *mMessageDescrs.find(nlmsg_type)->second;
@@ -41,7 +41,7 @@
NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
MessageDescriptorMap map;
- for (const auto& descr : descrs) {
+ for (auto& descr : descrs) {
for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
index c969547..b173b91 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
@@ -40,17 +40,17 @@
const std::string& getName() const;
- virtual const std::optional<std::reference_wrapper<const MessageDescriptor>>
- getMessageDescriptor(nlmsgtype_t nlmsg_type);
+ virtual const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
+ nlmsgtype_t nlmsg_type);
protected:
- typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
+ typedef std::vector<std::shared_ptr<MessageDescriptor>> MessageDescriptorList;
NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs);
private:
- typedef std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> MessageDescriptorMap;
+ typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> MessageDescriptorMap;
const int mProtocol;
const std::string mName;
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
index 8a672d3..4b509c9 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
@@ -20,9 +20,9 @@
// clang-format off
Empty::Empty() : MessageDefinition<char>("nlmsg", {
- {NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
- {NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
- {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
+ {NLMSG_NOOP, {"NOOP", MessageGenre::Unknown}},
+ {NLMSG_DONE, {"DONE", MessageGenre::Unknown}},
+ {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::Unknown}},
}) {}
// clang-format on
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
index 44708a3..77451ed 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
@@ -20,13 +20,15 @@
#include <libnl++/printer.h>
+#include <map>
+
namespace android::nl::protocols::base {
using DataType = AttributeDefinition::DataType;
// clang-format off
Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
- {NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
+ {NLMSG_ERROR, {"ERROR", MessageGenre::Ack}},
}, {
{NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
{NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
@@ -34,9 +36,156 @@
}), mProtocol(protocol) {}
// clang-format on
+std::map<int, std::string> errnoNames{
+ {EPERM, "EPERM"}, // Operation not permitted
+ {ENOENT, "ENOENT"}, // No such file or directory
+ {ESRCH, "ESRCH"}, // No such process
+ {EINTR, "EINTR"}, // Interrupted system call
+ {EIO, "EIO"}, // I/O error
+ {ENXIO, "ENXIO"}, // No such device or address
+ {E2BIG, "E2BIG"}, // Argument list too long
+ {ENOEXEC, "ENOEXEC"}, // Exec format error
+ {EBADF, "EBADF"}, // Bad file number
+ {ECHILD, "ECHILD"}, // No child processes
+ {EAGAIN, "EAGAIN"}, // Try again
+ {ENOMEM, "ENOMEM"}, // Out of memory
+ {EACCES, "EACCES"}, // Permission denied
+ {EFAULT, "EFAULT"}, // Bad address
+ {ENOTBLK, "ENOTBLK"}, // Block device required
+ {EBUSY, "EBUSY"}, // Device or resource busy
+ {EEXIST, "EEXIST"}, // File exists
+ {EXDEV, "EXDEV"}, // Cross-device link
+ {ENODEV, "ENODEV"}, // No such device
+ {ENOTDIR, "ENOTDIR"}, // Not a directory
+ {EISDIR, "EISDIR"}, // Is a directory
+ {EINVAL, "EINVAL"}, // Invalid argument
+ {ENFILE, "ENFILE"}, // File table overflow
+ {EMFILE, "EMFILE"}, // Too many open files
+ {ENOTTY, "ENOTTY"}, // Not a typewriter
+ {ETXTBSY, "ETXTBSY"}, // Text file busy
+ {EFBIG, "EFBIG"}, // File too large
+ {ENOSPC, "ENOSPC"}, // No space left on device
+ {ESPIPE, "ESPIPE"}, // Illegal seek
+ {EROFS, "EROFS"}, // Read-only file system
+ {EMLINK, "EMLINK"}, // Too many links
+ {EPIPE, "EPIPE"}, // Broken pipe
+ {EDOM, "EDOM"}, // Math argument out of domain of func
+ {ERANGE, "ERANGE"}, // Math result not representable
+ {EDEADLK, "EDEADLK"}, // Resource deadlock would occur
+ {ENAMETOOLONG, "ENAMETOOLONG"}, // File name too long
+ {ENOLCK, "ENOLCK"}, // No record locks available
+ {ENOSYS, "ENOSYS"}, // Invalid system call number
+ {ENOTEMPTY, "ENOTEMPTY"}, // Directory not empty
+ {ELOOP, "ELOOP"}, // Too many symbolic links encountered
+ {ENOMSG, "ENOMSG"}, // No message of desired type
+ {EIDRM, "EIDRM"}, // Identifier removed
+ {ECHRNG, "ECHRNG"}, // Channel number out of range
+ {EL2NSYNC, "EL2NSYNC"}, // Level 2 not synchronized
+ {EL3HLT, "EL3HLT"}, // Level 3 halted
+ {EL3RST, "EL3RST"}, // Level 3 reset
+ {ELNRNG, "ELNRNG"}, // Link number out of range
+ {EUNATCH, "EUNATCH"}, // Protocol driver not attached
+ {ENOCSI, "ENOCSI"}, // No CSI structure available
+ {EL2HLT, "EL2HLT"}, // Level 2 halted
+ {EBADE, "EBADE"}, // Invalid exchange
+ {EBADR, "EBADR"}, // Invalid request descriptor
+ {EXFULL, "EXFULL"}, // Exchange full
+ {ENOANO, "ENOANO"}, // No anode
+ {EBADRQC, "EBADRQC"}, // Invalid request code
+ {EBADSLT, "EBADSLT"}, // Invalid slot
+ {EBFONT, "EBFONT"}, // Bad font file format
+ {ENOSTR, "ENOSTR"}, // Device not a stream
+ {ENODATA, "ENODATA"}, // No data available
+ {ETIME, "ETIME"}, // Timer expired
+ {ENOSR, "ENOSR"}, // Out of streams resources
+ {ENONET, "ENONET"}, // Machine is not on the network
+ {ENOPKG, "ENOPKG"}, // Package not installed
+ {EREMOTE, "EREMOTE"}, // Object is remote
+ {ENOLINK, "ENOLINK"}, // Link has been severed
+ {EADV, "EADV"}, // Advertise error
+ {ESRMNT, "ESRMNT"}, // Srmount error
+ {ECOMM, "ECOMM"}, // Communication error on send
+ {EPROTO, "EPROTO"}, // Protocol error
+ {EMULTIHOP, "EMULTIHOP"}, // Multihop attempted
+ {EDOTDOT, "EDOTDOT"}, // RFS specific error
+ {EBADMSG, "EBADMSG"}, // Not a data message
+ {EOVERFLOW, "EOVERFLOW"}, // Value too large for defined data type
+ {ENOTUNIQ, "ENOTUNIQ"}, // Name not unique on network
+ {EBADFD, "EBADFD"}, // File descriptor in bad state
+ {EREMCHG, "EREMCHG"}, // Remote address changed
+ {ELIBACC, "ELIBACC"}, // Can not access a needed shared library
+ {ELIBBAD, "ELIBBAD"}, // Accessing a corrupted shared library
+ {ELIBSCN, "ELIBSCN"}, // .lib section in a.out corrupted
+ {ELIBMAX, "ELIBMAX"}, // Attempting to link in too many shared libraries
+ {ELIBEXEC, "ELIBEXEC"}, // Cannot exec a shared library directly
+ {EILSEQ, "EILSEQ"}, // Illegal byte sequence
+ {ERESTART, "ERESTART"}, // Interrupted system call should be restarted
+ {ESTRPIPE, "ESTRPIPE"}, // Streams pipe error
+ {EUSERS, "EUSERS"}, // Too many users
+ {ENOTSOCK, "ENOTSOCK"}, // Socket operation on non-socket
+ {EDESTADDRREQ, "EDESTADDRREQ"}, // Destination address required
+ {EMSGSIZE, "EMSGSIZE"}, // Message too long
+ {EPROTOTYPE, "EPROTOTYPE"}, // Protocol wrong type for socket
+ {ENOPROTOOPT, "ENOPROTOOPT"}, // Protocol not available
+ {EPROTONOSUPPORT, "EPROTONOSUPPORT"}, // Protocol not supported
+ {ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"}, // Socket type not supported
+ {EOPNOTSUPP, "EOPNOTSUPP"}, // Operation not supported on transport endpoint
+ {EPFNOSUPPORT, "EPFNOSUPPORT"}, // Protocol family not supported
+ {EAFNOSUPPORT, "EAFNOSUPPORT"}, // Address family not supported by protocol
+ {EADDRINUSE, "EADDRINUSE"}, // Address already in use
+ {EADDRNOTAVAIL, "EADDRNOTAVAIL"}, // Cannot assign requested address
+ {ENETDOWN, "ENETDOWN"}, // Network is down
+ {ENETUNREACH, "ENETUNREACH"}, // Network is unreachable
+ {ENETRESET, "ENETRESET"}, // Network dropped connection because of reset
+ {ECONNABORTED, "ECONNABORTED"}, // Software caused connection abort
+ {ECONNRESET, "ECONNRESET"}, // Connection reset by peer
+ {ENOBUFS, "ENOBUFS"}, // No buffer space available
+ {EISCONN, "EISCONN"}, // Transport endpoint is already connected
+ {ENOTCONN, "ENOTCONN"}, // Transport endpoint is not connected
+ {ESHUTDOWN, "ESHUTDOWN"}, // Cannot send after transport endpoint shutdown
+ {ETOOMANYREFS, "ETOOMANYREFS"}, // Too many references: cannot splice
+ {ETIMEDOUT, "ETIMEDOUT"}, // Connection timed out
+ {ECONNREFUSED, "ECONNREFUSED"}, // Connection refused
+ {EHOSTDOWN, "EHOSTDOWN"}, // Host is down
+ {EHOSTUNREACH, "EHOSTUNREACH"}, // No route to host
+ {EALREADY, "EALREADY"}, // Operation already in progress
+ {EINPROGRESS, "EINPROGRESS"}, // Operation now in progress
+ {ESTALE, "ESTALE"}, // Stale file handle
+ {EUCLEAN, "EUCLEAN"}, // Structure needs cleaning
+ {ENOTNAM, "ENOTNAM"}, // Not a XENIX named type file
+ {ENAVAIL, "ENAVAIL"}, // No XENIX semaphores available
+ {EISNAM, "EISNAM"}, // Is a named type file
+ {EREMOTEIO, "EREMOTEIO"}, // Remote I/O error
+ {EDQUOT, "EDQUOT"}, // Quota exceeded
+ {ENOMEDIUM, "ENOMEDIUM"}, // No medium found
+ {EMEDIUMTYPE, "EMEDIUMTYPE"}, // Wrong medium type
+ {ECANCELED, "ECANCELED"}, // Operation Canceled
+ {ENOKEY, "ENOKEY"}, // Required key not available
+ {EKEYEXPIRED, "EKEYEXPIRED"}, // Key has expired
+ {EKEYREVOKED, "EKEYREVOKED"}, // Key has been revoked
+ {EKEYREJECTED, "EKEYREJECTED"}, // Key was rejected by service
+ {EOWNERDEAD, "EOWNERDEAD"}, // Owner died
+ {ENOTRECOVERABLE, "ENOTRECOVERABLE"}, // State not recoverable
+ {ERFKILL, "ERFKILL"}, // Operation not possible due to RF-kill
+ {EHWPOISON, "EHWPOISON"}, // Memory page has hardware error
+
+ // Duplicates: EWOULDBLOCK (Operation would block), EDEADLOCK
+};
+
void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
- ss << "nlmsgerr{error=" << data.error
- << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
+ ss << "nlmsgerr{";
+ if (data.error == 0) {
+ ss << "ACK";
+ } else {
+ ss << "error=";
+ const auto nameIt = errnoNames.find(-data.error);
+ if (nameIt == errnoNames.end()) {
+ ss << data.error;
+ } else {
+ ss << nameIt->second;
+ }
+ }
+ ss << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
}
} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
index a3c6736..1e1ad12 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
@@ -16,12 +16,19 @@
#include "Ctrl.h"
+#include "families/Nl80211.h"
+
+#include <libnl++/Message.h>
+
namespace android::nl::protocols::generic {
using DataType = AttributeDefinition::DataType;
+using Flags = AttributeDefinition::Flags;
// clang-format off
-Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
+Ctrl::Ctrl(Generic::FamilyRegister& familyRegister)
+ : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL",
+{
{CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
{CTRL_CMD_DELFAMILY, "DELFAMILY"},
{CTRL_CMD_GETFAMILY, "GETFAMILY"},
@@ -33,7 +40,7 @@
{CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
}, {
{CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
- {CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::String}},
+ {CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::StringNul}},
{CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
{CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
{CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
@@ -42,14 +49,31 @@
{CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
{CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
}}},
- }}},
+ }, Flags::Verbose}},
{CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, AttributeMap{
{std::nullopt, {"GRP", DataType::Nested, AttributeMap{
- {CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::String}},
+ {CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::StringNul}},
{CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
}}},
}}},
-}) {}
+}), mFamilyRegister(familyRegister) {}
// clang-format on
+void Ctrl::track(const Buffer<nlmsghdr> hdr) {
+ const auto msgMaybe = Message<genlmsghdr>::parse(hdr, {GENL_ID_CTRL});
+ if (!msgMaybe.has_value()) return;
+ const auto msg = *msgMaybe;
+
+ if (msg->cmd != CTRL_CMD_NEWFAMILY) return;
+ const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
+ const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
+
+ /* For now, we support just a single family. But if you add more, please define proper
+ * abstraction and not hardcode every name and class here.
+ */
+ if (familyName == "nl80211") {
+ mFamilyRegister[familyId] = std::make_shared<families::Nl80211>(familyId);
+ }
+}
+
} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
index 6af87a8..b13df02 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
@@ -16,13 +16,19 @@
#pragma once
+#include "Generic.h"
#include "GenericMessageBase.h"
namespace android::nl::protocols::generic {
class Ctrl : public GenericMessageBase {
public:
- Ctrl();
+ Ctrl(Generic::FamilyRegister& familyRegister);
+
+ void track(const Buffer<nlmsghdr> hdr) override;
+
+ private:
+ Generic::FamilyRegister& mFamilyRegister;
};
} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
index 1a24914..5e34a1f 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
@@ -21,11 +21,12 @@
namespace android::nl::protocols::generic {
-Generic::Generic() : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>()}) {}
+Generic::Generic()
+ : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>(mFamilyRegister)}) {}
-const std::optional<std::reference_wrapper<const MessageDescriptor>> Generic::getMessageDescriptor(
+const std::optional<std::reference_wrapper<MessageDescriptor>> Generic::getMessageDescriptor(
nlmsgtype_t nlmsg_type) {
- const auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
+ auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
if (desc.has_value()) return desc;
auto it = mFamilyRegister.find(nlmsg_type);
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
index 593c92d..2cdd584 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
@@ -25,13 +25,15 @@
*/
class Generic : public NetlinkProtocol {
public:
+ typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> FamilyRegister;
+
Generic();
- const std::optional<std::reference_wrapper<const MessageDescriptor>> getMessageDescriptor(
+ const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
nlmsgtype_t nlmsg_type);
private:
- std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> mFamilyRegister;
+ FamilyRegister mFamilyRegister;
};
} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
index 134638e..b7b811b 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
@@ -22,16 +22,27 @@
nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
const std::initializer_list<AttributeMap::value_type> attrTypes)
- : MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
+ : MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::Unknown}}},
attrTypes),
mCommandNames(commandNames) {}
void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
+ const auto commandNameIt = mCommandNames.find(data.cmd);
+ const auto commandName = (commandNameIt == mCommandNames.end())
+ ? std::nullopt
+ : std::optional<std::string>(commandNameIt->second);
+
+ if (commandName.has_value() && data.version == 1 && data.reserved == 0) {
+ // short version
+ ss << *commandName;
+ return;
+ }
+
ss << "genlmsghdr{";
- if (mCommandNames.count(data.cmd) == 0) {
+ if (commandName.has_value()) {
ss << "cmd=" << unsigned(data.cmd);
} else {
- ss << "cmd=" << mCommandNames.find(data.cmd)->second;
+ ss << "cmd=" << *commandName;
}
ss << ", version=" << unsigned(data.version);
if (data.reserved != 0) ss << ", reserved=" << data.reserved;
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.cpp
new file mode 100644
index 0000000..23ec66f
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.cpp
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Nl80211.h"
+
+#include "../../structs.h"
+#include "common.h"
+
+#include <linux/nl80211.h>
+
+#include <iomanip>
+
+namespace android::nl::protocols::generic::families {
+
+/**
+ * Reduce verbosity of printed Information Elements.
+ */
+static constexpr bool kCompactIE = true;
+
+enum {
+ // broken compatibility in Aug 2020
+ NL80211_ATTR_CNTDWN_OFFS_BEACON = NL80211_ATTR_CSA_C_OFF_BEACON,
+ NL80211_ATTR_CNTDWN_OFFS_PRESP = NL80211_ATTR_CSA_C_OFF_PRESP,
+
+ // new fields not available in current Android
+ NL80211_ATTR_FILS_DISCOVERY = NL80211_ATTR_HE_6GHZ_CAPABILITY + 1,
+ NL80211_ATTR_UNSOL_BCAST_PROBE_RESP,
+ NL80211_ATTR_S1G_CAPABILITY,
+ NL80211_ATTR_S1G_CAPABILITY_MASK,
+
+ NL80211_FREQUENCY_ATTR_1MHZ = NL80211_FREQUENCY_ATTR_OFFSET + 1,
+ NL80211_FREQUENCY_ATTR_2MHZ,
+ NL80211_FREQUENCY_ATTR_4MHZ,
+ NL80211_FREQUENCY_ATTR_8MHZ,
+ NL80211_FREQUENCY_ATTR_16MHZ,
+};
+
+enum ieee80211_eid {
+ WLAN_EID_SSID = 0,
+};
+
+using DataType = AttributeDefinition::DataType;
+using Flags = AttributeDefinition::Flags;
+
+static void informationElementsToStream(std::stringstream& ss, const Buffer<nlattr> attr);
+static void nl80211_pattern_supportToStream(std::stringstream& ss, const Buffer<nlattr> attr);
+
+static const AttributeMap iftypes{
+ {NL80211_IFTYPE_UNSPECIFIED, {"UNSPECIFIED", DataType::Flag}},
+ {NL80211_IFTYPE_ADHOC, {"ADHOC", DataType::Flag}},
+ {NL80211_IFTYPE_STATION, {"STATION", DataType::Flag}},
+ {NL80211_IFTYPE_AP, {"AP", DataType::Flag}},
+ {NL80211_IFTYPE_AP_VLAN, {"AP_VLAN", DataType::Flag}},
+ {NL80211_IFTYPE_WDS, {"WDS", DataType::Flag}},
+ {NL80211_IFTYPE_MONITOR, {"MONITOR", DataType::Flag}},
+ {NL80211_IFTYPE_MESH_POINT, {"MESH_POINT", DataType::Flag}},
+ {NL80211_IFTYPE_P2P_CLIENT, {"P2P_CLIENT", DataType::Flag}},
+ {NL80211_IFTYPE_P2P_GO, {"P2P_GO", DataType::Flag}},
+ {NL80211_IFTYPE_P2P_DEVICE, {"P2P_DEVICE", DataType::Flag}},
+ {NL80211_IFTYPE_OCB, {"OCB", DataType::Flag}},
+ {NL80211_IFTYPE_NAN, {"NAN", DataType::Flag}},
+};
+
+// clang-format off
+Nl80211::Nl80211(nlmsgtype_t familyId) : GenericMessageBase(familyId, "nl80211", {
+ /* Script to generate the (initial) top-level list from linux/nl80211.h:
+ * sed -e 's/^ NL80211_CMD_\(.*\),$/ {NL80211_CMD_\1, "\1"},/g'
+ */
+ {NL80211_CMD_UNSPEC, "UNSPEC"},
+
+ {NL80211_CMD_GET_WIPHY, "GET_WIPHY"},
+ {NL80211_CMD_SET_WIPHY, "SET_WIPHY"},
+ {NL80211_CMD_NEW_WIPHY, "NEW_WIPHY"},
+ {NL80211_CMD_DEL_WIPHY, "DEL_WIPHY"},
+
+ {NL80211_CMD_GET_INTERFACE, "GET_INTERFACE"},
+ {NL80211_CMD_SET_INTERFACE, "SET_INTERFACE"},
+ {NL80211_CMD_NEW_INTERFACE, "NEW_INTERFACE"},
+ {NL80211_CMD_DEL_INTERFACE, "DEL_INTERFACE"},
+
+ {NL80211_CMD_GET_KEY, "GET_KEY"},
+ {NL80211_CMD_SET_KEY, "SET_KEY"},
+ {NL80211_CMD_NEW_KEY, "NEW_KEY"},
+ {NL80211_CMD_DEL_KEY, "DEL_KEY"},
+
+ {NL80211_CMD_GET_BEACON, "GET_BEACON"},
+ {NL80211_CMD_SET_BEACON, "SET_BEACON"},
+ {NL80211_CMD_START_AP, "START_AP"},
+ {NL80211_CMD_STOP_AP, "STOP_AP"},
+
+ {NL80211_CMD_GET_STATION, "GET_STATION"},
+ {NL80211_CMD_SET_STATION, "SET_STATION"},
+ {NL80211_CMD_NEW_STATION, "NEW_STATION"},
+ {NL80211_CMD_DEL_STATION, "DEL_STATION"},
+
+ {NL80211_CMD_GET_MPATH, "GET_MPATH"},
+ {NL80211_CMD_SET_MPATH, "SET_MPATH"},
+ {NL80211_CMD_NEW_MPATH, "NEW_MPATH"},
+ {NL80211_CMD_DEL_MPATH, "DEL_MPATH"},
+
+ {NL80211_CMD_SET_BSS, "SET_BSS"},
+
+ {NL80211_CMD_SET_REG, "SET_REG"},
+ {NL80211_CMD_REQ_SET_REG, "REQ_SET_REG"},
+
+ {NL80211_CMD_GET_MESH_CONFIG, "GET_MESH_CONFIG"},
+ {NL80211_CMD_SET_MESH_CONFIG, "SET_MESH_CONFIG"},
+
+ {NL80211_CMD_SET_MGMT_EXTRA_IE, "SET_MGMT_EXTRA_IE"},
+
+ {NL80211_CMD_GET_REG, "GET_REG"},
+
+ {NL80211_CMD_GET_SCAN, "GET_SCAN"},
+ {NL80211_CMD_TRIGGER_SCAN, "TRIGGER_SCAN"},
+ {NL80211_CMD_NEW_SCAN_RESULTS, "NEW_SCAN_RESULTS"},
+ {NL80211_CMD_SCAN_ABORTED, "SCAN_ABORTED"},
+
+ {NL80211_CMD_REG_CHANGE, "REG_CHANGE"},
+
+ {NL80211_CMD_AUTHENTICATE, "AUTHENTICATE"},
+ {NL80211_CMD_ASSOCIATE, "ASSOCIATE"},
+ {NL80211_CMD_DEAUTHENTICATE, "DEAUTHENTICATE"},
+ {NL80211_CMD_DISASSOCIATE, "DISASSOCIATE"},
+
+ {NL80211_CMD_MICHAEL_MIC_FAILURE, "MICHAEL_MIC_FAILURE"},
+
+ {NL80211_CMD_REG_BEACON_HINT, "REG_BEACON_HINT"},
+
+ {NL80211_CMD_JOIN_IBSS, "JOIN_IBSS"},
+ {NL80211_CMD_LEAVE_IBSS, "LEAVE_IBSS"},
+
+ {NL80211_CMD_TESTMODE, "TESTMODE"},
+
+ {NL80211_CMD_CONNECT, "CONNECT"},
+ {NL80211_CMD_ROAM, "ROAM"},
+ {NL80211_CMD_DISCONNECT, "DISCONNECT"},
+
+ {NL80211_CMD_SET_WIPHY_NETNS, "SET_WIPHY_NETNS"},
+
+ {NL80211_CMD_GET_SURVEY, "GET_SURVEY"},
+ {NL80211_CMD_NEW_SURVEY_RESULTS, "NEW_SURVEY_RESULTS"},
+
+ {NL80211_CMD_SET_PMKSA, "SET_PMKSA"},
+ {NL80211_CMD_DEL_PMKSA, "DEL_PMKSA"},
+ {NL80211_CMD_FLUSH_PMKSA, "FLUSH_PMKSA"},
+
+ {NL80211_CMD_REMAIN_ON_CHANNEL, "REMAIN_ON_CHANNEL"},
+ {NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, "CANCEL_REMAIN_ON_CHANNEL"},
+
+ {NL80211_CMD_SET_TX_BITRATE_MASK, "SET_TX_BITRATE_MASK"},
+
+ {NL80211_CMD_REGISTER_FRAME, "REGISTER_FRAME"},
+ {NL80211_CMD_FRAME, "FRAME"},
+ {NL80211_CMD_FRAME_TX_STATUS, "FRAME_TX_STATUS"},
+
+ {NL80211_CMD_SET_POWER_SAVE, "SET_POWER_SAVE"},
+ {NL80211_CMD_GET_POWER_SAVE, "GET_POWER_SAVE"},
+
+ {NL80211_CMD_SET_CQM, "SET_CQM"},
+ {NL80211_CMD_NOTIFY_CQM, "NOTIFY_CQM"},
+
+ {NL80211_CMD_SET_CHANNEL, "SET_CHANNEL"},
+ {NL80211_CMD_SET_WDS_PEER, "SET_WDS_PEER"},
+
+ {NL80211_CMD_FRAME_WAIT_CANCEL, "FRAME_WAIT_CANCEL"},
+
+ {NL80211_CMD_JOIN_MESH, "JOIN_MESH"},
+ {NL80211_CMD_LEAVE_MESH, "LEAVE_MESH"},
+
+ {NL80211_CMD_UNPROT_DEAUTHENTICATE, "UNPROT_DEAUTHENTICATE"},
+ {NL80211_CMD_UNPROT_DISASSOCIATE, "UNPROT_DISASSOCIATE"},
+
+ {NL80211_CMD_NEW_PEER_CANDIDATE, "NEW_PEER_CANDIDATE"},
+
+ {NL80211_CMD_GET_WOWLAN, "GET_WOWLAN"},
+ {NL80211_CMD_SET_WOWLAN, "SET_WOWLAN"},
+
+ {NL80211_CMD_START_SCHED_SCAN, "START_SCHED_SCAN"},
+ {NL80211_CMD_STOP_SCHED_SCAN, "STOP_SCHED_SCAN"},
+ {NL80211_CMD_SCHED_SCAN_RESULTS, "SCHED_SCAN_RESULTS"},
+ {NL80211_CMD_SCHED_SCAN_STOPPED, "SCHED_SCAN_STOPPED"},
+
+ {NL80211_CMD_SET_REKEY_OFFLOAD, "SET_REKEY_OFFLOAD"},
+
+ {NL80211_CMD_PMKSA_CANDIDATE, "PMKSA_CANDIDATE"},
+
+ {NL80211_CMD_TDLS_OPER, "TDLS_OPER"},
+ {NL80211_CMD_TDLS_MGMT, "TDLS_MGMT"},
+
+ {NL80211_CMD_UNEXPECTED_FRAME, "UNEXPECTED_FRAME"},
+
+ {NL80211_CMD_PROBE_CLIENT, "PROBE_CLIENT"},
+
+ {NL80211_CMD_REGISTER_BEACONS, "REGISTER_BEACONS"},
+
+ {NL80211_CMD_UNEXPECTED_4ADDR_FRAME, "UNEXPECTED_4ADDR_FRAME"},
+
+ {NL80211_CMD_SET_NOACK_MAP, "SET_NOACK_MAP"},
+
+ {NL80211_CMD_CH_SWITCH_NOTIFY, "CH_SWITCH_NOTIFY"},
+
+ {NL80211_CMD_START_P2P_DEVICE, "START_P2P_DEVICE"},
+ {NL80211_CMD_STOP_P2P_DEVICE, "STOP_P2P_DEVICE"},
+
+ {NL80211_CMD_CONN_FAILED, "CONN_FAILED"},
+
+ {NL80211_CMD_SET_MCAST_RATE, "SET_MCAST_RATE"},
+
+ {NL80211_CMD_SET_MAC_ACL, "SET_MAC_ACL"},
+
+ {NL80211_CMD_RADAR_DETECT, "RADAR_DETECT"},
+
+ {NL80211_CMD_GET_PROTOCOL_FEATURES, "GET_PROTOCOL_FEATURES"},
+
+ {NL80211_CMD_UPDATE_FT_IES, "UPDATE_FT_IES"},
+ {NL80211_CMD_FT_EVENT, "FT_EVENT"},
+
+ {NL80211_CMD_CRIT_PROTOCOL_START, "CRIT_PROTOCOL_START"},
+ {NL80211_CMD_CRIT_PROTOCOL_STOP, "CRIT_PROTOCOL_STOP"},
+
+ {NL80211_CMD_GET_COALESCE, "GET_COALESCE"},
+ {NL80211_CMD_SET_COALESCE, "SET_COALESCE"},
+
+ {NL80211_CMD_CHANNEL_SWITCH, "CHANNEL_SWITCH"},
+
+ {NL80211_CMD_VENDOR, "VENDOR"},
+
+ {NL80211_CMD_SET_QOS_MAP, "SET_QOS_MAP"},
+
+ {NL80211_CMD_ADD_TX_TS, "ADD_TX_TS"},
+ {NL80211_CMD_DEL_TX_TS, "DEL_TX_TS"},
+
+ {NL80211_CMD_GET_MPP, "GET_MPP"},
+
+ {NL80211_CMD_JOIN_OCB, "JOIN_OCB"},
+ {NL80211_CMD_LEAVE_OCB, "LEAVE_OCB"},
+
+ {NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, "CH_SWITCH_STARTED_NOTIFY"},
+
+ {NL80211_CMD_TDLS_CHANNEL_SWITCH, "TDLS_CHANNEL_SWITCH"},
+ {NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, "TDLS_CANCEL_CHANNEL_SWITCH"},
+
+ {NL80211_CMD_WIPHY_REG_CHANGE, "WIPHY_REG_CHANGE"},
+
+ {NL80211_CMD_ABORT_SCAN, "ABORT_SCAN"},
+
+ {NL80211_CMD_START_NAN, "START_NAN"},
+ {NL80211_CMD_STOP_NAN, "STOP_NAN"},
+ {NL80211_CMD_ADD_NAN_FUNCTION, "ADD_NAN_FUNCTION"},
+ {NL80211_CMD_DEL_NAN_FUNCTION, "DEL_NAN_FUNCTION"},
+ {NL80211_CMD_CHANGE_NAN_CONFIG, "CHANGE_NAN_CONFIG"},
+ {NL80211_CMD_NAN_MATCH, "NAN_MATCH"},
+
+ {NL80211_CMD_SET_MULTICAST_TO_UNICAST, "SET_MULTICAST_TO_UNICAST"},
+
+ {NL80211_CMD_UPDATE_CONNECT_PARAMS, "UPDATE_CONNECT_PARAMS"},
+
+ {NL80211_CMD_SET_PMK, "SET_PMK"},
+ {NL80211_CMD_DEL_PMK, "DEL_PMK"},
+
+ {NL80211_CMD_PORT_AUTHORIZED, "PORT_AUTHORIZED"},
+
+ {NL80211_CMD_RELOAD_REGDB, "RELOAD_REGDB"},
+
+ {NL80211_CMD_EXTERNAL_AUTH, "EXTERNAL_AUTH"},
+
+ {NL80211_CMD_STA_OPMODE_CHANGED, "STA_OPMODE_CHANGED"},
+
+ {NL80211_CMD_CONTROL_PORT_FRAME, "CONTROL_PORT_FRAME"},
+
+ {NL80211_CMD_GET_FTM_RESPONDER_STATS, "GET_FTM_RESPONDER_STATS"},
+
+ {NL80211_CMD_PEER_MEASUREMENT_START, "PEER_MEASUREMENT_START"},
+ {NL80211_CMD_PEER_MEASUREMENT_RESULT, "PEER_MEASUREMENT_RESULT"},
+ {NL80211_CMD_PEER_MEASUREMENT_COMPLETE, "PEER_MEASUREMENT_COMPLETE"},
+
+ {NL80211_CMD_NOTIFY_RADAR, "NOTIFY_RADAR"},
+
+ {NL80211_CMD_UPDATE_OWE_INFO, "UPDATE_OWE_INFO"},
+
+ {NL80211_CMD_PROBE_MESH_LINK, "PROBE_MESH_LINK"},
+
+ {NL80211_CMD_SET_TID_CONFIG, "SET_TID_CONFIG"},
+
+ {NL80211_CMD_UNPROT_BEACON, "UNPROT_BEACON"},
+
+ {NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, "CONTROL_PORT_FRAME_TX_STATUS"},
+}, {
+ /* Script to generate the (initial) top-level list from linux/nl80211.h:
+ * sed -e 's/^\tNL80211_ATTR_\(.*\),$/ {NL80211_ATTR_\1, {"\1"}},/g'
+ */
+ {NL80211_ATTR_UNSPEC, {"UNSPEC"}},
+
+ {NL80211_ATTR_WIPHY, {"WIPHY", DataType::Uint}},
+ {NL80211_ATTR_WIPHY_NAME, {"WIPHY_NAME", DataType::StringNul}},
+
+ {NL80211_ATTR_IFINDEX, {"IFINDEX", DataType::Uint}},
+ {NL80211_ATTR_IFNAME, {"IFNAME", DataType::StringNul}},
+ {NL80211_ATTR_IFTYPE, {"IFTYPE", DataType::Uint}},
+
+ {NL80211_ATTR_MAC, {"MAC", DataType::Raw}},
+
+ {NL80211_ATTR_KEY_DATA, {"KEY_DATA"}},
+ {NL80211_ATTR_KEY_IDX, {"KEY_IDX"}},
+ {NL80211_ATTR_KEY_CIPHER, {"KEY_CIPHER"}},
+ {NL80211_ATTR_KEY_SEQ, {"KEY_SEQ"}},
+ {NL80211_ATTR_KEY_DEFAULT, {"KEY_DEFAULT"}},
+
+ {NL80211_ATTR_BEACON_INTERVAL, {"BEACON_INTERVAL"}},
+ {NL80211_ATTR_DTIM_PERIOD, {"DTIM_PERIOD"}},
+ {NL80211_ATTR_BEACON_HEAD, {"BEACON_HEAD"}},
+ {NL80211_ATTR_BEACON_TAIL, {"BEACON_TAIL"}},
+
+ {NL80211_ATTR_STA_AID, {"STA_AID"}},
+ {NL80211_ATTR_STA_FLAGS, {"STA_FLAGS"}},
+ {NL80211_ATTR_STA_LISTEN_INTERVAL, {"STA_LISTEN_INTERVAL"}},
+ {NL80211_ATTR_STA_SUPPORTED_RATES, {"STA_SUPPORTED_RATES"}},
+ {NL80211_ATTR_STA_VLAN, {"STA_VLAN"}},
+ {NL80211_ATTR_STA_INFO, {"STA_INFO"}},
+
+ {NL80211_ATTR_WIPHY_BANDS, {"WIPHY_BANDS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"BAND", DataType::Nested, AttributeMap{
+ {NL80211_BAND_ATTR_FREQS, {"FREQS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"FQ", DataType::Nested, AttributeMap{
+ {NL80211_FREQUENCY_ATTR_FREQ, {"FREQ", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_DISABLED, {"DISABLED", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_IR, {"NO_IR", DataType::Flag}},
+ {__NL80211_FREQUENCY_ATTR_NO_IBSS, {"_NO_IBSS", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_RADAR, {"RADAR", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_MAX_TX_POWER, {"MAX_TX_POWER", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_DFS_STATE, {"DFS_STATE", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_DFS_TIME, {"DFS_TIME", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, {"NO_HT40_MINUS", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, {"NO_HT40_PLUS", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_80MHZ, {"NO_80MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_160MHZ, {"NO_160MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, {"DFS_CAC_TIME", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_INDOOR_ONLY, {"INDOOR_ONLY", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_IR_CONCURRENT, {"IR_CONCURRENT", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_20MHZ, {"NO_20MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_NO_10MHZ, {"NO_10MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_WMM, {"WMM"}},
+ {NL80211_FREQUENCY_ATTR_NO_HE, {"NO_HE", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_OFFSET, {"OFFSET", DataType::Uint}},
+ {NL80211_FREQUENCY_ATTR_1MHZ, {"1MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_2MHZ, {"2MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_4MHZ, {"4MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_8MHZ, {"8MHZ", DataType::Flag}},
+ {NL80211_FREQUENCY_ATTR_16MHZ, {"16MHZ", DataType::Flag}},
+ }}},
+ }, Flags::Verbose}},
+ {NL80211_BAND_ATTR_RATES, {"RATES", DataType::Nested, AttributeMap{
+ {std::nullopt, {"RATE", DataType::Nested, AttributeMap{
+ {NL80211_BITRATE_ATTR_RATE, {"RATE", DataType::Uint}},
+ {NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+ {"2GHZ_SHORTPREAMBLE", DataType::Flag}},
+ }}},
+ }}},
+
+ {NL80211_BAND_ATTR_HT_MCS_SET, {"HT_MCS_SET"}}, // struct ieee80211_mcs_info
+ {NL80211_BAND_ATTR_HT_CAPA, {"HT_CAPA", DataType::Uint}},
+ {NL80211_BAND_ATTR_HT_AMPDU_FACTOR, {"HT_AMPDU_FACTOR", DataType::Uint}},
+ {NL80211_BAND_ATTR_HT_AMPDU_DENSITY, {"HT_AMPDU_DENSITY", DataType::Uint}},
+
+ {NL80211_BAND_ATTR_VHT_MCS_SET, {"VHT_MCS_SET"}}, // struct ieee80211_vht_mcs_info
+ {NL80211_BAND_ATTR_VHT_CAPA, {"VHT_CAPA", DataType::Uint}},
+ {NL80211_BAND_ATTR_IFTYPE_DATA, {"IFTYPE_DATA"}},
+
+ {NL80211_BAND_ATTR_EDMG_CHANNELS, {"EDMG_CHANNELS"}},
+ {NL80211_BAND_ATTR_EDMG_BW_CONFIG, {"EDMG_BW_CONFIG"}},
+ }}},
+ }, Flags::Verbose}},
+
+ {NL80211_ATTR_MNTR_FLAGS, {"MNTR_FLAGS"}},
+
+ {NL80211_ATTR_MESH_ID, {"MESH_ID"}},
+ {NL80211_ATTR_STA_PLINK_ACTION, {"STA_PLINK_ACTION"}},
+ {NL80211_ATTR_MPATH_NEXT_HOP, {"MPATH_NEXT_HOP"}},
+ {NL80211_ATTR_MPATH_INFO, {"MPATH_INFO"}},
+
+ {NL80211_ATTR_BSS_CTS_PROT, {"BSS_CTS_PROT"}},
+ {NL80211_ATTR_BSS_SHORT_PREAMBLE, {"BSS_SHORT_PREAMBLE"}},
+ {NL80211_ATTR_BSS_SHORT_SLOT_TIME, {"BSS_SHORT_SLOT_TIME"}},
+
+ {NL80211_ATTR_HT_CAPABILITY, {"HT_CAPABILITY"}},
+
+ {NL80211_ATTR_SUPPORTED_IFTYPES, {"SUPPORTED_IFTYPES", DataType::Nested, iftypes}},
+
+ {NL80211_ATTR_REG_ALPHA2, {"REG_ALPHA2"}},
+ {NL80211_ATTR_REG_RULES, {"REG_RULES"}},
+
+ {NL80211_ATTR_MESH_CONFIG, {"MESH_CONFIG"}},
+
+ {NL80211_ATTR_BSS_BASIC_RATES, {"BSS_BASIC_RATES"}},
+
+ {NL80211_ATTR_WIPHY_TXQ_PARAMS, {"WIPHY_TXQ_PARAMS"}},
+ {NL80211_ATTR_WIPHY_FREQ, {"WIPHY_FREQ"}},
+ {NL80211_ATTR_WIPHY_CHANNEL_TYPE, {"WIPHY_CHANNEL_TYPE"}},
+
+ {NL80211_ATTR_KEY_DEFAULT_MGMT, {"KEY_DEFAULT_MGMT"}},
+
+ {NL80211_ATTR_MGMT_SUBTYPE, {"MGMT_SUBTYPE"}},
+ {NL80211_ATTR_IE, {"IE"}},
+
+ {NL80211_ATTR_MAX_NUM_SCAN_SSIDS, {"MAX_NUM_SCAN_SSIDS", DataType::Uint}},
+
+ {NL80211_ATTR_SCAN_FREQUENCIES, {"SCAN_FREQUENCIES", DataType::Nested, AttributeMap{
+ {std::nullopt, {"FQ", DataType::Uint}},
+ }, Flags::Verbose}},
+ {NL80211_ATTR_SCAN_SSIDS, {"SCAN_SSIDS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"SSID", DataType::String}},
+ }}},
+ {NL80211_ATTR_GENERATION, {"GENERATION", DataType::Uint}},
+ {NL80211_ATTR_BSS, {"BSS", DataType::Nested, AttributeMap{
+ {NL80211_BSS_BSSID, {"BSSID", DataType::Raw}},
+ {NL80211_BSS_FREQUENCY, {"FREQUENCY", DataType::Uint}},
+ {NL80211_BSS_TSF, {"TSF", DataType::Uint}},
+ {NL80211_BSS_BEACON_INTERVAL, {"BEACON_INTERVAL", DataType::Uint}},
+ {NL80211_BSS_CAPABILITY, {"CAPABILITY", DataType::Uint}},
+ {NL80211_BSS_INFORMATION_ELEMENTS, {"INFORMATION_ELEMENTS",
+ DataType::Struct, informationElementsToStream}},
+ {NL80211_BSS_SIGNAL_MBM, {"SIGNAL_MBM", DataType::Uint}},
+ {NL80211_BSS_SIGNAL_UNSPEC, {"SIGNAL_UNSPEC", DataType::Uint}},
+ {NL80211_BSS_STATUS, {"STATUS", DataType::Uint}}, // enum nl80211_bss_status
+ {NL80211_BSS_SEEN_MS_AGO, {"SEEN_MS_AGO", DataType::Uint}},
+ {NL80211_BSS_BEACON_IES, {"BEACON_IES", DataType::Struct, informationElementsToStream}},
+ {NL80211_BSS_CHAN_WIDTH, {"CHAN_WIDTH", DataType::Uint}},
+ {NL80211_BSS_BEACON_TSF, {"BEACON_TSF", DataType::Uint}},
+ {NL80211_BSS_PRESP_DATA, {"PRESP_DATA", DataType::Flag}},
+ {NL80211_BSS_LAST_SEEN_BOOTTIME, {"LAST_SEEN_BOOTTIME", DataType::Uint}},
+ {NL80211_BSS_PAD, {"PAD"}},
+ {NL80211_BSS_PARENT_TSF, {"PARENT_TSF"}},
+ {NL80211_BSS_PARENT_BSSID, {"PARENT_BSSID"}},
+ {NL80211_BSS_CHAIN_SIGNAL, {"CHAIN_SIGNAL", DataType::Nested, AttributeMap{
+ {std::nullopt, {"SIG", DataType::Uint}},
+ }}},
+ {NL80211_BSS_FREQUENCY_OFFSET, {"FREQUENCY_OFFSET"}},
+ }}},
+
+ {NL80211_ATTR_REG_INITIATOR, {"REG_INITIATOR"}},
+ {NL80211_ATTR_REG_TYPE, {"REG_TYPE"}},
+
+ {NL80211_ATTR_SUPPORTED_COMMANDS, {"SUPPORTED_COMMANDS", DataType::Nested,AttributeMap{
+ {std::nullopt, {"CMD", DataType::Uint}}, // enum nl80211_commands
+ }}},
+
+ {NL80211_ATTR_FRAME, {"FRAME"}},
+ {NL80211_ATTR_SSID, {"SSID"}},
+ {NL80211_ATTR_AUTH_TYPE, {"AUTH_TYPE"}},
+ {NL80211_ATTR_REASON_CODE, {"REASON_CODE"}},
+
+ {NL80211_ATTR_KEY_TYPE, {"KEY_TYPE"}},
+
+ {NL80211_ATTR_MAX_SCAN_IE_LEN, {"MAX_SCAN_IE_LEN", DataType::Uint}},
+ {NL80211_ATTR_CIPHER_SUITES, {"CIPHER_SUITES", DataType::Struct, arrayToStream<int32_t>}},
+
+ {NL80211_ATTR_FREQ_BEFORE, {"FREQ_BEFORE"}},
+ {NL80211_ATTR_FREQ_AFTER, {"FREQ_AFTER"}},
+
+ {NL80211_ATTR_FREQ_FIXED, {"FREQ_FIXED"}},
+
+ {NL80211_ATTR_WIPHY_RETRY_SHORT, {"WIPHY_RETRY_SHORT", DataType::Uint}},
+ {NL80211_ATTR_WIPHY_RETRY_LONG, {"WIPHY_RETRY_LONG", DataType::Uint}},
+ {NL80211_ATTR_WIPHY_FRAG_THRESHOLD, {"WIPHY_FRAG_THRESHOLD", DataType::Uint}},
+ {NL80211_ATTR_WIPHY_RTS_THRESHOLD, {"WIPHY_RTS_THRESHOLD", DataType::Uint}},
+
+ {NL80211_ATTR_TIMED_OUT, {"TIMED_OUT"}},
+
+ {NL80211_ATTR_USE_MFP, {"USE_MFP"}},
+
+ {NL80211_ATTR_STA_FLAGS2, {"STA_FLAGS2"}},
+
+ {NL80211_ATTR_CONTROL_PORT, {"CONTROL_PORT"}},
+
+ {NL80211_ATTR_TESTDATA, {"TESTDATA"}},
+
+ {NL80211_ATTR_PRIVACY, {"PRIVACY"}},
+
+ {NL80211_ATTR_DISCONNECTED_BY_AP, {"DISCONNECTED_BY_AP"}},
+ {NL80211_ATTR_STATUS_CODE, {"STATUS_CODE"}},
+
+ {NL80211_ATTR_CIPHER_SUITES_PAIRWISE, {"CIPHER_SUITES_PAIRWISE"}},
+ {NL80211_ATTR_CIPHER_SUITE_GROUP, {"CIPHER_SUITE_GROUP"}},
+ {NL80211_ATTR_WPA_VERSIONS, {"WPA_VERSIONS"}},
+ {NL80211_ATTR_AKM_SUITES, {"AKM_SUITES"}},
+
+ {NL80211_ATTR_REQ_IE, {"REQ_IE"}},
+ {NL80211_ATTR_RESP_IE, {"RESP_IE"}},
+
+ {NL80211_ATTR_PREV_BSSID, {"PREV_BSSID"}},
+
+ {NL80211_ATTR_KEY, {"KEY"}},
+ {NL80211_ATTR_KEYS, {"KEYS"}},
+
+ {NL80211_ATTR_PID, {"PID"}},
+
+ {NL80211_ATTR_4ADDR, {"4ADDR"}},
+
+ {NL80211_ATTR_SURVEY_INFO, {"SURVEY_INFO"}},
+
+ {NL80211_ATTR_PMKID, {"PMKID"}},
+ {NL80211_ATTR_MAX_NUM_PMKIDS, {"MAX_NUM_PMKIDS", DataType::Uint}},
+
+ {NL80211_ATTR_DURATION, {"DURATION"}},
+
+ {NL80211_ATTR_COOKIE, {"COOKIE"}},
+
+ {NL80211_ATTR_WIPHY_COVERAGE_CLASS, {"WIPHY_COVERAGE_CLASS", DataType::Uint}},
+
+ {NL80211_ATTR_TX_RATES, {"TX_RATES"}},
+
+ {NL80211_ATTR_FRAME_MATCH, {"FRAME_MATCH"}},
+
+ {NL80211_ATTR_ACK, {"ACK"}},
+
+ {NL80211_ATTR_PS_STATE, {"PS_STATE"}},
+
+ {NL80211_ATTR_CQM, {"CQM"}},
+
+ {NL80211_ATTR_LOCAL_STATE_CHANGE, {"LOCAL_STATE_CHANGE"}},
+
+ {NL80211_ATTR_AP_ISOLATE, {"AP_ISOLATE"}},
+
+ {NL80211_ATTR_WIPHY_TX_POWER_SETTING, {"WIPHY_TX_POWER_SETTING"}},
+ {NL80211_ATTR_WIPHY_TX_POWER_LEVEL, {"WIPHY_TX_POWER_LEVEL"}},
+
+ {NL80211_ATTR_TX_FRAME_TYPES, {"TX_FRAME_TYPES", DataType::Nested, AttributeMap{
+ {std::nullopt, {"TFT", DataType::Nested, AttributeMap{
+ {NL80211_ATTR_FRAME_TYPE, {"FRAME_TYPE", DataType::Uint}},
+ }}},
+ }, Flags::Verbose}},
+ {NL80211_ATTR_RX_FRAME_TYPES, {"RX_FRAME_TYPES", DataType::Nested, AttributeMap{
+ {std::nullopt, {"RFT", DataType::Nested, AttributeMap{
+ {NL80211_ATTR_FRAME_TYPE, {"FRAME_TYPE", DataType::Uint}},
+ }}},
+ }, Flags::Verbose}},
+
+ {NL80211_ATTR_FRAME_TYPE, {"FRAME_TYPE", DataType::Uint}},
+
+ {NL80211_ATTR_CONTROL_PORT_ETHERTYPE, {"CONTROL_PORT_ETHERTYPE"}},
+ {NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, {"CONTROL_PORT_NO_ENCRYPT"}},
+
+ {NL80211_ATTR_SUPPORT_IBSS_RSN, {"SUPPORT_IBSS_RSN"}},
+
+ {NL80211_ATTR_WIPHY_ANTENNA_TX, {"WIPHY_ANTENNA_TX"}},
+ {NL80211_ATTR_WIPHY_ANTENNA_RX, {"WIPHY_ANTENNA_RX"}},
+
+ {NL80211_ATTR_MCAST_RATE, {"MCAST_RATE"}},
+
+ {NL80211_ATTR_OFFCHANNEL_TX_OK, {"OFFCHANNEL_TX_OK", DataType::Flag}},
+
+ {NL80211_ATTR_BSS_HT_OPMODE, {"BSS_HT_OPMODE"}},
+
+ {NL80211_ATTR_KEY_DEFAULT_TYPES, {"KEY_DEFAULT_TYPES"}},
+
+ {NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+ {"MAX_REMAIN_ON_CHANNEL_DURATION", DataType::Uint}},
+
+ {NL80211_ATTR_MESH_SETUP, {"MESH_SETUP"}},
+
+ {NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, {"WIPHY_ANTENNA_AVAIL_TX", DataType::Uint}},
+ {NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, {"WIPHY_ANTENNA_AVAIL_RX", DataType::Uint}},
+
+ {NL80211_ATTR_SUPPORT_MESH_AUTH, {"SUPPORT_MESH_AUTH"}},
+ {NL80211_ATTR_STA_PLINK_STATE, {"STA_PLINK_STATE"}},
+
+ {NL80211_ATTR_WOWLAN_TRIGGERS, {"WOWLAN_TRIGGERS"}},
+ {NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+ {"WOWLAN_TRIGGERS_SUPPORTED", DataType::Nested, AttributeMap{
+ {NL80211_WOWLAN_TRIG_ANY, {"ANY", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_DISCONNECT, {"DISCONNECT", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_MAGIC_PKT, {"MAGIC_PKT", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ {"PKT_PATTERN", DataType::Struct, nl80211_pattern_supportToStream}},
+ {NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, {"GTK_REKEY_SUPPORTED", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, {"GTK_REKEY_FAILURE", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, {"EAP_IDENT_REQUEST", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, {"4WAY_HANDSHAKE", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_RFKILL_RELEASE, {"RFKILL_RELEASE", DataType::Flag}},
+ {NL80211_WOWLAN_TRIG_TCP_CONNECTION, {"TCP_CONNECTION", DataType::Nested, AttributeMap{
+ {NL80211_WOWLAN_TCP_SRC_IPV4, {"SRC_IPV4"}},
+ {NL80211_WOWLAN_TCP_DST_IPV4, {"DST_IPV4"}},
+ {NL80211_WOWLAN_TCP_DST_MAC, {"DST_MAC"}},
+ {NL80211_WOWLAN_TCP_SRC_PORT, {"SRC_PORT", DataType::Uint}},
+ {NL80211_WOWLAN_TCP_DST_PORT, {"DST_PORT", DataType::Uint}},
+ {NL80211_WOWLAN_TCP_DATA_PAYLOAD, {"DATA_PAYLOAD"}},
+ {NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, {"DATA_PAYLOAD_SEQ"}},
+ {NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, {"DATA_PAYLOAD_TOKEN"}},
+ {NL80211_WOWLAN_TCP_DATA_INTERVAL, {"DATA_INTERVAL", DataType::Uint}},
+ {NL80211_WOWLAN_TCP_WAKE_PAYLOAD, {"WAKE_PAYLOAD"}},
+ {NL80211_WOWLAN_TCP_WAKE_MASK, {"WAKE_MASK"}},
+ }}},
+ {NL80211_WOWLAN_TRIG_NET_DETECT, {"NET_DETECT", DataType::Uint}},
+
+ /* Not in WOWLAN_TRIGGERS_SUPPORTED:
+ * - NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211
+ * - NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN
+ * - NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023
+ * - NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN
+ * - NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH
+ * - NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST
+ * - NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS
+ * - NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS
+ */
+ }}},
+
+ {NL80211_ATTR_SCHED_SCAN_INTERVAL, {"SCHED_SCAN_INTERVAL"}},
+
+ {NL80211_ATTR_INTERFACE_COMBINATIONS, {"INTERFACE_COMBINATIONS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"IC", DataType::Nested, AttributeMap{
+ {NL80211_IFACE_COMB_UNSPEC, {"UNSPEC"}},
+ {NL80211_IFACE_COMB_LIMITS, {"LIMITS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"LT", DataType::Nested, AttributeMap{
+ {NL80211_IFACE_LIMIT_UNSPEC, {"UNSPEC"}},
+ {NL80211_IFACE_LIMIT_MAX, {"MAX", DataType::Uint}},
+ {NL80211_IFACE_LIMIT_TYPES, {"TYPES", DataType::Nested, iftypes}},
+ }}},
+ }}},
+ {NL80211_IFACE_COMB_MAXNUM, {"MAXNUM", DataType::Uint}},
+ {NL80211_IFACE_COMB_STA_AP_BI_MATCH, {"STA_AP_BI_MATCH", DataType::Flag}},
+ {NL80211_IFACE_COMB_NUM_CHANNELS, {"NUM_CHANNELS", DataType::Uint}},
+ {NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, {"RADAR_DETECT_WIDTHS", DataType::Uint}},
+ {NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, {"RADAR_DETECT_REGIONS", DataType::Uint}},
+ {NL80211_IFACE_COMB_BI_MIN_GCD, {"BI_MIN_GCD"}},
+ }}},
+ }, Flags::Verbose}},
+ {NL80211_ATTR_SOFTWARE_IFTYPES, {"SOFTWARE_IFTYPES", DataType::Nested, iftypes}},
+
+ {NL80211_ATTR_REKEY_DATA, {"REKEY_DATA"}},
+
+ {NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, {"MAX_NUM_SCHED_SCAN_SSIDS", DataType::Uint}},
+ {NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, {"MAX_SCHED_SCAN_IE_LEN", DataType::Uint}},
+
+ {NL80211_ATTR_SCAN_SUPP_RATES, {"SCAN_SUPP_RATES"}},
+
+ {NL80211_ATTR_HIDDEN_SSID, {"HIDDEN_SSID"}},
+
+ {NL80211_ATTR_IE_PROBE_RESP, {"IE_PROBE_RESP"}},
+ {NL80211_ATTR_IE_ASSOC_RESP, {"IE_ASSOC_RESP"}},
+
+ {NL80211_ATTR_STA_WME, {"STA_WME"}},
+ {NL80211_ATTR_SUPPORT_AP_UAPSD, {"SUPPORT_AP_UAPSD"}},
+
+ {NL80211_ATTR_ROAM_SUPPORT, {"ROAM_SUPPORT", DataType::Flag}},
+
+ {NL80211_ATTR_SCHED_SCAN_MATCH, {"SCHED_SCAN_MATCH"}},
+ {NL80211_ATTR_MAX_MATCH_SETS, {"MAX_MATCH_SETS", DataType::Uint}},
+
+ {NL80211_ATTR_PMKSA_CANDIDATE, {"PMKSA_CANDIDATE"}},
+
+ {NL80211_ATTR_TX_NO_CCK_RATE, {"TX_NO_CCK_RATE"}},
+
+ {NL80211_ATTR_TDLS_ACTION, {"TDLS_ACTION"}},
+ {NL80211_ATTR_TDLS_DIALOG_TOKEN, {"TDLS_DIALOG_TOKEN"}},
+ {NL80211_ATTR_TDLS_OPERATION, {"TDLS_OPERATION"}},
+ {NL80211_ATTR_TDLS_SUPPORT, {"TDLS_SUPPORT", DataType::Flag}},
+ {NL80211_ATTR_TDLS_EXTERNAL_SETUP, {"TDLS_EXTERNAL_SETUP", DataType::Flag}},
+
+ {NL80211_ATTR_DEVICE_AP_SME, {"DEVICE_AP_SME", DataType::Uint}},
+
+ {NL80211_ATTR_DONT_WAIT_FOR_ACK, {"DONT_WAIT_FOR_ACK"}},
+
+ {NL80211_ATTR_FEATURE_FLAGS, {"FEATURE_FLAGS", DataType::Uint}},
+
+ {NL80211_ATTR_PROBE_RESP_OFFLOAD, {"PROBE_RESP_OFFLOAD", DataType::Uint}},
+
+ {NL80211_ATTR_PROBE_RESP, {"PROBE_RESP"}},
+
+ {NL80211_ATTR_DFS_REGION, {"DFS_REGION"}},
+
+ {NL80211_ATTR_DISABLE_HT, {"DISABLE_HT"}},
+ {NL80211_ATTR_HT_CAPABILITY_MASK, {"HT_CAPABILITY_MASK"}},
+
+ {NL80211_ATTR_NOACK_MAP, {"NOACK_MAP"}},
+
+ {NL80211_ATTR_INACTIVITY_TIMEOUT, {"INACTIVITY_TIMEOUT"}},
+
+ {NL80211_ATTR_RX_SIGNAL_DBM, {"RX_SIGNAL_DBM"}},
+
+ {NL80211_ATTR_BG_SCAN_PERIOD, {"BG_SCAN_PERIOD"}},
+
+ {NL80211_ATTR_WDEV, {"WDEV", DataType::Uint}},
+
+ {NL80211_ATTR_USER_REG_HINT_TYPE, {"USER_REG_HINT_TYPE"}},
+
+ {NL80211_ATTR_CONN_FAILED_REASON, {"CONN_FAILED_REASON"}},
+
+ {NL80211_ATTR_AUTH_DATA, {"AUTH_DATA"}},
+
+ {NL80211_ATTR_VHT_CAPABILITY, {"VHT_CAPABILITY"}},
+
+ {NL80211_ATTR_SCAN_FLAGS, {"SCAN_FLAGS", DataType::Uint}},
+
+ {NL80211_ATTR_CHANNEL_WIDTH, {"CHANNEL_WIDTH"}},
+ {NL80211_ATTR_CENTER_FREQ1, {"CENTER_FREQ1"}},
+ {NL80211_ATTR_CENTER_FREQ2, {"CENTER_FREQ2"}},
+
+ {NL80211_ATTR_P2P_CTWINDOW, {"P2P_CTWINDOW"}},
+ {NL80211_ATTR_P2P_OPPPS, {"P2P_OPPPS"}},
+
+ {NL80211_ATTR_LOCAL_MESH_POWER_MODE, {"LOCAL_MESH_POWER_MODE"}},
+
+ {NL80211_ATTR_ACL_POLICY, {"ACL_POLICY"}},
+
+ {NL80211_ATTR_MAC_ADDRS, {"MAC_ADDRS"}},
+
+ {NL80211_ATTR_MAC_ACL_MAX, {"MAC_ACL_MAX", DataType::Uint}},
+
+ {NL80211_ATTR_RADAR_EVENT, {"RADAR_EVENT"}},
+
+ {NL80211_ATTR_EXT_CAPA, {"EXT_CAPA"}},
+ {NL80211_ATTR_EXT_CAPA_MASK, {"EXT_CAPA_MASK"}},
+
+ {NL80211_ATTR_STA_CAPABILITY, {"STA_CAPABILITY"}},
+ {NL80211_ATTR_STA_EXT_CAPABILITY, {"STA_EXT_CAPABILITY"}},
+
+ {NL80211_ATTR_PROTOCOL_FEATURES, {"PROTOCOL_FEATURES", DataType::Uint}},
+ {NL80211_ATTR_SPLIT_WIPHY_DUMP, {"SPLIT_WIPHY_DUMP", DataType::Flag}},
+
+ {NL80211_ATTR_DISABLE_VHT, {"DISABLE_VHT", DataType::Flag}},
+ {NL80211_ATTR_VHT_CAPABILITY_MASK, {"VHT_CAPABILITY_MASK"}},
+
+ {NL80211_ATTR_MDID, {"MDID"}},
+ {NL80211_ATTR_IE_RIC, {"IE_RIC"}},
+
+ {NL80211_ATTR_CRIT_PROT_ID, {"CRIT_PROT_ID"}},
+ {NL80211_ATTR_MAX_CRIT_PROT_DURATION, {"MAX_CRIT_PROT_DURATION"}},
+
+ {NL80211_ATTR_PEER_AID, {"PEER_AID"}},
+
+ {NL80211_ATTR_COALESCE_RULE, {"COALESCE_RULE"}},
+
+ {NL80211_ATTR_CH_SWITCH_COUNT, {"CH_SWITCH_COUNT"}},
+ {NL80211_ATTR_CH_SWITCH_BLOCK_TX, {"CH_SWITCH_BLOCK_TX"}},
+ {NL80211_ATTR_CSA_IES, {"CSA_IES"}},
+ {NL80211_ATTR_CNTDWN_OFFS_BEACON, {"CNTDWN_OFFS_BEACON"}},
+ {NL80211_ATTR_CNTDWN_OFFS_PRESP, {"CNTDWN_OFFS_PRESP"}},
+
+ {NL80211_ATTR_RXMGMT_FLAGS, {"RXMGMT_FLAGS"}},
+
+ {NL80211_ATTR_STA_SUPPORTED_CHANNELS, {"STA_SUPPORTED_CHANNELS"}},
+
+ {NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, {"STA_SUPPORTED_OPER_CLASSES"}},
+
+ {NL80211_ATTR_HANDLE_DFS, {"HANDLE_DFS"}},
+
+ {NL80211_ATTR_SUPPORT_5_MHZ, {"SUPPORT_5_MHZ"}},
+ {NL80211_ATTR_SUPPORT_10_MHZ, {"SUPPORT_10_MHZ"}},
+
+ {NL80211_ATTR_OPMODE_NOTIF, {"OPMODE_NOTIF"}},
+
+ {NL80211_ATTR_VENDOR_ID, {"VENDOR_ID"}},
+ {NL80211_ATTR_VENDOR_SUBCMD, {"VENDOR_SUBCMD"}},
+ {NL80211_ATTR_VENDOR_DATA, {"VENDOR_DATA", DataType::Raw, AttributeMap{}, Flags::Verbose}},
+ {NL80211_ATTR_VENDOR_EVENTS, {"VENDOR_EVENTS", DataType::Nested, AttributeMap{},
+ Flags::Verbose}},
+
+ {NL80211_ATTR_QOS_MAP, {"QOS_MAP"}},
+
+ {NL80211_ATTR_MAC_HINT, {"MAC_HINT"}},
+ {NL80211_ATTR_WIPHY_FREQ_HINT, {"WIPHY_FREQ_HINT"}},
+
+ {NL80211_ATTR_MAX_AP_ASSOC_STA, {"MAX_AP_ASSOC_STA"}},
+
+ {NL80211_ATTR_TDLS_PEER_CAPABILITY, {"TDLS_PEER_CAPABILITY"}},
+
+ {NL80211_ATTR_SOCKET_OWNER, {"SOCKET_OWNER"}},
+
+ {NL80211_ATTR_CSA_C_OFFSETS_TX, {"CSA_C_OFFSETS_TX"}},
+ {NL80211_ATTR_MAX_CSA_COUNTERS, {"MAX_CSA_COUNTERS"}},
+
+ {NL80211_ATTR_TDLS_INITIATOR, {"TDLS_INITIATOR"}},
+
+ {NL80211_ATTR_USE_RRM, {"USE_RRM"}},
+
+ {NL80211_ATTR_WIPHY_DYN_ACK, {"WIPHY_DYN_ACK"}},
+
+ {NL80211_ATTR_TSID, {"TSID"}},
+ {NL80211_ATTR_USER_PRIO, {"USER_PRIO"}},
+ {NL80211_ATTR_ADMITTED_TIME, {"ADMITTED_TIME"}},
+
+ {NL80211_ATTR_SMPS_MODE, {"SMPS_MODE"}},
+
+ {NL80211_ATTR_OPER_CLASS, {"OPER_CLASS"}},
+
+ {NL80211_ATTR_MAC_MASK, {"MAC_MASK"}},
+
+ {NL80211_ATTR_WIPHY_SELF_MANAGED_REG, {"WIPHY_SELF_MANAGED_REG"}},
+
+ {NL80211_ATTR_EXT_FEATURES, {"EXT_FEATURES"}},
+
+ {NL80211_ATTR_SURVEY_RADIO_STATS, {"SURVEY_RADIO_STATS"}},
+
+ {NL80211_ATTR_NETNS_FD, {"NETNS_FD"}},
+
+ {NL80211_ATTR_SCHED_SCAN_DELAY, {"SCHED_SCAN_DELAY"}},
+
+ {NL80211_ATTR_REG_INDOOR, {"REG_INDOOR"}},
+
+ {NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS, {"MAX_NUM_SCHED_SCAN_PLANS", DataType::Uint}},
+ {NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, {"MAX_SCAN_PLAN_INTERVAL", DataType::Uint}},
+ {NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS, {"MAX_SCAN_PLAN_ITERATIONS", DataType::Uint}},
+ {NL80211_ATTR_SCHED_SCAN_PLANS, {"SCHED_SCAN_PLANS"}},
+
+ {NL80211_ATTR_PBSS, {"PBSS"}},
+
+ {NL80211_ATTR_BSS_SELECT, {"BSS_SELECT"}},
+
+ {NL80211_ATTR_STA_SUPPORT_P2P_PS, {"STA_SUPPORT_P2P_PS"}},
+
+ {NL80211_ATTR_PAD, {"PAD"}},
+
+ {NL80211_ATTR_IFTYPE_EXT_CAPA, {"IFTYPE_EXT_CAPA"}},
+
+ {NL80211_ATTR_MU_MIMO_GROUP_DATA, {"MU_MIMO_GROUP_DATA"}},
+ {NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR, {"MU_MIMO_FOLLOW_MAC_ADDR"}},
+
+ {NL80211_ATTR_SCAN_START_TIME_TSF, {"SCAN_START_TIME_TSF"}},
+ {NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, {"SCAN_START_TIME_TSF_BSSID"}},
+ {NL80211_ATTR_MEASUREMENT_DURATION, {"MEASUREMENT_DURATION"}},
+ {NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY, {"MEASUREMENT_DURATION_MANDATORY"}},
+
+ {NL80211_ATTR_MESH_PEER_AID, {"MESH_PEER_AID"}},
+
+ {NL80211_ATTR_NAN_MASTER_PREF, {"NAN_MASTER_PREF"}},
+ {NL80211_ATTR_BANDS, {"BANDS"}},
+ {NL80211_ATTR_NAN_FUNC, {"NAN_FUNC"}},
+ {NL80211_ATTR_NAN_MATCH, {"NAN_MATCH"}},
+
+ {NL80211_ATTR_FILS_KEK, {"FILS_KEK"}},
+ {NL80211_ATTR_FILS_NONCES, {"FILS_NONCES"}},
+
+ {NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED, {"MULTICAST_TO_UNICAST_ENABLED"}},
+
+ {NL80211_ATTR_BSSID, {"BSSID"}},
+
+ {NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, {"SCHED_SCAN_RELATIVE_RSSI"}},
+ {NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, {"SCHED_SCAN_RSSI_ADJUST"}},
+
+ {NL80211_ATTR_TIMEOUT_REASON, {"TIMEOUT_REASON"}},
+
+ {NL80211_ATTR_FILS_ERP_USERNAME, {"FILS_ERP_USERNAME"}},
+ {NL80211_ATTR_FILS_ERP_REALM, {"FILS_ERP_REALM"}},
+ {NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM, {"FILS_ERP_NEXT_SEQ_NUM"}},
+ {NL80211_ATTR_FILS_ERP_RRK, {"FILS_ERP_RRK"}},
+ {NL80211_ATTR_FILS_CACHE_ID, {"FILS_CACHE_ID"}},
+
+ {NL80211_ATTR_PMK, {"PMK"}},
+
+ {NL80211_ATTR_SCHED_SCAN_MULTI, {"SCHED_SCAN_MULTI"}},
+ {NL80211_ATTR_SCHED_SCAN_MAX_REQS, {"SCHED_SCAN_MAX_REQS"}},
+
+ {NL80211_ATTR_WANT_1X_4WAY_HS, {"WANT_1X_4WAY_HS"}},
+ {NL80211_ATTR_PMKR0_NAME, {"PMKR0_NAME"}},
+ {NL80211_ATTR_PORT_AUTHORIZED, {"PORT_AUTHORIZED"}},
+
+ {NL80211_ATTR_EXTERNAL_AUTH_ACTION, {"EXTERNAL_AUTH_ACTION"}},
+ {NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, {"EXTERNAL_AUTH_SUPPORT"}},
+
+ {NL80211_ATTR_NSS, {"NSS"}},
+ {NL80211_ATTR_ACK_SIGNAL, {"ACK_SIGNAL"}},
+
+ {NL80211_ATTR_CONTROL_PORT_OVER_NL80211, {"CONTROL_PORT_OVER_NL80211"}},
+
+ {NL80211_ATTR_TXQ_STATS, {"TXQ_STATS"}},
+ {NL80211_ATTR_TXQ_LIMIT, {"TXQ_LIMIT"}},
+ {NL80211_ATTR_TXQ_MEMORY_LIMIT, {"TXQ_MEMORY_LIMIT"}},
+ {NL80211_ATTR_TXQ_QUANTUM, {"TXQ_QUANTUM"}},
+
+ {NL80211_ATTR_HE_CAPABILITY, {"HE_CAPABILITY"}},
+
+ {NL80211_ATTR_FTM_RESPONDER, {"FTM_RESPONDER"}},
+
+ {NL80211_ATTR_FTM_RESPONDER_STATS, {"FTM_RESPONDER_STATS"}},
+
+ {NL80211_ATTR_TIMEOUT, {"TIMEOUT"}},
+
+ {NL80211_ATTR_PEER_MEASUREMENTS, {"PEER_MEASUREMENTS"}},
+
+ {NL80211_ATTR_AIRTIME_WEIGHT, {"AIRTIME_WEIGHT"}},
+ {NL80211_ATTR_STA_TX_POWER_SETTING, {"STA_TX_POWER_SETTING"}},
+ {NL80211_ATTR_STA_TX_POWER, {"STA_TX_POWER"}},
+
+ {NL80211_ATTR_SAE_PASSWORD, {"SAE_PASSWORD"}},
+
+ {NL80211_ATTR_TWT_RESPONDER, {"TWT_RESPONDER"}},
+
+ {NL80211_ATTR_HE_OBSS_PD, {"HE_OBSS_PD"}},
+
+ {NL80211_ATTR_WIPHY_EDMG_CHANNELS, {"WIPHY_EDMG_CHANNELS"}},
+ {NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, {"WIPHY_EDMG_BW_CONFIG"}},
+
+ {NL80211_ATTR_VLAN_ID, {"VLAN_ID"}},
+
+ {NL80211_ATTR_HE_BSS_COLOR, {"HE_BSS_COLOR"}},
+
+ {NL80211_ATTR_IFTYPE_AKM_SUITES, {"IFTYPE_AKM_SUITES"}},
+
+ {NL80211_ATTR_TID_CONFIG, {"TID_CONFIG"}},
+
+ {NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, {"CONTROL_PORT_NO_PREAUTH"}},
+
+ {NL80211_ATTR_PMK_LIFETIME, {"PMK_LIFETIME"}},
+ {NL80211_ATTR_PMK_REAUTH_THRESHOLD, {"PMK_REAUTH_THRESHOLD"}},
+
+ {NL80211_ATTR_RECEIVE_MULTICAST, {"RECEIVE_MULTICAST"}},
+ {NL80211_ATTR_WIPHY_FREQ_OFFSET, {"WIPHY_FREQ_OFFSET"}},
+ {NL80211_ATTR_CENTER_FREQ1_OFFSET, {"CENTER_FREQ1_OFFSET"}},
+ {NL80211_ATTR_SCAN_FREQ_KHZ, {"SCAN_FREQ_KHZ"}},
+
+ {NL80211_ATTR_HE_6GHZ_CAPABILITY, {"HE_6GHZ_CAPABILITY"}},
+
+ {NL80211_ATTR_FILS_DISCOVERY, {"FILS_DISCOVERY"}},
+
+ {NL80211_ATTR_UNSOL_BCAST_PROBE_RESP, {"UNSOL_BCAST_PROBE_RESP"}},
+
+ {NL80211_ATTR_S1G_CAPABILITY, {"S1G_CAPABILITY"}},
+ {NL80211_ATTR_S1G_CAPABILITY_MASK, {"S1G_CAPABILITY_MASK"}},
+}) {}
+// clang-format on
+
+static void informationElementsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+ struct IEHeader {
+ uint8_t elementId;
+ uint8_t length;
+ } __attribute__((packed));
+ static_assert(sizeof(IEHeader) == 2);
+
+ const auto alldata = attr.data<uint8_t>();
+ const auto bytes = alldata.getRaw();
+
+ ss << '{';
+
+ if constexpr (kCompactIE) {
+ ss << "len=" << bytes.len() << ", ";
+ ss << "crc=" << std::hex << std::setw(4) << crc16(alldata) << std::dec << ", ";
+ }
+
+ bool first = true;
+ auto printComma = [&first, &ss]() {
+ // put separator at every but first entry
+ if (!first) ss << ", ";
+ first = false;
+ };
+
+ for (size_t offset = 0; offset < bytes.len();) {
+ const auto ptr = bytes.ptr() + offset;
+ const auto remainingLen = bytes.len() - offset;
+
+ // can we fit one more header?
+ if (sizeof(IEHeader) > remainingLen) break;
+ IEHeader ieHeader;
+ memcpy(&ieHeader, ptr, sizeof(IEHeader));
+ if (sizeof(IEHeader) + ieHeader.length > remainingLen) {
+ printComma();
+ ss << "ERR";
+ break;
+ }
+ offset += sizeof(IEHeader) + ieHeader.length;
+
+ const Buffer<uint8_t> data(ptr + sizeof(IEHeader), ieHeader.length);
+
+ if (ieHeader.elementId == WLAN_EID_SSID) {
+ printComma();
+
+ const auto str = data.getRaw();
+ const std::string ssid(reinterpret_cast<const char*>(str.ptr()), str.len());
+ ss << "SSID=\"" << printableOnly(ssid) << '"';
+
+ continue;
+ }
+
+ if constexpr (kCompactIE) continue;
+
+ // print entry ID:LENGTH/CRC16
+ printComma();
+ ss << (int)ieHeader.elementId << ':' << (int)ieHeader.length << '/';
+ ss << std::hex << std::setw(4) << crc16(data) << std::dec;
+ }
+ ss << '}';
+}
+
+static void nl80211_pattern_supportToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+ const auto& [ok, data] = attr.data<nl80211_pattern_support>().getFirst();
+ if (!ok) {
+ ss << "invalid structure";
+ return;
+ }
+ ss << '{' //
+ << data.max_patterns << ',' //
+ << data.min_pattern_len << ',' //
+ << data.max_pattern_len << ',' //
+ << data.max_pkt_offset << '}';
+}
+
+} // namespace android::nl::protocols::generic::families
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.h b/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.h
new file mode 100644
index 0000000..8a9608c
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/families/Nl80211.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include "../GenericMessageBase.h"
+
+namespace android::nl::protocols::generic::families {
+
+class Nl80211 : public GenericMessageBase {
+ public:
+ Nl80211(nlmsgtype_t familyId);
+};
+
+} // namespace android::nl::protocols::generic::families
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
index 7db487a..9cc05da 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
@@ -16,6 +16,7 @@
#include "Link.h"
+#include "../structs.h"
#include "structs.h"
#include <net/if.h>
@@ -26,9 +27,9 @@
// clang-format off
Link::Link() : MessageDefinition<ifinfomsg>("link", {
- {RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
- {RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
- {RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
+ {RTM_NEWLINK, {"NEWLINK", MessageGenre::New}},
+ {RTM_DELLINK, {"DELLINK", MessageGenre::Delete}},
+ {RTM_GETLINK, {"GETLINK", MessageGenre::Get}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
index b9d622a..fea2ce1 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -30,16 +30,6 @@
// ifla_cacheinfo
void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
-template <typename T>
-void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
- ss << '{';
- for (const auto it : attr.data<T>().getRaw()) {
- ss << it << ',';
- }
- ss.seekp(-1, std::ios_base::cur);
- ss << '}';
-}
-
// rtnl_link_stats or rtnl_link_stats64
template <typename T>
void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
diff --git a/automotive/can/1.0/default/libnl++/protocols/structs.h b/automotive/can/1.0/default/libnl++/protocols/structs.h
new file mode 100644
index 0000000..44c17b8
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/structs.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <sstream>
+
+namespace android::nl::protocols {
+
+template <typename T>
+void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+ ss << '{';
+ for (const auto it : attr.data<T>().getRaw()) {
+ ss << it << ',';
+ }
+ ss.seekp(-1, std::ios_base::cur);
+ ss << '}';
+}
+
+} // namespace android::nl::protocols
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 8de9304..e56c2d1 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -305,11 +305,22 @@
const auto id = 0xFFFFFFFF; // meaningless id
hidl_vec<uint8_t> values;
auto err = pCam->setExtendedInfo_1_1(id, values);
- ASSERT_NE(EvsResult::INVALID_ARG, err);
+ if (isLogicalCam) {
+ // Logical camera device does not support setExtendedInfo
+ // method.
+ ASSERT_EQ(EvsResult::INVALID_ARG, err);
+ } else {
+ ASSERT_NE(EvsResult::INVALID_ARG, err);
+ }
- pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
- ASSERT_NE(EvsResult::INVALID_ARG, result);
- ASSERT_EQ(0, data.size());
+
+ pCam->getExtendedInfo_1_1(id, [&isLogicalCam](const auto& result, const auto& data) {
+ if (isLogicalCam) {
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
+ } else {
+ ASSERT_NE(EvsResult::INVALID_ARG, result);
+ ASSERT_EQ(0, data.size());
+ }
});
// Explicitly close the camera so resources are released right away
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 8d1693a..bbb48e1 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -88,6 +88,7 @@
whole_static_libs: [
"android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
"android.hardware.automotive.vehicle@2.0-manager-lib",
+ "libqemu_pipe",
],
shared_libs: [
"libbase",
@@ -95,7 +96,6 @@
"libprotobuf-cpp-lite",
],
static_libs: [
- "libqemu_pipe",
"android.hardware.automotive.vehicle@2.0-libproto-native",
],
}
@@ -210,6 +210,5 @@
"android.hardware.automotive.vehicle@2.0-manager-lib",
"android.hardware.automotive.vehicle@2.0-default-impl-lib",
"android.hardware.automotive.vehicle@2.0-libproto-native",
- "libqemu_pipe",
],
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 80a1831..8ef2b60 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -308,6 +308,19 @@
{.config =
{
+ .prop = toInt(VehicleProperty::SEAT_OCCUPANCY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = (SEAT_1_LEFT)},
+ VehicleAreaConfig{.areaId = (SEAT_1_RIGHT)}},
+ },
+ .initialAreaValues = {{SEAT_1_LEFT,
+ {.int32Values = {(int)VehicleSeatOccupancyState::VACANT}}},
+ {SEAT_1_RIGHT,
+ {.int32Values = {(int)VehicleSeatOccupancyState::VACANT}}}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
@@ -417,7 +430,7 @@
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
},
- .initialValue = {.floatValues = {100.0f}}}, // units in meters
+ .initialValue = {.floatValues = {50000.0f}}}, // units in meters
{.config =
{
diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
index 2143880..57b3a92 100644
--- a/biometrics/face/1.1/default/BiometricsFace.cpp
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -24,8 +24,8 @@
constexpr uint64_t kDeviceId = 123;
// Arbitrary value.
constexpr uint64_t kAuthenticatorId = 987;
-// Arbitrary value.
-constexpr uint64_t kLockoutDuration = 555;
+// Not locked out.
+constexpr uint64_t kLockoutDuration = 0;
BiometricsFace::BiometricsFace() : mRandom(std::mt19937::default_seed) {}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
index 88c066c..a05fad9 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -42,4 +42,8 @@
SENSOR_DIRTY = 21,
VENDOR = 22,
FIRST_FRAME_RECEIVED = 23,
+ DARK_GLASSES_DETECTED = 24,
+ FACE_COVERING_DETECTED = 25,
+ EYES_NOT_VISIBLE = 26,
+ MOUTH_NOT_VISIBLE = 27,
}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
index 477ba5a..caf65ae 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -19,8 +19,8 @@
@VintfStability
interface ISessionCallback {
void onStateChanged(in int cookie, in android.hardware.biometrics.face.SessionState state);
- void onChallengeGenerated(in int sensorId, in int userId, in long challenge);
- void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
+ void onChallengeGenerated(in long challenge);
+ void onChallengeRevoked(in long challenge);
void onAcquired(in android.hardware.biometrics.face.AcquiredInfo info, in int vendorCode);
void onError(in android.hardware.biometrics.face.Error error, in int vendorCode);
void onEnrollmentProgress(in int enrollmentId, int remaining);
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
index 5897cdc..56a600f 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -218,6 +218,30 @@
/**
* The first frame from the camera has been received.
*/
- FIRST_FRAME_RECEIVED = 23
+ FIRST_FRAME_RECEIVED = 23,
+
+ /**
+ * Dark glasses detected. This can be useful for providing relevant feedback to the user and
+ * enabling an alternative authentication logic if the implementation supports it.
+ */
+ DARK_GLASSES_DETECTED = 24,
+
+ /**
+ * A face mask or face covering detected. This can be useful for providing relevant feedback to
+ * the user and enabling an alternative authentication logic if the implementation supports it.
+ */
+ FACE_COVERING_DETECTED = 25,
+
+ /**
+ * Either one or both eyes are not visible in the frame. Prefer to use DARK_GLASSES_DETECTED if
+ * the eyes are not visible due to dark glasses.
+ */
+ EYES_NOT_VISIBLE = 26,
+
+ /**
+ * The mouth is not visible in the frame. Prefer to use MASK_DETECTED if the mouth is not
+ * visible due to a mask.
+ */
+ MOUTH_NOT_VISIBLE = 27,
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index c7beae0..425b352 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -292,16 +292,9 @@
*
* When invoked by the framework, the implementation must perform the following sequence of
* events:
- * 1) Verify the authenticity and integrity of the provided HAT. If this check fails, the HAL
- * must invoke ISessionCallback#onError with Error::UNABLE_TO_PROCESS and return to
- * SessionState::IDLING if no subsequent work is in the queue.
- * 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
- * order of minutes, not hours). If this check fails, the HAL must invoke
- * ISessionCallback#onError with Error::UNABLE_TO_PROCESS and return to
- * SessionState::IDLING if no subsequent work is in the queue.
- * 3) Update the authenticatorId with a new entropy-encoded random number
- * 4) Persist the new authenticatorId to non-ephemeral storage
- * 5) Notify the framework that the above is completed, via
+ * 1) Update the authenticatorId with a new entropy-encoded random number
+ * 2) Persist the new authenticatorId to non-ephemeral storage
+ * 3) Notify the framework that the above is completed, via
* ISessionCallback#onAuthenticatorInvalidated
*
* A practical use case of invalidation would be when the user adds a new enrollment to a sensor
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
index 2608d5f..fd4a648 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -31,12 +31,12 @@
/**
* Notifies the framework when a challenge is successfully generated.
*/
- void onChallengeGenerated(in int sensorId, in int userId, in long challenge);
+ void onChallengeGenerated(in long challenge);
/**
* Notifies the framework when a challenge has been revoked.
*/
- void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
+ void onChallengeRevoked(in long challenge);
/**
* This method must only be used to notify the framework during the following states:
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index 929c7e7..d3883d6 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -20,7 +20,7 @@
namespace aidl::android::hardware::biometrics::face {
const int kSensorId = 0;
-const common::SensorStrength kSensorStrength = common::SensorStrength::WEAK;
+const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
const int kMaxEnrollmentsPerUser = 5;
const FaceSensorType kSensorType = FaceSensorType::RGB;
const bool kHalControlsPreview = true;
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index 2b1d4a7..c5d7d23 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -21,17 +21,35 @@
namespace aidl::android::hardware::biometrics::face {
class CancellationSignal : public common::BnCancellationSignal {
+ private:
+ std::shared_ptr<ISessionCallback> cb_;
public:
- ndk::ScopedAStatus cancel() override { return ndk::ScopedAStatus::ok(); }
+ explicit CancellationSignal(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
+
+ ndk::ScopedAStatus cancel() override {
+ cb_->onError(Error::CANCELED, 0 /* vendorCode */);
+ cb_->onStateChanged(0, SessionState::IDLING);
+ return ndk::ScopedAStatus::ok();
+ }
};
Session::Session(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
ndk::ScopedAStatus Session::generateChallenge(int32_t /*cookie*/, int32_t /*timeoutSec*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::GENERATING_CHALLENGE);
+ cb_->onChallengeGenerated(0);
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t /*challenge*/) {
+ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t challenge) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::REVOKING_CHALLENGE);
+ cb_->onChallengeRevoked(challenge);
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
@@ -47,7 +65,7 @@
if (cb_) {
cb_->onStateChanged(0, SessionState::AUTHENTICATING);
}
- *return_val = SharedRefBase::make<CancellationSignal>();
+ *return_val = SharedRefBase::make<CancellationSignal>(cb_);
return ndk::ScopedAStatus::ok();
}
@@ -57,15 +75,30 @@
}
ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
+ cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
const std::vector<int32_t>& /*enrollmentIds*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::REMOVING_ENROLLMENTS);
+ cb_->onEnrollmentsRemoved(std::vector<int32_t>());
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
+ cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
@@ -75,6 +108,11 @@
ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
const keymaster::HardwareAuthToken& /*hat*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::RESETTING_LOCKOUT);
+ cb_->onLockoutCleared();
+ cb_->onStateChanged(0, SessionState::IDLING);
+ }
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
index c1ba66b..5f10306 100644
--- a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
+++ b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
@@ -51,13 +51,11 @@
return ndk::ScopedAStatus::ok();
}
- ndk::ScopedAStatus onChallengeGenerated(int32_t /*sensorId*/, int32_t /*userId*/,
- int64_t /*challenge*/) override {
+ ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
return ndk::ScopedAStatus::ok();
}
- ndk::ScopedAStatus onChallengeRevoked(int32_t /*sensorId*/, int32_t /*userId*/,
- int64_t /*challenge*/) override {
+ ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/fingerprint/2.1/default/README.md b/biometrics/fingerprint/2.1/default/README.md
new file mode 100644
index 0000000..c41664e
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/README.md
@@ -0,0 +1,6 @@
+## Default IBiometricsFingerprint@2.1 HAL ##
+---
+
+## Overview: ##
+
+Provides a default implementation that loads pre-HIDL HALs and exposes it to the framework.
\ No newline at end of file
diff --git a/biometrics/fingerprint/2.2/default/Android.bp b/biometrics/fingerprint/2.2/default/Android.bp
new file mode 100644
index 0000000..8931308
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/Android.bp
@@ -0,0 +1,22 @@
+cc_binary {
+ name: "android.hardware.biometrics.fingerprint@2.2-service.example",
+ defaults: ["hidl_defaults"],
+ init_rc: ["android.hardware.biometrics.fingerprint@2.2-service.rc"],
+ vintf_fragments: ["android.hardware.biometrics.fingerprint@2.2-service.xml"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "BiometricsFingerprint.cpp",
+ "service.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libhidlbase",
+ "libhardware",
+ "libutils",
+ "android.hardware.biometrics.fingerprint@2.2",
+ ],
+
+}
diff --git a/biometrics/fingerprint/2.2/default/BiometricsFingerprint.cpp b/biometrics/fingerprint/2.2/default/BiometricsFingerprint.cpp
new file mode 100644
index 0000000..b07a17c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/BiometricsFingerprint.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "android.hardware.biometrics.fingerprint@2.2-service"
+#define LOG_VERBOSE "android.hardware.biometrics.fingerprint@2.2-service"
+
+#include <hardware/hw_auth_token.h>
+
+#include <android/log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include "BiometricsFingerprint.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+namespace V2_2 {
+namespace implementation {
+
+using RequestStatus = android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using FingerprintError = android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+
+constexpr uint64_t kDeviceId = 1;
+
+BiometricsFingerprint::BiometricsFingerprint() {
+
+}
+
+BiometricsFingerprint::~BiometricsFingerprint() {
+
+}
+
+Return<uint64_t> BiometricsFingerprint::setNotify(
+ const sp<IBiometricsFingerprintClientCallback>& clientCallback) {
+ mClientCallback = clientCallback;
+ return kDeviceId;
+}
+
+Return<uint64_t> BiometricsFingerprint::preEnroll() {
+ // On a real implementation, this must be generated and stored in the TEE or its equivalent.
+ return rand();
+}
+
+Return<RequestStatus> BiometricsFingerprint::enroll(const hidl_array<uint8_t, 69>& /* hat */,
+ uint32_t /* gid */, uint32_t /* timeoutSec */) {
+ // On a real implementation, the HAT must be checked in the TEE or its equivalent.
+ mClientCallback->onError(kDeviceId, FingerprintError::ERROR_UNABLE_TO_PROCESS,
+ 0 /* vendorCode */);
+ return RequestStatus::SYS_OK;
+}
+
+Return<RequestStatus> BiometricsFingerprint::postEnroll() {
+ return RequestStatus::SYS_OK;
+}
+
+Return<uint64_t> BiometricsFingerprint::getAuthenticatorId() {
+ return 1;
+}
+
+Return<RequestStatus> BiometricsFingerprint::cancel() {
+ mClientCallback->onError(kDeviceId, FingerprintError::ERROR_CANCELED, 0 /* vendorCode */);
+ return RequestStatus::SYS_OK;
+}
+
+Return<RequestStatus> BiometricsFingerprint::enumerate() {
+ mClientCallback->onEnumerate(kDeviceId, 0 /* fingerId */, 0 /* groupId */,
+ 0 /* remaining */);
+ return RequestStatus::SYS_OK;
+}
+
+Return<RequestStatus> BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) {
+ mClientCallback->onRemoved(kDeviceId, fid, gid, 0 /* remaining */);
+ return RequestStatus::SYS_OK;
+}
+
+Return<RequestStatus> BiometricsFingerprint::setActiveGroup(uint32_t /* gid */,
+ const hidl_string& storePath) {
+ // Return invalid for paths that the HAL is unable to write to.
+ std::string path = storePath.c_str();
+ if (path.compare("") == 0 || path.compare("/") == 0) {
+ return RequestStatus::SYS_EINVAL;
+ }
+ return RequestStatus::SYS_OK;
+}
+
+Return<RequestStatus> BiometricsFingerprint::authenticate(uint64_t /* operationId */,
+ uint32_t /* gid */) {
+ return RequestStatus::SYS_OK;
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
diff --git a/biometrics/fingerprint/2.2/default/BiometricsFingerprint.h b/biometrics/fingerprint/2.2/default/BiometricsFingerprint.h
new file mode 100644
index 0000000..a6861b3
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/BiometricsFingerprint.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_2_BIOMETRICSFINGERPRINT_H
+#define ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_2_BIOMETRICSFINGERPRINT_H
+
+#include <log/log.h>
+#include <android/log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using ::android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct BiometricsFingerprint : public IBiometricsFingerprint {
+public:
+ BiometricsFingerprint();
+ ~BiometricsFingerprint();
+
+ // Methods from ::android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint follow.
+ Return<uint64_t> setNotify(const sp<IBiometricsFingerprintClientCallback>& clientCallback) override;
+ Return<uint64_t> preEnroll() override;
+ Return<RequestStatus> enroll(const hidl_array<uint8_t, 69>& hat, uint32_t gid, uint32_t timeoutSec) override;
+ Return<RequestStatus> postEnroll() override;
+ Return<uint64_t> getAuthenticatorId() override;
+ Return<RequestStatus> cancel() override;
+ Return<RequestStatus> enumerate() override;
+ Return<RequestStatus> remove(uint32_t gid, uint32_t fid) override;
+ Return<RequestStatus> setActiveGroup(uint32_t gid, const hidl_string& storePath) override;
+ Return<RequestStatus> authenticate(uint64_t operationId, uint32_t gid) override;
+
+private:
+ sp<IBiometricsFingerprintClientCallback> mClientCallback;
+
+};
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_2_BIOMETRICSFINGERPRINT_H
diff --git a/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.rc b/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.rc
new file mode 100644
index 0000000..1b406b0
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.rc
@@ -0,0 +1,4 @@
+service vendor.fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.2-service.example
+ class hal
+ user nobody
+ group nobody
diff --git a/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.xml b/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.xml
new file mode 100644
index 0000000..5e69a1e
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/android.hardware.biometrics.fingerprint@2.2-service.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.biometrics.fingerprint</name>
+ <transport>hwbinder</transport>
+ <version>2.2</version>
+ <interface>
+ <name>IBiometricsFingerprint</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/biometrics/fingerprint/2.2/default/service.cpp b/biometrics/fingerprint/2.2/default/service.cpp
new file mode 100644
index 0000000..5bc69a0
--- /dev/null
+++ b/biometrics/fingerprint/2.2/default/service.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.biometrics.fingerprint@2.2-service"
+
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.2/types.h>
+#include "BiometricsFingerprint.h"
+
+using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+using android::hardware::biometrics::fingerprint::V2_2::implementation::BiometricsFingerprint;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::sp;
+
+int main() {
+ android::sp<IBiometricsFingerprint> bio = new BiometricsFingerprint();
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ if (::android::OK != bio->registerAsService()) {
+ return 1;
+ }
+
+ joinRpcThreadpool();
+
+ return 0; // should never get here
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 00a08ba..4df7981 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -26,7 +26,7 @@
void enumerateEnrollments(in int cookie);
void removeEnrollments(in int cookie, in int[] enrollmentIds);
void getAuthenticatorId(in int cookie);
- void invalidateAuthenticatorId(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+ void invalidateAuthenticatorId(in int cookie);
void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
void onPointerUp(in int pointerId);
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index da767be..09bd04d 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -301,16 +301,9 @@
*
* When invoked by the framework, the implementation must perform the following sequence of
* events:
- * 1) Verify the authenticity and integrity of the provided HAT. If this check fails, the HAL
- * must invoke ISessionCallback#onError with Error::UNABLE_TO_PROCESS and return to
- * SessionState::IDLING if no subsequent work is in the queue.
- * 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
- * order of minutes, not hours). If this check fails, the HAL must invoke
- * ISessionCallback#onError with Error::UNABLE_TO_PROCESS and return to
- * SessionState::IDLING if no subsequent work is in the queue.
- * 3) Update the authenticatorId with a new entropy-encoded random number
- * 4) Persist the new authenticatorId to non-ephemeral storage
- * 5) Notify the framework that the above is completed, via
+ * 1) Update the authenticatorId with a new entropy-encoded random number
+ * 2) Persist the new authenticatorId to non-ephemeral storage
+ * 3) Notify the framework that the above is completed, via
* ISessionCallback#onAuthenticatorInvalidated
*
* A practical use case of invalidation would be when the user adds a new enrollment to a sensor
@@ -321,9 +314,8 @@
*
* @param cookie An identifier used to track subsystem operations related to this call path. The
* client must guarantee that it is unique per ISession.
- * @param hat HardwareAuthToken that must be validated before proceeding with this operation.
*/
- void invalidateAuthenticatorId(in int cookie, in HardwareAuthToken hat);
+ void invalidateAuthenticatorId(in int cookie);
/**
* resetLockout:
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 18ce0c8..6eb35d9 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -19,7 +19,7 @@
namespace aidl::android::hardware::biometrics::fingerprint {
-const int kSensorId = 0;
+const int kSensorId = 1;
const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
const int kMaxEnrollmentsPerUser = 5;
const FingerprintSensorType kSensorType = FingerprintSensorType::REAR;
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 96f1e56..bf08203 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -79,8 +79,7 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/,
- const keymaster::HardwareAuthToken& /*hat*/) {
+ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/) {
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/fingerprint/aidl/default/Session.h b/biometrics/fingerprint/aidl/default/Session.h
index 05c570c..ed3ae3f 100644
--- a/biometrics/fingerprint/aidl/default/Session.h
+++ b/biometrics/fingerprint/aidl/default/Session.h
@@ -49,8 +49,7 @@
ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
- ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie,
- const keymaster::HardwareAuthToken& hat) override;
+ ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie) override;
ndk::ScopedAStatus resetLockout(int32_t cookie,
const keymaster::HardwareAuthToken& hat) override;
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 8c24f76..43abbe4 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -90,6 +90,7 @@
hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
if (hci_packet_type_ != HCI_PACKET_TYPE_ACL_DATA &&
hci_packet_type_ != HCI_PACKET_TYPE_SCO_DATA &&
+ hci_packet_type_ != HCI_PACKET_TYPE_ISO_DATA &&
hci_packet_type_ != HCI_PACKET_TYPE_EVENT) {
LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__,
static_cast<int>(hci_packet_type_));
diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h
index 24e944f..6f7ff90 100644
--- a/bluetooth/1.0/default/hci_internals.h
+++ b/bluetooth/1.0/default/hci_internals.h
@@ -44,6 +44,10 @@
const size_t HCI_EVENT_PREAMBLE_SIZE = 2;
const size_t HCI_LENGTH_OFFSET_EVT = 1;
+// 2 bytes for handle and flags, 2 byte for data length (Volume 4, Part E, 5.4.5)
+const size_t HCI_ISO_PREAMBLE_SIZE = 4;
+const size_t HCI_LENGTH_OFFSET_ISO = 2;
+
const size_t HCI_PREAMBLE_SIZE_MAX = HCI_ACL_PREAMBLE_SIZE;
// Event codes (Volume 2, Part E, 7.7.14)
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 7cb3a11..78ce61d 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -26,17 +26,27 @@
namespace {
-const size_t preamble_size_for_type[] = {
- 0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
- HCI_EVENT_PREAMBLE_SIZE};
-const size_t packet_length_offset_for_type[] = {
- 0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
- HCI_LENGTH_OFFSET_EVT};
+const size_t preamble_size_for_type[] = {0,
+ HCI_COMMAND_PREAMBLE_SIZE,
+ HCI_ACL_PREAMBLE_SIZE,
+ HCI_SCO_PREAMBLE_SIZE,
+ HCI_EVENT_PREAMBLE_SIZE,
+ HCI_ISO_PREAMBLE_SIZE};
+const size_t packet_length_offset_for_type[] = {0,
+ HCI_LENGTH_OFFSET_CMD,
+ HCI_LENGTH_OFFSET_ACL,
+ HCI_LENGTH_OFFSET_SCO,
+ HCI_LENGTH_OFFSET_EVT,
+ HCI_LENGTH_OFFSET_ISO};
size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
size_t offset = packet_length_offset_for_type[type];
- if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
- return (((preamble[offset + 1]) << 8) | preamble[offset]);
+ if (type == HCI_PACKET_TYPE_ACL_DATA) {
+ return (((preamble[offset + 1]) << 8) | preamble[offset]);
+ } else if (type == HCI_PACKET_TYPE_ISO_DATA) {
+ return ((((preamble[offset + 1]) & 0x3f) << 8) | preamble[offset]);
+ }
+ return preamble[offset];
}
} // namespace
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
index 283243d..174861c 100644
--- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -190,8 +190,10 @@
void WriteAndExpectInboundIsoData(char* payload) {
// h4 type[1] + handle[2] + size[1]
- char preamble[4] = {HCI_PACKET_TYPE_ISO_DATA, 20, 17, 0};
- preamble[3] = strlen(payload) & 0xFF;
+ char preamble[5] = {HCI_PACKET_TYPE_ISO_DATA, 19, 92, 0, 0};
+ int length = strlen(payload);
+ preamble[3] = length & 0xFF;
+ preamble[4] = (length >> 8) & 0x3F;
ALOGD("%s writing", __func__);
TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp
index 0f349a4..092038b 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp
@@ -55,12 +55,17 @@
const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
AudioConfiguration audioConfig_2_1;
- audioConfig_2_1.codecConfig() = audioConfig.codecConfig();
- audioConfig_2_1.pcmConfig() = {
- .sampleRate = static_cast<SampleRate>(audioConfig.pcmConfig().sampleRate),
- .channelMode = audioConfig.pcmConfig().channelMode,
- .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
- .dataIntervalUs = 0};
+ if (audioConfig.getDiscriminator() ==
+ V2_0::AudioConfiguration::hidl_discriminator::pcmConfig) {
+ audioConfig_2_1.pcmConfig() = {
+ .sampleRate =
+ static_cast<SampleRate>(audioConfig.pcmConfig().sampleRate),
+ .channelMode = audioConfig.pcmConfig().channelMode,
+ .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
+ .dataIntervalUs = 0};
+ } else {
+ audioConfig_2_1.codecConfig() = audioConfig.codecConfig();
+ }
return startSession_2_1(hostIf, audioConfig_2_1, _hidl_cb);
}
diff --git a/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
index c0ec907..37d1281 100644
--- a/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
+++ b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
@@ -1043,6 +1043,7 @@
} else {
EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
EXPECT_FALSE(dataMQ.isHandleValid());
+ tempDataMQ.reset(nullptr);
}
};
android::hardware::bluetooth::audio::V2_1::AudioConfiguration audio_config =
@@ -1064,6 +1065,8 @@
ASSERT_TRUE(hidl_retval.isOk());
if (is_codec_config_valid) {
EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+ } else {
+ EXPECT_TRUE(tempDataMQ == nullptr);
}
EXPECT_TRUE(audio_provider_2_1_->endSession().isOk());
} // uint32_t (data interval in microseconds)
@@ -1132,6 +1135,7 @@
} else {
EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
EXPECT_FALSE(dataMQ.isHandleValid());
+ tempDataMQ.reset(nullptr);
}
};
android::hardware::bluetooth::audio::V2_1::AudioConfiguration audio_config =
diff --git a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
index 5468658..ac17d6d 100644
--- a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
+++ b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
@@ -32,6 +32,7 @@
unsigned int GetNumberSlots();
unsigned int GetCurrentSlot();
bool MarkBootSuccessful();
+ unsigned int GetActiveBootSlot();
bool SetActiveBootSlot(unsigned int slot);
bool SetSlotAsUnbootable(unsigned int slot);
bool SetSlotBootable(unsigned int slot);
diff --git a/boot/1.1/default/boot_control/libboot_control.cpp b/boot/1.1/default/boot_control/libboot_control.cpp
index 2c6ccaf..9387c32 100644
--- a/boot/1.1/default/boot_control/libboot_control.cpp
+++ b/boot/1.1/default/boot_control/libboot_control.cpp
@@ -261,6 +261,24 @@
return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
}
+unsigned int BootControl::GetActiveBootSlot() {
+ bootloader_control bootctrl;
+ if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
+
+ // Use the current slot by default.
+ unsigned int active_boot_slot = current_slot_;
+ unsigned int max_priority = bootctrl.slot_info[current_slot_].priority;
+ // Find the slot with the highest priority.
+ for (unsigned int i = 0; i < num_slots_; ++i) {
+ if (bootctrl.slot_info[i].priority > max_priority) {
+ max_priority = bootctrl.slot_info[i].priority;
+ active_boot_slot = i;
+ }
+ }
+
+ return active_boot_slot;
+}
+
bool BootControl::SetActiveBootSlot(unsigned int slot) {
if (slot >= kMaxNumSlots || slot >= num_slots_) {
// Invalid slot number.
diff --git a/boot/1.2/Android.bp b/boot/1.2/Android.bp
new file mode 100644
index 0000000..e51c5cd
--- /dev/null
+++ b/boot/1.2/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.boot@1.2",
+ root: "android.hardware",
+ srcs: [
+ "IBootControl.hal",
+ ],
+ interfaces: [
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/boot/1.2/IBootControl.hal b/boot/1.2/IBootControl.hal
new file mode 100644
index 0000000..bb0ad13
--- /dev/null
+++ b/boot/1.2/IBootControl.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 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.hardware.boot@1.2;
+
+import @1.0::IBootControl;
+import @1.0::Slot;
+import @1.1::IBootControl;
+
+interface IBootControl extends @1.1::IBootControl {
+
+ /**
+ * Returns the active slot to boot into on the next boot. If
+ * setActiveBootSlot() has been called, the getter function should return the
+ * same slot as the one provided in the last setActiveBootSlot() call.
+ * The returned value is always guaranteed to be strictly less than the
+ * value returned by getNumberSlots. Slots start at 0 and finish at
+ * getNumberSlots() - 1. For instance, a system with A/B must return 0 or 1.
+ */
+ getActiveBootSlot() generates (Slot slot);
+};
+
diff --git a/boot/1.2/default/Android.bp b/boot/1.2/default/Android.bp
new file mode 100644
index 0000000..c097667
--- /dev/null
+++ b/boot/1.2/default/Android.bp
@@ -0,0 +1,50 @@
+cc_library_shared {
+ name: "android.hardware.boot@1.2-impl",
+ stem: "android.hardware.boot@1.0-impl-1.2",
+ defaults: [
+ "hidl_defaults",
+ "libboot_control_defaults",
+ ],
+ relative_install_path: "hw",
+ vendor: true,
+ recovery_available: true,
+ srcs: ["BootControl.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libhardware",
+ "libutils",
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
+ ],
+ static_libs: [
+ "libboot_control",
+ "libfstab",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.boot@1.2-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.boot@1.2-service.rc"],
+ srcs: ["service.cpp"],
+
+ vintf_fragments: [
+ "android.hardware.boot@1.2.xml",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libhidlbase",
+ "libutils",
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
+ ],
+
+}
diff --git a/boot/1.2/default/BootControl.cpp b/boot/1.2/default/BootControl.cpp
new file mode 100644
index 0000000..c0bf02f
--- /dev/null
+++ b/boot/1.2/default/BootControl.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "android.hardware.boot@1.2-impl"
+
+#include <memory>
+
+#include <log/log.h>
+
+#include "BootControl.h"
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::hardware::boot::V1_0::CommandResult;
+
+bool BootControl::Init() {
+ return impl_.Init();
+}
+
+// Methods from ::android::hardware::boot::V1_0::IBootControl.
+Return<uint32_t> BootControl::getNumberSlots() {
+ return impl_.GetNumberSlots();
+}
+
+Return<uint32_t> BootControl::getCurrentSlot() {
+ return impl_.GetCurrentSlot();
+}
+
+Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {
+ struct CommandResult cr;
+ if (impl_.MarkBootSuccessful()) {
+ cr.success = true;
+ cr.errMsg = "Success";
+ } else {
+ cr.success = false;
+ cr.errMsg = "Operation failed";
+ }
+ _hidl_cb(cr);
+ return Void();
+}
+
+Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {
+ struct CommandResult cr;
+ if (impl_.SetActiveBootSlot(slot)) {
+ cr.success = true;
+ cr.errMsg = "Success";
+ } else {
+ cr.success = false;
+ cr.errMsg = "Operation failed";
+ }
+ _hidl_cb(cr);
+ return Void();
+}
+
+Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {
+ struct CommandResult cr;
+ if (impl_.SetSlotAsUnbootable(slot)) {
+ cr.success = true;
+ cr.errMsg = "Success";
+ } else {
+ cr.success = false;
+ cr.errMsg = "Operation failed";
+ }
+ _hidl_cb(cr);
+ return Void();
+}
+
+Return<BoolResult> BootControl::isSlotBootable(uint32_t slot) {
+ if (!impl_.IsValidSlot(slot)) {
+ return BoolResult::INVALID_SLOT;
+ }
+ return impl_.IsSlotBootable(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) {
+ if (!impl_.IsValidSlot(slot)) {
+ return BoolResult::INVALID_SLOT;
+ }
+ return impl_.IsSlotMarkedSuccessful(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {
+ hidl_string ans;
+ const char* suffix = impl_.GetSuffix(slot);
+ if (suffix) {
+ ans = suffix;
+ }
+ _hidl_cb(ans);
+ return Void();
+}
+
+// Methods from ::android::hardware::boot::V1_1::IBootControl.
+Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus status) {
+ return impl_.SetSnapshotMergeStatus(status);
+}
+
+Return<MergeStatus> BootControl::getSnapshotMergeStatus() {
+ return impl_.GetSnapshotMergeStatus();
+}
+
+// Methods from ::android::hardware::boot::V1_2::IBootControl.
+Return<uint32_t> BootControl::getActiveBootSlot() {
+ return impl_.GetActiveBootSlot();
+}
+
+IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) {
+ auto module = std::make_unique<BootControl>();
+ if (!module->Init()) {
+ ALOGE("Could not initialize BootControl module");
+ return nullptr;
+ }
+ return module.release();
+}
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace boot
+} // namespace hardware
+} // namespace android
diff --git a/boot/1.2/default/BootControl.h b/boot/1.2/default/BootControl.h
new file mode 100644
index 0000000..5791699
--- /dev/null
+++ b/boot/1.2/default/BootControl.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <libboot_control/libboot_control.h>
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_2 {
+namespace implementation {
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_1::MergeStatus;
+using ::android::hardware::boot::V1_2::IBootControl;
+
+class BootControl : public IBootControl {
+ public:
+ bool Init();
+
+ // Methods from ::android::hardware::boot::V1_0::IBootControl.
+ Return<uint32_t> getNumberSlots() override;
+ Return<uint32_t> getCurrentSlot() override;
+ Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override;
+ Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override;
+ Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override;
+ Return<BoolResult> isSlotBootable(uint32_t slot) override;
+ Return<BoolResult> isSlotMarkedSuccessful(uint32_t slot) override;
+ Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::boot::V1_1::IBootControl.
+ Return<bool> setSnapshotMergeStatus(MergeStatus status) override;
+ Return<MergeStatus> getSnapshotMergeStatus() override;
+
+ // Methods from ::android::hardware::boot::V1_2::IBootControl.
+ Return<uint32_t> getActiveBootSlot() override;
+
+ private:
+ android::bootable::BootControl impl_;
+};
+
+extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name);
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace boot
+} // namespace hardware
+} // namespace android
diff --git a/boot/1.2/default/android.hardware.boot@1.2-service.rc b/boot/1.2/default/android.hardware.boot@1.2-service.rc
new file mode 100644
index 0000000..14926c0
--- /dev/null
+++ b/boot/1.2/default/android.hardware.boot@1.2-service.rc
@@ -0,0 +1,7 @@
+service vendor.boot-hal-1-2 /vendor/bin/hw/android.hardware.boot@1.2-service
+ interface android.hardware.boot@1.0::IBootControl default
+ interface android.hardware.boot@1.1::IBootControl default
+ interface android.hardware.boot@1.2::IBootControl default
+ class early_hal
+ user root
+ group root
diff --git a/boot/1.2/default/android.hardware.boot@1.2.xml b/boot/1.2/default/android.hardware.boot@1.2.xml
new file mode 100644
index 0000000..ba91e8f
--- /dev/null
+++ b/boot/1.2/default/android.hardware.boot@1.2.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.boot</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.2::IBootControl/default</fqname>
+ </hal>
+</manifest>
diff --git a/boot/1.2/default/service.cpp b/boot/1.2/default/service.cpp
new file mode 100644
index 0000000..3053957
--- /dev/null
+++ b/boot/1.2/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "android.hardware.boot@1.2-service"
+
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::defaultPassthroughServiceImplementation;
+using IBootControl_V1_0 = android::hardware::boot::V1_0::IBootControl;
+using IBootControl_V1_2 = android::hardware::boot::V1_2::IBootControl;
+
+int main(int /* argc */, char* /* argv */[]) {
+ return defaultPassthroughServiceImplementation<IBootControl_V1_0, IBootControl_V1_2>();
+}
diff --git a/boot/1.2/vts/functional/Android.bp b/boot/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..a7f5ccb
--- /dev/null
+++ b/boot/1.2/vts/functional/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_test {
+ name: "VtsHalBootV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBootV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
+ "libgmock",
+ ],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
+}
diff --git a/boot/1.2/vts/functional/VtsHalBootV1_2TargetTest.cpp b/boot/1.2/vts/functional/VtsHalBootV1_2TargetTest.cpp
new file mode 100644
index 0000000..9df23c3
--- /dev/null
+++ b/boot/1.2/vts/functional/VtsHalBootV1_2TargetTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "boot_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_0::CommandResult;
+using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::boot::V1_2::IBootControl;
+
+class BootHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ boot = IBootControl::getService(GetParam());
+ ASSERT_NE(boot, nullptr);
+
+ LOG(INFO) << "Test is remote " << boot->isRemote();
+ }
+
+ sp<IBootControl> boot;
+};
+
+auto generate_callback(CommandResult* dest) {
+ return [=](CommandResult cr) { *dest = cr; };
+}
+
+TEST_P(BootHidlTest, GetActiveBootSlot) {
+ Slot curSlot = boot->getCurrentSlot();
+ Slot otherSlot = curSlot ? 0 : 1;
+
+ // Set the active slot, then check if the getter returns the correct slot.
+ CommandResult cr;
+ Return<void> result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ Slot activeSlot = boot->getActiveBootSlot();
+ EXPECT_EQ(otherSlot, activeSlot);
+
+ result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ activeSlot = boot->getActiveBootSlot();
+ EXPECT_EQ(curSlot, activeSlot);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BootHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, BootHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBootControl::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 86f26e4..27e74f1 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -529,24 +529,29 @@
}
void CameraModule::removeCamera(int cameraId) {
- std::unordered_set<std::string> physicalIds;
- camera_metadata_t *metadata = const_cast<camera_metadata_t*>(
- mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
- common::V1_0::helper::CameraMetadata hidlMetadata(metadata);
+ // Skip HAL1 devices which isn't cached in mCameraInfoMap and don't advertise
+ // static_camera_characteristics
+ if (getDeviceVersion(cameraId) >= CAMERA_DEVICE_API_VERSION_3_0) {
+ std::unordered_set<std::string> physicalIds;
+ camera_metadata_t *metadata = const_cast<camera_metadata_t*>(
+ mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
+ common::V1_0::helper::CameraMetadata hidlMetadata(metadata);
- if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
- for (const auto& id : physicalIds) {
- int idInt = std::stoi(id);
- if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) {
- free_camera_metadata(mPhysicalCameraInfoMap[idInt]);
- mPhysicalCameraInfoMap.removeItem(idInt);
- } else {
- ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
- __FUNCTION__, id.c_str());
+ if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
+ for (const auto& id : physicalIds) {
+ int idInt = std::stoi(id);
+ if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) {
+ free_camera_metadata(mPhysicalCameraInfoMap[idInt]);
+ mPhysicalCameraInfoMap.removeItem(idInt);
+ } else {
+ ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
+ __FUNCTION__, id.c_str());
+ }
}
}
+ free_camera_metadata(metadata);
}
- free_camera_metadata(metadata);
+
mCameraInfoMap.removeItem(cameraId);
mDeviceVersionMap.removeItem(cameraId);
}
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index aa5c48f..9e2b077 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -1209,7 +1209,12 @@
return notify;
}
- if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) {
+ // Physical device results are only expected in the last/final
+ // partial result notification.
+ bool expectPhysicalResults = !(request->usePartialResult &&
+ (results.partialResult < request->numPartialResults));
+ if (expectPhysicalResults &&
+ (physicalCameraMetadata.size() != request->expectedPhysicalResults.size())) {
ALOGE("%s: Frame %d: Returned physical metadata count %zu "
"must be equal to expected count %zu", __func__, frameNumber,
physicalCameraMetadata.size(), request->expectedPhysicalResults.size());
@@ -1260,9 +1265,27 @@
ADD_FAILURE();
return notify;
}
- request->collectedResult.append(
- reinterpret_cast<const camera_metadata_t*>(
- resultMetadata.data()));
+
+ // Verify no duplicate tags between partial results
+ const camera_metadata_t* partialMetadata =
+ reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+ const camera_metadata_t* collectedMetadata = request->collectedResult.getAndLock();
+ camera_metadata_ro_entry_t searchEntry, foundEntry;
+ for (size_t i = 0; i < get_camera_metadata_size(partialMetadata); i++) {
+ if (0 != get_camera_metadata_ro_entry(partialMetadata, i, &searchEntry)) {
+ ADD_FAILURE();
+ request->collectedResult.unlock(collectedMetadata);
+ return notify;
+ }
+ if (-ENOENT !=
+ find_camera_metadata_ro_entry(collectedMetadata, searchEntry.tag, &foundEntry)) {
+ ADD_FAILURE();
+ request->collectedResult.unlock(collectedMetadata);
+ return notify;
+ }
+ }
+ request->collectedResult.unlock(collectedMetadata);
+ request->collectedResult.append(partialMetadata);
isPartialResult =
(results.partialResult < request->numPartialResults);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 57f390c..b16ae40 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -134,7 +134,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.boot</name>
- <version>1.1</version>
+ <version>1.2</version>
<interface>
<name>IBootControl</name>
<instance>default</instance>
@@ -319,6 +319,14 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.security.keymint</name>
+ <interface>
+ <name>IKeyMintDevice</name>
+ <instance>default</instance>
+ <instance>strongbox</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.light</name>
<interface>
<name>ILights</name>
@@ -422,6 +430,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.radio.config</name>
+ <version>1.3</version>
+ <interface>
+ <name>IRadioConfig</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.renderscript</name>
<version>1.0</version>
<interface>
@@ -521,7 +537,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.usb.gadget</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IUsbGadget</name>
<instance>default</instance>
@@ -534,6 +550,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.vibrator</name>
+ <interface>
+ <name>IVibratorManager</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.vr</name>
<version>1.0</version>
diff --git a/current.txt b/current.txt
index 7ef176b..8623fc0 100644
--- a/current.txt
+++ b/current.txt
@@ -769,10 +769,18 @@
# ABI preserving changes to HALs during Android S
1ca372cd67d197df099e87616a613ba6ede6552638a603e18f86c8834302c3d1 android.hardware.gnss@1.0::IGnssMeasurementCallback
6a271e493907e8ba20912e42771bd0d99ae45431a851d5675ef9496d02510a34 android.hardware.gnss@1.1::IGnssMeasurementCallback
+2c331a9605f3a08d9c1e0a36169ca57758bc43c11a78ef3f3730509885e52c15 android.hardware.graphics.composer@2.4::IComposerClient
3da3ce039247872d95c6bd48621dbfdfa1c2d2a91a90f257862f87ee2bc46300 android.hardware.health@2.1::types
+9679f27a42f75781c8993ef163ed92808a1928de186639834841d0b8e326e63d android.hardware.gatekeeper@1.0::IGatekeeper
+9c4eb603d7b9ad675a14edb6180681c5a78da5c6bdc7755853912c974a21f7e5 android.hardware.gnss@1.0::IAGnssCallback
+40456eb90ea88b62d18ad3fbf1da8917981cd55ac04ce69c8e058d49ff5beff4 android.hardware.keymaster@3.0::IKeymasterDevice
+6017b4f2481feb0fffceae81c62bc372c898998b2d8fe69fbd39859d3a315e5e android.hardware.keymaster@4.0::IKeymasterDevice
+dabe23dde7c9e3ad65c61def7392f186d7efe7f4216f9b6f9cf0863745b1a9f4 android.hardware.keymaster@4.1::IKeymasterDevice
cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
+e8c86c69c438da8d1549856c1bb3e2d1b8da52722f8235ff49a30f2cce91742c android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
+b9fbb6e2e061ed0960939d48b785e9700210add1f13ed32ecd688d0f1ca20ef7 android.hardware.renderscript@1.0::types
0f53d70e1eadf8d987766db4bf6ae2048004682168f4cab118da576787def3fa android.hardware.radio@1.0::types
38d65fb20c60a5b823298560fc0825457ecdc49603a4b4e94bf81511790737da android.hardware.radio@1.4::types
954c334efd80e8869b66d1ce5fe2755712d96ba4b3c38d415739c330af5fb4cb android.hardware.radio@1.5::types
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
index 28fd5b6..f5cb8e4 100644
--- a/gatekeeper/1.0/Android.bp
+++ b/gatekeeper/1.0/Android.bp
@@ -10,5 +10,5 @@
interfaces: [
"android.hidl.base@1.0",
],
- gen_java: true,
+ gen_java: false,
}
diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal
index 59dd7d1..84e8e06 100644
--- a/gatekeeper/1.0/IGatekeeper.hal
+++ b/gatekeeper/1.0/IGatekeeper.hal
@@ -15,6 +15,7 @@
*/
package android.hardware.gatekeeper@1.0;
+@SensitiveData
interface IGatekeeper {
/**
diff --git a/gnss/1.0/IAGnssCallback.hal b/gnss/1.0/IAGnssCallback.hal
index 81f1689..11a6a5d 100644
--- a/gnss/1.0/IAGnssCallback.hal
+++ b/gnss/1.0/IAGnssCallback.hal
@@ -42,7 +42,6 @@
/**
* Represents the status of AGNSS augmented to support IPv4.
*/
- @export(name="", value_prefix="GPS_")
struct AGnssStatusIpV4 {
AGnssType type;
AGnssStatusValue status;
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 9c498d5..ef43a34 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -18,6 +18,7 @@
"android.hardware.gnss@2.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@1.0",
+ "android.hardware.gnss-ndk_platform",
],
static_libs: [
"android.hardware.gnss@common-default-lib",
diff --git a/gnss/1.1/default/GnssDebug.cpp b/gnss/1.1/default/GnssDebug.cpp
index 252f4e6..39efcd2 100644
--- a/gnss/1.1/default/GnssDebug.cpp
+++ b/gnss/1.1/default/GnssDebug.cpp
@@ -37,8 +37,8 @@
.latitudeDegrees = gMockLatitudeDegrees,
.longitudeDegrees = gMockLongitudeDegrees,
.altitudeMeters = gMockAltitudeMeters,
- .speedMetersPerSec = kMockSpeedMetersPerSec,
- .bearingDegrees = kMockBearingDegrees,
+ .speedMetersPerSec = gMockSpeedMetersPerSec,
+ .bearingDegrees = gMockBearingDegrees,
.horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
.verticalAccuracyMeters = kMockVerticalAccuracyMeters,
.speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 37de55d..7da462f 100644
--- a/gnss/2.0/default/Android.bp
+++ b/gnss/2.0/default/Android.bp
@@ -29,7 +29,7 @@
"GnssMeasurement.cpp",
"GnssMeasurementCorrections.cpp",
"GnssVisibilityControl.cpp",
- "service.cpp"
+ "service.cpp",
],
shared_libs: [
"libhidlbase",
@@ -39,8 +39,9 @@
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.gnss@2.1",
"android.hardware.gnss@2.0",
- "android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss-ndk_platform",
],
static_libs: [
"android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 7739f90..63e5013 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -34,6 +34,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss-ndk_platform",
],
static_libs: [
"android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index 7950670..2bcecf4 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -19,10 +19,9 @@
#include <android/hardware/gnss/2.1/IGnss.h>
#include "v2_1/gnss_hal_test_template.h"
-using android::hardware::gnss::V2_1::IGnss;
-
// The main test class for GNSS HAL.
-class GnssHalTest : public GnssHalTestTemplate<IGnss> {
+class GnssHalTest : public android::hardware::gnss::common::GnssHalTestTemplate<
+ android::hardware::gnss::V2_1::IGnss> {
public:
/**
* IsGnssHalVersion_2_1:
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 7afd49c..deb80e8 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -27,6 +27,9 @@
using android::hardware::gnss::common::Utils;
+using android::hardware::gnss::V2_1::IGnssAntennaInfo;
+using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
+
using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
diff --git a/gnss/3.0/default/Android.bp b/gnss/3.0/default/Android.bp
index 2b33b32..bb3c467 100644
--- a/gnss/3.0/default/Android.bp
+++ b/gnss/3.0/default/Android.bp
@@ -36,6 +36,7 @@
"android.hardware.gnss@3.0",
"android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss-ndk_platform",
],
static_libs: [
"android.hardware.gnss@common-default-lib",
diff --git a/gnss/3.0/vts/functional/gnss_hal_test.h b/gnss/3.0/vts/functional/gnss_hal_test.h
index 387214e..be6d38c 100644
--- a/gnss/3.0/vts/functional/gnss_hal_test.h
+++ b/gnss/3.0/vts/functional/gnss_hal_test.h
@@ -19,7 +19,6 @@
#include <android/hardware/gnss/3.0/IGnss.h>
#include "v2_1/gnss_hal_test_template.h"
-using android::hardware::gnss::V3_0::IGnss;
-
// The main test class for GNSS HAL.
-class GnssHalTest : public GnssHalTestTemplate<IGnss> {};
\ No newline at end of file
+class GnssHalTest : public android::hardware::gnss::common::GnssHalTestTemplate<
+ android::hardware::gnss::V3_0::IGnss> {};
\ No newline at end of file
diff --git a/gnss/aidl/TEST_MAPPING b/gnss/aidl/TEST_MAPPING
new file mode 100644
index 0000000..c21c3e4
--- /dev/null
+++ b/gnss/aidl/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalGnssTargetTest"
+ }
+ ]
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
new file mode 100644
index 0000000..a0e8de4
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable ElapsedRealtime {
+ int flags;
+ long timestampNs;
+ double timeUncertaintyNs;
+ const int HAS_TIMESTAMP_NS = 1;
+ const int HAS_TIME_UNCERTAINTY_NS = 2;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
new file mode 100644
index 0000000..42b940e
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable GnssClock {
+ int gnssClockFlags;
+ int leapSecond;
+ long timeNs;
+ double timeUncertaintyNs;
+ long fullBiasNs;
+ double biasNs;
+ double biasUncertaintyNs;
+ double driftNsps;
+ double driftUncertaintyNsps;
+ int hwClockDiscontinuityCount;
+ android.hardware.gnss.GnssSignalType referenceSignalTypeForIsb;
+ const int HAS_LEAP_SECOND = 1;
+ const int HAS_TIME_UNCERTAINTY = 2;
+ const int HAS_FULL_BIAS = 4;
+ const int HAS_BIAS = 8;
+ const int HAS_BIAS_UNCERTAINTY = 16;
+ const int HAS_DRIFT = 32;
+ const int HAS_DRIFT_UNCERTAINTY = 64;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
new file mode 100644
index 0000000..7ffabd2
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable GnssData {
+ android.hardware.gnss.GnssMeasurement[] measurements;
+ android.hardware.gnss.GnssClock clock;
+ android.hardware.gnss.ElapsedRealtime elapsedRealtime;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
new file mode 100644
index 0000000..7d15855
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable GnssMeasurement {
+ int flags;
+ int svid;
+ android.hardware.gnss.GnssSignalType signalType;
+ double timeOffsetNs;
+ int state;
+ long receivedSvTimeInNs;
+ long receivedSvTimeUncertaintyInNs;
+ double antennaCN0DbHz;
+ double basebandCN0DbHz;
+ double pseudorangeRateMps;
+ double pseudorangeRateUncertaintyMps;
+ int accumulatedDeltaRangeState;
+ double accumulatedDeltaRangeM;
+ double accumulatedDeltaRangeUncertaintyM;
+ float carrierFrequencyHz;
+ long carrierCycles;
+ double carrierPhase;
+ double carrierPhaseUncertainty;
+ android.hardware.gnss.GnssMultipathIndicator multipathIndicator;
+ double snrDb;
+ double agcLevelDb;
+ double fullInterSignalBiasNs;
+ double fullInterSignalBiasUncertaintyNs;
+ double satelliteInterSignalBiasNs;
+ double satelliteInterSignalBiasUncertaintyNs;
+ const int HAS_SNR = 1;
+ const int HAS_CARRIER_FREQUENCY = 512;
+ const int HAS_CARRIER_CYCLES = 1024;
+ const int HAS_CARRIER_PHASE = 2048;
+ const int HAS_CARRIER_PHASE_UNCERTAINTY = 4096;
+ const int HAS_AUTOMATIC_GAIN_CONTROL = 8192;
+ const int HAS_FULL_ISB = 65536;
+ const int HAS_FULL_ISB_UNCERTAINTY = 131072;
+ const int HAS_SATELLITE_ISB = 262144;
+ const int HAS_SATELLITE_ISB_UNCERTAINTY = 524288;
+ const int STATE_UNKNOWN = 0;
+ const int STATE_CODE_LOCK = 1;
+ const int STATE_BIT_SYNC = 2;
+ const int STATE_SUBFRAME_SYNC = 4;
+ const int STATE_TOW_DECODED = 8;
+ const int STATE_MSEC_AMBIGUOUS = 16;
+ const int STATE_SYMBOL_SYNC = 32;
+ const int STATE_GLO_STRING_SYNC = 64;
+ const int STATE_GLO_TOD_DECODED = 128;
+ const int STATE_BDS_D2_BIT_SYNC = 256;
+ const int STATE_BDS_D2_SUBFRAME_SYNC = 512;
+ const int STATE_GAL_E1BC_CODE_LOCK = 1024;
+ const int STATE_GAL_E1C_2ND_CODE_LOCK = 2048;
+ const int STATE_GAL_E1B_PAGE_SYNC = 4096;
+ const int STATE_SBAS_SYNC = 8192;
+ const int STATE_TOW_KNOWN = 16384;
+ const int STATE_GLO_TOD_KNOWN = 32768;
+ const int STATE_2ND_CODE_LOCK = 65536;
+ const int ADR_STATE_UNKNOWN = 0;
+ const int ADR_STATE_VALID = 1;
+ const int ADR_STATE_RESET = 2;
+ const int ADR_STATE_CYCLE_SLIP = 4;
+ const int ADR_STATE_HALF_CYCLE_RESOLVED = 8;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
new file mode 100644
index 0000000..75ca3af
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@Backing(type="int") @VintfStability
+enum GnssMultipathIndicator {
+ UNKNOWN = 0,
+ PRESENT = 1,
+ NOT_PRESENT = 2,
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
new file mode 100644
index 0000000..d385fd4
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable GnssPowerStats {
+ android.hardware.gnss.ElapsedRealtime elapsedRealtime;
+ double totalEnergyMilliJoule;
+ double singlebandTrackingModeEnergyMilliJoule;
+ double multibandTrackingModeEnergyMilliJoule;
+ double singlebandAcquisitionModeEnergyMilliJoule;
+ double multibandAcquisitionModeEnergyMilliJoule;
+ double[] otherModesEnergyMilliJoule;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
new file mode 100644
index 0000000..3e66c4a
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable GnssSignalType {
+ android.hardware.gnss.GnssConstellationType constellation;
+ double carrierFrequencyHz;
+ String codeType;
+ const String CODE_TYPE_A = "A";
+ const String CODE_TYPE_B = "B";
+ const String CODE_TYPE_C = "C";
+ const String CODE_TYPE_D = "D";
+ const String CODE_TYPE_I = "I";
+ const String CODE_TYPE_L = "L";
+ const String CODE_TYPE_M = "M";
+ const String CODE_TYPE_N = "N";
+ const String CODE_TYPE_P = "P";
+ const String CODE_TYPE_Q = "Q";
+ const String CODE_TYPE_S = "S";
+ const String CODE_TYPE_W = "W";
+ const String CODE_TYPE_X = "X";
+ const String CODE_TYPE_Y = "Y";
+ const String CODE_TYPE_Z = "Z";
+ const String CODE_TYPE_UNKNOWN = "UNKNOWN";
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 146577e..10ac150 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -22,5 +22,7 @@
void close();
android.hardware.gnss.IGnssPsds getExtensionPsds();
android.hardware.gnss.IGnssConfiguration getExtensionGnssConfiguration();
+ android.hardware.gnss.IGnssMeasurementInterface getExtensionGnssMeasurement();
+ android.hardware.gnss.IGnssPowerIndication getExtensionGnssPowerIndication();
const int ERROR_INVALID_ARGUMENT = 1;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
new file mode 100644
index 0000000..e05e9b9
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssMeasurementCallback {
+ void gnssMeasurementCb(in android.hardware.gnss.GnssData data);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
new file mode 100644
index 0000000..9576205
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssMeasurementInterface {
+ void setCallback(in android.hardware.gnss.IGnssMeasurementCallback callback, in boolean enableFullTracking);
+ void close();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
new file mode 100644
index 0000000..843489e
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssPowerIndication {
+ void setCallback(in android.hardware.gnss.IGnssPowerIndicationCallback callback);
+ oneway void requestGnssPowerStats();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
new file mode 100644
index 0000000..5281d29
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssPowerIndicationCallback {
+ void setCapabilitiesCb(in int capabilities);
+ oneway void gnssPowerStatsCb(in android.hardware.gnss.GnssPowerStats gnssPowerStats);
+ const int CAPABILITY_TOTAL = 1;
+ const int CAPABILITY_SINGLEBAND_TRACKING = 2;
+ const int CAPABILITY_MULTIBAND_TRACKING = 4;
+ const int CAPABILITY_SINGLEBAND_ACQUISITION = 8;
+ const int CAPABILITY_MULTIBAND_ACQUISITION = 16;
+ const int CAPABILITY_OTHER_MODES = 32;
+}
diff --git a/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl
new file mode 100644
index 0000000..67d090e
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+/**
+ * Cumulative GNSS power statistics since boot.
+ */
+@VintfStability
+parcelable ElapsedRealtime {
+
+ /** Bit mask indicating a valid timestampNs is stored in the ElapsedRealtime parcelable. */
+ const int HAS_TIMESTAMP_NS = 1 << 0;
+
+ /**
+ * Bit mask indicating a valid timeUncertaintyNs is stored in the ElapsedRealtime parcelable.
+ */
+ const int HAS_TIME_UNCERTAINTY_NS = 1 << 1;
+
+ /**
+ * A bit field of flags indicating the validity of each field in this data structure.
+ *
+ * The bit masks are the constants with prefix HAS_.
+ *
+ * Fields may have invalid information in them, if not marked as valid by the corresponding bit
+ * in flags.
+ */
+ int flags;
+
+ /**
+ * Estimate of the elapsed time since boot value for the corresponding event in nanoseconds.
+ */
+ long timestampNs;
+
+ /**
+ * Estimate of the relative precision of the alignment of this SystemClock timestamp, with the
+ * reported measurements in nanoseconds (68% confidence).
+ */
+ double timeUncertaintyNs;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/android/hardware/gnss/GnssClock.aidl
new file mode 100644
index 0000000..f416e08
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssClock.aidl
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.GnssSignalType;
+
+/**
+ * Represents an estimate of the GNSS clock time.
+ */
+@VintfStability
+parcelable GnssClock {
+ /** Bit mask indicating a valid 'leap second' is stored in the GnssClock. */
+ const int HAS_LEAP_SECOND = 1 << 0;
+ /** Bit mask indicating a valid 'time uncertainty' is stored in the GnssClock. */
+ const int HAS_TIME_UNCERTAINTY = 1 << 1;
+ /** Bit mask indicating a valid 'full bias' is stored in the GnssClock. */
+ const int HAS_FULL_BIAS = 1 << 2;
+ /** Bit mask indicating a valid 'bias' is stored in the GnssClock. */
+ const int HAS_BIAS = 1 << 3;
+ /** Bit mask indicating a valid 'bias uncertainty' is stored in the GnssClock. */
+ const int HAS_BIAS_UNCERTAINTY = 1 << 4;
+ /** Bit mask indicating a valid 'drift' is stored in the GnssClock. */
+ const int HAS_DRIFT = 1 << 5;
+ /** Bit mask indicating a valid 'drift uncertainty' is stored in the GnssClock. */
+ const int HAS_DRIFT_UNCERTAINTY = 1 << 6;
+
+ /**
+ * A bitfield of flags indicating the validity of the fields in this data
+ * structure.
+ *
+ * The bit masks are the constants with perfix HAS_.
+ *
+ * Fields for which there is no corresponding flag must be filled in
+ * with a valid value. For convenience, these are marked as mandatory.
+ *
+ * Others fields may have invalid information in them, if not marked as
+ * valid by the corresponding bit in gnssClockFlags.
+ */
+ int gnssClockFlags;
+
+ /**
+ * Leap second data.
+ * The sign of the value is defined by the following equation:
+ * utcTimeNs = timeNs - (fullBiasNs + biasNs) - leapSecond *
+ * 1,000,000,000
+ *
+ * If this data is available, gnssClockFlags must contain
+ * HAS_LEAP_SECOND.
+ */
+ int leapSecond;
+
+ /**
+ * The GNSS receiver internal clock value. This is the local hardware clock
+ * value.
+ *
+ * For local hardware clock, this value is expected to be monotonically
+ * increasing while the hardware clock remains powered on. (For the case of a
+ * HW clock that is not continuously on, see the
+ * hwClockDiscontinuityCount field). The receiver's estimate of GNSS time
+ * can be derived by subtracting the sum of fullBiasNs and biasNs (when
+ * available) from this value.
+ *
+ * This GNSS time must be the best estimate of current GNSS time
+ * that GNSS receiver can achieve.
+ *
+ * Sub-nanosecond accuracy can be provided by means of the 'biasNs' field.
+ * The value contains the timeUncertaintyNs in it.
+ *
+ * This value is mandatory.
+ */
+ long timeNs;
+
+ /**
+ * 1-Sigma uncertainty associated with the clock's time in nanoseconds.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_TIME_UNCERTAINTY. Ths value is ideally zero, as the time
+ * 'latched' by timeNs is defined as the reference clock vs. which all
+ * other times (and corresponding uncertainties) are measured.
+ */
+ double timeUncertaintyNs;
+
+ /**
+ * The difference between hardware clock ('time' field) inside GNSS receiver
+ * and the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
+ *
+ * The sign of the value is defined by the following equation:
+ * local estimate of GPS time = timeNs - (fullBiasNs + biasNs)
+ *
+ * If receiver has computed time for a non-GPS constellation, the time offset of
+ * that constellation versus GPS time must be applied to fill this value.
+ *
+ * The error estimate for the sum of this and the biasNs is the biasUncertaintyNs.
+ *
+ * If the data is available gnssClockFlags must contain HAS_FULL_BIAS.
+ *
+ * This value is mandatory if the receiver has estimated GPS time.
+ */
+ long fullBiasNs;
+
+ /**
+ * Sub-nanosecond bias - used with fullBiasNS, see fullBiasNs for details.
+ *
+ * The error estimate for the sum of this and the fullBiasNs is the
+ * biasUncertaintyNs.
+ *
+ * If the data is available gnssClockFlags must contain HAS_BIAS.
+ *
+ * This value is mandatory if the receiver has estimated GPS time.
+ */
+ double biasNs;
+
+ /**
+ * 1-Sigma uncertainty associated with the local estimate of GNSS time (clock
+ * bias) in nanoseconds. The uncertainty is represented as an absolute
+ * (single sided) value.
+ *
+ * The caller is responsible for using this uncertainty (it can be very
+ * large before the GPS time has been fully resolved.)
+ *
+ * If the data is available gnssClockFlags must contain HAS_BIAS_UNCERTAINTY.
+ *
+ * This value is mandatory if the receiver has estimated GPS time.
+ */
+ double biasUncertaintyNs;
+
+ /**
+ * The clock's drift in nanoseconds (per second).
+ *
+ * A positive value means that the frequency is higher than the nominal
+ * frequency, and that the (fullBiasNs + biasNs) is growing more positive
+ * over time.
+ *
+ * If the data is available gnssClockFlags must contain HAS_DRIFT.
+ *
+ * This value is mandatory if the receiver has estimated GPS time.
+ */
+ double driftNsps;
+
+ /**
+ * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per
+ * second).
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available gnssClockFlags must contain HAS_DRIFT_UNCERTAINTY.
+ *
+ * This value is mandatory if the receiver has estimated GPS time.
+ */
+ double driftUncertaintyNsps;
+
+ /**
+ * This field must be incremented, when there are discontinuities in the
+ * hardware clock.
+ *
+ * A "discontinuity" is meant to cover the case of a switch from one source
+ * of clock to another. A single free-running crystal oscillator (XO)
+ * will generally not have any discontinuities, and this can be set and
+ * left at 0.
+ *
+ * If, however, the timeNs value (HW clock) is derived from a composite of
+ * sources, that is not as smooth as a typical XO, or is otherwise stopped &
+ * restarted, then this value shall be incremented each time a discontinuity
+ * occurs. (E.g. this value can start at zero at device boot-up and
+ * increment each time there is a change in clock continuity. In the
+ * unlikely event that this value reaches full scale, rollover (not
+ * clamping) is required, such that this value continues to change, during
+ * subsequent discontinuity events.)
+ *
+ * While this number stays the same, between GnssClock reports, it can be
+ * safely assumed that the timeNs value has been running continuously, e.g.
+ * derived from a single, high quality clock (XO like, or better, that is
+ * typically used during continuous GNSS signal sampling.)
+ *
+ * It is expected, esp. during periods where there are few GNSS signals
+ * available, that the HW clock be discontinuity-free as long as possible,
+ * as this avoids the need to use (waste) a GNSS measurement to fully
+ * re-solve for the GNSS clock bias and drift, when using the accompanying
+ * measurements, from consecutive GnssData reports.
+ *
+ * This value is mandatory.
+ */
+ int hwClockDiscontinuityCount;
+
+ /**
+ * Reference GNSS signal type for inter-signal bias.
+ */
+ GnssSignalType referenceSignalTypeForIsb;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
new file mode 100644
index 0000000..ed30c98
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.ElapsedRealtime;
+import android.hardware.gnss.GnssClock;
+import android.hardware.gnss.GnssMeasurement;
+
+/**
+ * Represents a reading of GNSS measurements. For devices launched in Android Q or newer, it is
+ * mandatory that these be provided, on request, when the GNSS receiver is searching/tracking
+ * signals.
+ *
+ * - Reporting of GNSS constellation measurements is mandatory.
+ * - Reporting of all tracked constellations are encouraged.
+ */
+@VintfStability
+parcelable GnssData {
+ /** The array of measurements. */
+ GnssMeasurement[] measurements;
+
+ /** The GNSS clock time reading. */
+ GnssClock clock;
+
+ /**
+ * Timing information of the GNSS data synchronized with SystemClock.elapsedRealtimeNanos()
+ * clock.
+ */
+ ElapsedRealtime elapsedRealtime;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
new file mode 100644
index 0000000..fae862b
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.GnssConstellationType;
+import android.hardware.gnss.GnssSignalType;
+import android.hardware.gnss.GnssMultipathIndicator;
+
+/**
+ * Represents a GNSS Measurement, it contains raw and computed information.
+ *
+ * All signal measurement information (e.g. svTime, pseudorangeRate, multipathIndicator) reported in
+ * this struct must be based on GNSS signal measurements only. You must not synthesize measurements
+ * by calculating or reporting expected measurements based on known or estimated position, velocity,
+ * or time.
+ */
+@VintfStability
+parcelable GnssMeasurement {
+ /** Bit mask indicating a valid 'snr' is stored in the GnssMeasurement. */
+ const int HAS_SNR = 1 << 0;
+ /** Bit mask indicating a valid 'carrier frequency' is stored in the GnssMeasurement. */
+ const int HAS_CARRIER_FREQUENCY = 1 << 9;
+ /** Bit mask indicating a valid 'carrier cycles' is stored in the GnssMeasurement. */
+ const int HAS_CARRIER_CYCLES = 1 << 10;
+ /** Bit mask indicating a valid 'carrier phase' is stored in the GnssMeasurement. */
+ const int HAS_CARRIER_PHASE = 1 << 11;
+ /** Bit mask indicating a valid 'carrier phase uncertainty' is stored in the GnssMeasurement. */
+ const int HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12;
+ /** Bit mask indicating a valid automatic gain control is stored in the GnssMeasurement. */
+ const int HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13;
+ /** Bit mask indicating a valid full inter-signal bias is stored in the GnssMeasurement. */
+ const int HAS_FULL_ISB = 1 << 16;
+ /**
+ * Bit mask indicating a valid full inter-signal bias uncertainty is stored in the
+ * GnssMeasurement.
+ */
+ const int HAS_FULL_ISB_UNCERTAINTY = 1 << 17;
+ /**
+ * Bit mask indicating a valid satellite inter-signal bias is stored in the GnssMeasurement.
+ */
+ const int HAS_SATELLITE_ISB = 1 << 18;
+ /**
+ * Bit mask indicating a valid satellite inter-signal bias uncertainty is stored in the
+ * GnssMeasurement.
+ */
+ const int HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19;
+
+ /**
+ * A bitfield of flags indicating the validity of the fields in this GnssMeasurement. The bit
+ * masks are defined in the constants with prefix HAS_*
+ *
+ * Fields for which there is no corresponding flag must be filled in with a valid value. For
+ * convenience, these are marked as mandatory.
+ *
+ * Others fields may have invalid information in them, if not marked as valid by the
+ * corresponding bit in flags.
+ */
+ int flags;
+
+ /**
+ * Satellite vehicle ID number, as defined in GnssSvInfo::svid
+ *
+ * This value is mandatory.
+ */
+ int svid;
+
+ /**
+ * Defines the constellation of the given SV.
+ *
+ * This value is mandatory.
+ */
+ GnssSignalType signalType;
+
+ /**
+ * Time offset at which the measurement was taken in nanoseconds.
+ * The reference receiver's time is specified by GnssData::clock::timeNs.
+ *
+ * The sign of timeOffsetNs is given by the following equation:
+ * measurement time = GnssClock::timeNs + timeOffsetNs
+ *
+ * It provides an individual time-stamp for the measurement, and allows
+ * sub-nanosecond accuracy. It may be zero if all measurements are
+ * aligned to a common time.
+ *
+ * This value is mandatory.
+ */
+ double timeOffsetNs;
+
+ /**
+ * Flags indicating the GNSS measurement state.
+ *
+ * The expected behavior here is for GNSS HAL to set all the flags that apply. For example, if
+ * the state for a satellite is only C/A code locked and bit synchronized, and there is still
+ * millisecond ambiguity, the state must be set as:
+ *
+ * STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_MSEC_AMBIGUOUS
+ *
+ * If GNSS is still searching for a satellite, the corresponding state must be set to
+ * STATE_UNKNOWN(0).
+ *
+ * The received satellite time is relative to the beginning of the system week for all
+ * constellations except for Glonass where it is relative to the beginning of the Glonass system
+ * day.
+ *
+ * The table below indicates the valid range of the received GNSS satellite time. These ranges
+ * depend on the constellation and code being tracked and the state of the tracking algorithms
+ * given by the getState method. If the state flag is set, then the valid measurement range is
+ * zero to the value in the table. The state flag with the widest range indicates the range of
+ * the received GNSS satellite time value.
+ *
+ * +---------------------------+--------------------+-----+-----------+--------------------+------+
+ * | |GPS/QZSS |GLNS |BDS |GAL |SBAS |
+ * +---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |State Flag |L1 |L5I |L5Q |L1OF |B1I |B1I |E1B |E1C |E5AQ |L1 |
+ * | |C/A | | | |(D1) |(D2)| | | |C/A |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_UNKNOWN |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_CODE_LOCK |1ms |1 ms |1 ms |1 ms |1 ms |1 ms|- |- |1 ms |1 ms |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_SYMBOL_SYNC |20ms |10 ms |1 ms |10 ms|20 ms |2 ms|4 ms |4 ms |1 ms |2 ms |
+ * | |(opt.)| |(opt.)| |(opt.)| |(opt.)|(opt.)|(opt.)| |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_BIT_SYNC |20 ms |20 ms |1 ms |20 ms|20 ms |- |8 ms |- |1 ms |4 ms |
+ * | | | |(opt.)| | | | | |(opt.)| |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_SUBFRAME_SYNC |6s |6s |- |2 s |6 s |- |- |- |100 ms|- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_TOW_DECODED |1 week|- |- |1 day|1 week|- |1 week|- |- |1 week|
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_TOW_KNOWN |1 week|- |- |1 day|1 week|- |1 week|- |- |1 week|
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GLO_STRING_SYNC |- |- |- |2 s |- |- |- |- |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GLO_TOD_DECODED |- |- |- |1 day|- |- |- |- |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GLO_TOD_KNOWN |- |- |- |1 day|- |- |- |- |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_BDS_D2_BIT_SYNC |- |- |- |- |- |2 ms|- |- |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_BDS_D2_SUBFRAME_SYNC |- |- |- |- |- |600 |- |- |- |- |
+ * | | | | | | |ms | | | | |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GAL_E1BC_CODE_LOCK |- |- |- |- |- |- |4 ms |4 ms |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GAL_E1C_2ND_CODE_LOCK|- |- |- |- |- |- |- |100 ms|- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_2ND_CODE_LOCK |- |10 ms |20 ms |- |- |- |- |100 ms|100 ms|- |
+ * | | |(opt.)| | | | | |(opt.)| | |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_GAL_E1B_PAGE_SYNC |- |- |- |- |- |- |2 s |- |- |- |
+ * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ * |STATE_SBAS_SYNC |- |- |- |- |- |- |- |- |- |1s |
+ * +---------------------------+------+------+------+-----+------+----+------+------+------+------+
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
+ * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
+ *
+ * Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be
+ * set accordingly, in the 'state' field. This value must be populated if 'state' !=
+ * STATE_UNKNOWN.
+ *
+ * Note on optional flags:
+ * - For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the
+ * same as the bit length.
+ * - For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are
+ * implied by STATE_CODE_LOCK.
+ * - STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC.
+ * - STATE_2ND_CODE_LOCK for E1C is optional since it is implied by
+ * STATE_GAL_E1C_2ND_CODE_LOCK.
+ * - For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by
+ * STATE_GAL_E1BC_CODE_LOCK.
+ */
+ const int STATE_UNKNOWN = 0;
+ const int STATE_CODE_LOCK = 1 << 0;
+ const int STATE_BIT_SYNC = 1 << 1;
+ const int STATE_SUBFRAME_SYNC = 1 << 2;
+ const int STATE_TOW_DECODED = 1 << 3;
+ const int STATE_MSEC_AMBIGUOUS = 1 << 4;
+ const int STATE_SYMBOL_SYNC = 1 << 5;
+ const int STATE_GLO_STRING_SYNC = 1 << 6;
+ const int STATE_GLO_TOD_DECODED = 1 << 7;
+ const int STATE_BDS_D2_BIT_SYNC = 1 << 8;
+ const int STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9;
+ const int STATE_GAL_E1BC_CODE_LOCK = 1 << 10;
+ const int STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11;
+ const int STATE_GAL_E1B_PAGE_SYNC = 1 << 12;
+ const int STATE_SBAS_SYNC = 1 << 13;
+ const int STATE_TOW_KNOWN = 1 << 14;
+ const int STATE_GLO_TOD_KNOWN = 1 << 15;
+ const int STATE_2ND_CODE_LOCK = 1 << 16;
+
+ /**
+ * A bitfield of flags indicating the GnssMeasurementState per satellite sync state. It
+ * represents the current sync state for the associated satellite.
+ *
+ * Based on the sync state, the 'received GNSS tow' field must be interpreted accordingly.
+ *
+ * The bit masks are defined in the constants with prefix STATE_.
+ *
+ * This value is mandatory.
+ */
+ int state;
+
+ /**
+ * The received GNSS Time-of-Week at the measurement time, in nanoseconds.
+ * For GNSS & QZSS, this is the received GNSS Time-of-Week at the
+ * measurement time, in nanoseconds. The value is relative to the
+ * beginning of the current GNSS week.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set
+ * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC set
+ * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED set
+ * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * Note: If there is any ambiguity in integer millisecond,
+ * STATE_MSEC_AMBIGUOUS must be set accordingly, in the
+ * 'state' field.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ *
+ * For Glonass, this is the received Glonass time of day, at the
+ * measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN set
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set
+ * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set
+ * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC set
+ * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED set
+ * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set
+ *
+ * Note: Time of day known refers to the case where it is possibly not
+ * decoded over the air but has been determined from other sources. If
+ * Time of day decoded is set then Time of day known must also be set.
+ *
+ * For Beidou, this is the received Beidou time of week,
+ * at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN set.
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set.
+ * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC set.
+ * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC set.
+ * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC set.
+ * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC set.
+ * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED set.
+ * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * For Galileo, this is the received Galileo time of week,
+ * at the measurement time in nanoseconds.
+ *
+ * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK set.
+ * E1C 2nd code lock : [ 0 100ms] : STATE_GAL_E1C_2ND_CODE_LOCK set.
+ * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC set.
+ * Time of week decoded : [ 0 1week] : STATE_TOW_DECODED is set.
+ * Time of week known : [ 0 1week] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * For SBAS, this is received SBAS time, at the measurement time in
+ * nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock: [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
+ * Message : [ 0 1s ] : STATE_SBAS_SYNC is set
+ */
+ long receivedSvTimeInNs;
+
+ /**
+ * 1-Sigma uncertainty of the Received GNSS Time-of-Week in nanoseconds.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ */
+ long receivedSvTimeUncertaintyInNs;
+
+ /**
+ * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+ * It contains the measured C/N0 value for the signal at the antenna port.
+ *
+ * If a signal has separate components (e.g. Pilot and Data channels) and
+ * the receiver only processes one of the components, then the reported
+ * antennaCN0DbHz reflects only the component that is processed.
+ *
+ * This value is mandatory.
+ */
+ double antennaCN0DbHz;
+
+ /**
+ * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains the
+ * measured C/N0 value for the signal measured at the baseband.
+ *
+ * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+ * which is reported in cN0DbHz.
+ *
+ * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+ * processes one of the components, then the reported basebandCN0DbHz reflects only the
+ * component that is processed.
+ *
+ * This value is mandatory.
+ */
+ double basebandCN0DbHz;
+
+ /**
+ * Pseudorange rate at the timestamp in m/s. The correction of a given
+ * Pseudorange Rate value includes corrections for receiver and satellite
+ * clock frequency errors. Ensure that this field is independent (see
+ * comment at top of GnssMeasurement struct.)
+ *
+ * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and
+ * provide GnssClock's 'drift' field as well. When providing the
+ * uncorrected pseudorange rate, do not apply the corrections described above.)
+ *
+ * The value includes the 'pseudorange rate uncertainty' in it.
+ * A positive 'uncorrected' value indicates that the SV is moving away from
+ * the receiver.
+ *
+ * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the
+ * sign of 'doppler shift' is given by the equation:
+ * pseudorange rate = -k * doppler shift (where k is a constant)
+ *
+ * This must be the most accurate pseudorange rate available, based on
+ * fresh signal measurements from this channel.
+ *
+ * It is mandatory that this value be provided at typical carrier phase PRR
+ * quality (few cm/sec per second of uncertainty, or better) - when signals
+ * are sufficiently strong & stable, e.g. signals from a GNSS simulator at >=
+ * 35 dB-Hz.
+ */
+ double pseudorangeRateMps;
+
+ /**
+ * 1-Sigma uncertainty of the pseudorangeRateMps.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * This value is mandatory.
+ */
+ double pseudorangeRateUncertaintyMps;
+
+
+ /**
+ * Flags indicating the Accumulated Delta Range's states.
+ *
+ * See the table below for a detailed interpretation of each state.
+ *
+ * +---------------------+-------------------+-----------------------------+
+ * | ADR_STATE | Time of relevance | Interpretation |
+ * +---------------------+-------------------+-----------------------------+
+ * | UNKNOWN | ADR(t) | No valid carrier phase |
+ * | | | information is available |
+ * | | | at time t. |
+ * +---------------------+-------------------+-----------------------------+
+ * | VALID | ADR(t) | Valid carrier phase |
+ * | | | information is available |
+ * | | | at time t. This indicates |
+ * | | | that this measurement can |
+ * | | | be used as a reference for |
+ * | | | future measurements. |
+ * | | | However, to compare it to |
+ * | | | previous measurements to |
+ * | | | compute delta range, |
+ * | | | other bits should be |
+ * | | | checked. Specifically, it |
+ * | | | can be used for delta range |
+ * | | | computation if it is valid |
+ * | | | and has no reset or cycle |
+ * | | | slip at this epoch i.e. |
+ * | | | if VALID_BIT == 1 && |
+ * | | | CYCLE_SLIP_BIT == 0 && |
+ * | | | RESET_BIT == 0. |
+ * +---------------------+-------------------+-----------------------------+
+ * | RESET | ADR(t) - ADR(t-1) | Carrier phase accumulation |
+ * | | | has been restarted between |
+ * | | | current time t and previous |
+ * | | | time t-1. This indicates |
+ * | | | that this measurement can |
+ * | | | be used as a reference for |
+ * | | | future measurements, but it |
+ * | | | should not be compared to |
+ * | | | previous measurements to |
+ * | | | compute delta range. |
+ * +---------------------+-------------------+-----------------------------+
+ * | CYCLE_SLIP | ADR(t) - ADR(t-1) | Cycle slip(s) have been |
+ * | | | detected between the |
+ * | | | current time t and previous |
+ * | | | time t-1. This indicates |
+ * | | | that this measurement can |
+ * | | | be used as a reference for |
+ * | | | future measurements. |
+ * | | | Clients can use a |
+ * | | | measurement with a cycle |
+ * | | | slip to compute delta range |
+ * | | | against previous |
+ * | | | measurements at their own |
+ * | | | risk. |
+ * +---------------------+-------------------+-----------------------------+
+ * | HALF_CYCLE_RESOLVED | ADR(t) | Half cycle ambiguity is |
+ * | | | resolved at time t. |
+ * +---------------------+-------------------+-----------------------------+
+ */
+ const int ADR_STATE_UNKNOWN = 0;
+ const int ADR_STATE_VALID = 1 << 0;
+ const int ADR_STATE_RESET = 1 << 1;
+ const int ADR_STATE_CYCLE_SLIP = 1 << 2;
+ const int ADR_STATE_HALF_CYCLE_RESOLVED = 1 << 3;
+
+ /**
+ * A bitfield of flags indicating the accumulated delta range's state. It indicates whether ADR
+ * is reset or there is a cycle slip(indicating loss of lock).
+ *
+ * The bit masks are defined in constants with prefix ADR_STATE_.
+ *
+ * This value is mandatory.
+ */
+ int accumulatedDeltaRangeState;
+
+ /**
+ * Accumulated delta range since the last channel reset in meters.
+ * A positive value indicates that the SV is moving away from the receiver.
+ *
+ * The sign of the 'accumulated delta range' and its relation to the sign of
+ * 'carrier phase' is given by the equation:
+ * accumulated delta range = -k * carrier phase (where k is a constant)
+ *
+ * This value must be populated if 'accumulated delta range state' !=
+ * ADR_STATE_UNKNOWN.
+ * However, it is expected that the data is only accurate when:
+ * 'accumulated delta range state' == ADR_STATE_VALID.
+ *
+ * The alignment of the phase measurement will not be adjusted by the receiver so the in-phase
+ * and quadrature phase components will have a quarter cycle offset as they do when transmitted
+ * from the satellites. If the measurement is from a combination of the in-phase and quadrature
+ * phase components, then the alignment of the phase measurement will be aligned to the in-phase
+ * component.
+ */
+ double accumulatedDeltaRangeM;
+
+ /**
+ * 1-Sigma uncertainty of the accumulated delta range in meters.
+ * This value must be populated if 'accumulated delta range state' !=
+ * ADR_STATE_UNKNOWN.
+ */
+ double accumulatedDeltaRangeUncertaintyM;
+
+ /**
+ * Carrier frequency of the signal tracked, for example it can be the
+ * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+ * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
+ * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
+ * for GPS.
+ *
+ * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+ * time, two raw measurement structs must be reported for this same
+ * satellite, in one of the measurement structs, all the values related
+ * to L1 must be filled, and in the other all of the values related to
+ * L5 must be filled.
+ *
+ * If the data is available, gnssMeasurementFlags must contain
+ * HAS_CARRIER_FREQUENCY.
+ */
+ float carrierFrequencyHz;
+
+ /**
+ * The number of full carrier cycles between the satellite and the
+ * receiver. The reference frequency is given by the field
+ * 'carrierFrequencyHz'. Indications of possible cycle slips and
+ * resets in the accumulation of this value can be inferred from the
+ * accumulatedDeltaRangeState flags.
+ *
+ * If the data is available, gnssMeasurementFlags must contain
+ * HAS_CARRIER_CYCLES.
+ */
+ long carrierCycles;
+
+ /**
+ * The RF phase detected by the receiver, in the range [0.0, 1.0].
+ * This is usually the fractional part of the complete carrier phase
+ * measurement.
+ *
+ * The reference frequency is given by the field 'carrierFrequencyHz'.
+ * The value contains the 'carrier-phase uncertainty' in it.
+ *
+ * If the data is available, gnssMeasurementFlags must contain
+ * HAS_CARRIER_PHASE.
+ */
+ double carrierPhase;
+
+ /**
+ * 1-Sigma uncertainty of the carrier-phase.
+ * If the data is available, gnssMeasurementFlags must contain
+ * HAS_CARRIER_PHASE_UNCERTAINTY.
+ */
+ double carrierPhaseUncertainty;
+
+ /**
+ * An enumeration that indicates the 'multipath' state of the event.
+ *
+ * The multipath Indicator is intended to report the presence of overlapping
+ * signals that manifest as distorted correlation peaks.
+ *
+ * - if there is a distorted correlation peak shape, report that multipath
+ * is MULTIPATH_INDICATOR_PRESENT.
+ * - if there is no distorted correlation peak shape, report
+ * MULTIPATH_INDICATOR_NOT_PRESENT
+ * - if signals are too weak to discern this information, report
+ * MULTIPATH_INDICATOR_UNKNOWN
+ *
+ * Example: when doing the standardized overlapping Multipath Performance
+ * test (3GPP TS 34.171) the Multipath indicator must report
+ * MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and
+ * contain multipath, and MULTIPATH_INDICATOR_NOT_PRESENT for those
+ * signals that are tracked and do not contain multipath.
+ */
+ GnssMultipathIndicator multipathIndicator;
+
+ /**
+ * Signal-to-noise ratio at correlator output in dB.
+ * If the data is available, GnssMeasurementFlags must contain HAS_SNR.
+ * This is the power ratio of the "correlation peak height above the
+ * observed noise floor" to "the noise RMS".
+ */
+ double snrDb;
+
+ /**
+ * Automatic gain control (AGC) level. AGC acts as a variable gain
+ * amplifier adjusting the power of the incoming signal. The AGC level
+ * may be used to indicate potential interference. When AGC is at a
+ * nominal level, this value must be set as 0. Higher gain (and/or lower
+ * input power) must be output as a positive number. Hence in cases of
+ * strong jamming, in the band of this signal, this value must go more
+ * negative.
+ *
+ * Note: Different hardware designs (e.g. antenna, pre-amplification, or
+ * other RF HW components) may also affect the typical output of this
+ * value on any given hardware design in an open sky test - the
+ * important aspect of this output is that changes in this value are
+ * indicative of changes on input signal power in the frequency band for
+ * this measurement.
+ */
+ double agcLevelDb;
+
+ /**
+ * The full inter-signal bias (ISB) in nanoseconds.
+ *
+ * This value is the sum of the estimated receiver-side and the space-segment-side inter-system
+ * bias, inter-frequency bias and inter-code bias, including
+ *
+ * - Receiver inter-constellation bias (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Receiver inter-frequency bias (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Receiver inter-code bias (with respect to the code type in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset (TauGps), BDS-GLO
+ * Time Offset (BGTO)) (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Group delay (e.g., Total Group Delay (TGD))
+ * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the code
+ * type in GnssClock.referenceSignalTypeForIsb)
+ *
+ * If a component of the above is already compensated in the provided
+ * GnssMeasurement.receivedSvTimeInNs, then it must not be included in the reported full ISB.
+ *
+ * The value does not include the inter-frequency Ionospheric bias.
+ *
+ * The full ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+ */
+ double fullInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the full inter-signal bias in nanoseconds.
+ */
+ double fullInterSignalBiasUncertaintyNs;
+
+ /**
+ * The satellite inter-signal bias in nanoseconds.
+ *
+ * This value is the sum of the space-segment-side inter-system bias, inter-frequency bias
+ * and inter-code bias, including
+ *
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset (TauGps), BDS-GLO
+ * Time Offset (BGTO)) (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Group delay (e.g., Total Group Delay (TGD))
+ * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the code
+ * type in GnssClock.referenceSignalTypeForIsb)
+ *
+ * The satellite ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+ */
+ double satelliteInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the satellite inter-signal bias in nanoseconds.
+ */
+ double satelliteInterSignalBiasUncertaintyNs;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl b/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl
new file mode 100644
index 0000000..ec1ce62
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+/**
+ * Enumeration of available values for the GNSS Measurement's multipath
+ * indicator.
+ */
+@VintfStability
+@Backing(type="int")
+enum GnssMultipathIndicator {
+ /** The indicator is not available or unknown. */
+ UNKNOWN = 0,
+ /** The measurement is indicated to be affected by multipath. */
+ PRESENT = 1,
+ /** The measurement is indicated to be not affected by multipath. */
+ NOT_PRESENT = 2,
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl b/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl
new file mode 100644
index 0000000..2bea44d
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.ElapsedRealtime;
+
+/**
+ * Cumulative GNSS power statistics since boot.
+ */
+@VintfStability
+parcelable GnssPowerStats {
+ /**
+ * Timing information of the GnssPowerStats synchronized with SystemClock.elapsedRealtimeNanos()
+ * clock.
+ */
+ ElapsedRealtime elapsedRealtime;
+
+ /**
+ * Total GNSS energy consumption in milli-joules (mWatt-seconds).
+ */
+ double totalEnergyMilliJoule;
+
+ /**
+ * Total energy consumption in milli-joules (mWatt-seconds) for which the GNSS engine is
+ * tracking signals of a single frequency band.
+ */
+ double singlebandTrackingModeEnergyMilliJoule;
+
+ /**
+ * Total energy consumption in milli-joules (mWatt-seconds) for which the GNSS engine is
+ * tracking signals of multiple frequency bands.
+ */
+ double multibandTrackingModeEnergyMilliJoule;
+
+ /**
+ * Total energy consumption in milli-joules (mWatt-seconds) for which the GNSS engine is
+ * acquiring signals of a single frequency band.
+ */
+ double singlebandAcquisitionModeEnergyMilliJoule;
+
+ /**
+ * Total energy consumption in milli-joules (mWatt-seconds) for which the GNSS engine is
+ * acquiring signals of multiple frequency bands.
+ */
+ double multibandAcquisitionModeEnergyMilliJoule;
+
+ /**
+ * Total energy consumption in milli-joules (mWatt-seconds) for which the GNSS engine is
+ * operating in each of the vendor-specific power modes.
+ */
+ double[] otherModesEnergyMilliJoule;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
new file mode 100644
index 0000000..a284fed
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.GnssConstellationType;
+
+/**
+ * Represents a GNSS signal type.
+ */
+@VintfStability
+parcelable GnssSignalType {
+ /**
+ * Constellation type of the SV that transmits the signal.
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Carrier frequency of the signal tracked, for example it can be the
+ * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+ * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
+ * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
+ * for GPS.
+ *
+ * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+ * time, two raw measurement structs must be reported for this same
+ * satellite, in one of the measurement structs, all the values related
+ * to L1 must be filled, and in the other all of the values related to
+ * L5 must be filled.
+ */
+ double carrierFrequencyHz;
+
+ /**
+ * GNSS signal code type "A" representing GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA.
+ */
+ const String CODE_TYPE_A = "A";
+
+ /**
+ * GNSS signal code type "B" representing GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB.
+ */
+ const String CODE_TYPE_B = "B";
+
+ /**
+ * GNSS signal code type "C" representing GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A,
+ * GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+ */
+ const String CODE_TYPE_C = "C";
+
+ /**
+ * GNSS signal code type "D" representing BDS B1C D.
+ */
+ const String CODE_TYPE_D = "D";
+
+ /**
+ * GNSS signal code type "I" representing GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I,
+ * GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+ */
+ const String CODE_TYPE_I = "I";
+
+ /**
+ * GNSS signal code type "L" representing GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L),
+ * LEX(6) L.
+ */
+ const String CODE_TYPE_L = "L";
+
+ /**
+ * GNSS signal code type "M" representing GPS L1M, GPS L2M.
+ */
+ const String CODE_TYPE_M = "M";
+
+ /**
+ * GNSS signal code type "N" representing GPS L1 codeless, GPS L2 codeless.
+ */
+ const String CODE_TYPE_N = "N";
+
+ /**
+ * GNSS signal code type "P" representing GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C P.
+ */
+ const String CODE_TYPE_P = "P";
+
+ /**
+ * GNSS signal code type "Q" representing GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q,
+ * GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+ */
+ const String CODE_TYPE_Q = "Q";
+
+ /**
+ * GNSS signal code type "S" represents GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M),
+ * LEX(6) S.
+ */
+ const String CODE_TYPE_S = "S";
+
+ /**
+ * GNSS signal code type "W" representing GPS L1 Z-tracking, GPS L2 Z-tracking.
+ */
+ const String CODE_TYPE_W = "W";
+
+ /**
+ * GNSS signal code type "X" representing GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q),
+ * GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q),
+ * GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
+ * LEX(6) (S+L), BDS B1 (I+Q), BDS B1C (D+P), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+ */
+ const String CODE_TYPE_X = "X";
+
+ /**
+ * GNSS signal code type "Y" representing GPS L1Y, GPS L2Y.
+ */
+ const String CODE_TYPE_Y = "Y";
+
+ /**
+ * GNSS signal code type "Z" representing GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF.
+ */
+ const String CODE_TYPE_Z = "Z";
+
+ /**
+ * GNSS signal code type "UNKNOWN" representing the GNSS Measurement's code type is unknown.
+ */
+ const String CODE_TYPE_UNKNOWN = "UNKNOWN";
+
+ /**
+ * The type of code that is currently being tracked in the GNSS signal.
+ *
+ * For high precision applications the type of code being tracked needs to be considered
+ * in-order to properly apply code specific corrections to the pseudorange measurements.
+ *
+ * The value is one of the constant Strings with prefix CODE_TYPE_ defined in this parcelable.
+ *
+ * This is used to specify the observation descriptor defined in GNSS Observation Data File
+ * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03,
+ * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for
+ * "A channel"). In the future, if for instance a code "G" was added in the official RINEX
+ * standard, "G" could be specified here.
+ */
+ String codeType;
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 24632aa..c815e2d 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -17,8 +17,10 @@
package android.hardware.gnss;
import android.hardware.gnss.IGnssCallback;
-import android.hardware.gnss.IGnssPsds;
import android.hardware.gnss.IGnssConfiguration;
+import android.hardware.gnss.IGnssMeasurementInterface;
+import android.hardware.gnss.IGnssPowerIndication;
+import android.hardware.gnss.IGnssPsds;
/**
* Represents the standard GNSS (Global Navigation Satellite System) interface.
@@ -65,6 +67,8 @@
/**
* This method returns the IGnssPsds interface.
*
+ * This method must return non-null.
+ *
* @return Handle to the IGnssPsds interface.
*/
IGnssPsds getExtensionPsds();
@@ -72,7 +76,27 @@
/**
* This method returns the IGnssConfiguration interface.
*
+ * This method must return non-null.
+ *
* @return Handle to the IGnssConfiguration interface.
*/
IGnssConfiguration getExtensionGnssConfiguration();
-}
\ No newline at end of file
+
+ /**
+ * This methods returns the IGnssMeasurementInterface interface.
+ *
+ * This method must return non-null.
+ *
+ * @return Handle to the IGnssMeasurementInterface interface.
+ */
+ IGnssMeasurementInterface getExtensionGnssMeasurement();
+
+ /**
+ * This method returns the IGnssPowerIndication interface.
+ *
+ * This method must return non-null.
+ *
+ * @return Handle to the IGnssPowerIndication interface.
+ */
+ IGnssPowerIndication getExtensionGnssPowerIndication();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl
new file mode 100644
index 0000000..328cf2a
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.GnssData;
+
+/**
+ * The callback interface to report GNSS Measurement from the HAL.
+ */
+@VintfStability
+interface IGnssMeasurementCallback {
+ /**
+ * Callback for the hal to pass a GnssData structure back to the client.
+ *
+ * @param data Contains a reading of GNSS measurements.
+ */
+ void gnssMeasurementCb(in GnssData data);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
new file mode 100644
index 0000000..fdeebde
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.IGnssMeasurementCallback;
+
+/**
+ * Extended interface for GNSS Measurement support.
+ */
+@VintfStability
+interface IGnssMeasurementInterface {
+ /**
+ * Initializes the interface and registers the callback routines with the HAL. After a
+ * successful call to 'setCallback' the HAL must begin to provide updates at an average
+ * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
+ * can be tolerated.)
+ *
+ * @param callback Handle to GnssMeasurement callback interface.
+ * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
+ * no clock discontinuities are expected and, when supported, carrier phase should be
+ * continuous in good signal conditions. All non-blocklisted, healthy constellations,
+ * satellites and frequency bands that the chipset supports must be reported in this mode.
+ * The GNSS chipset is allowed to consume more power in this mode. If false, API must
+ * optimize power via duty cycling, constellations and frequency limits, etc.
+ *
+ * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has
+ * already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC
+ * for any other error. The HAL must not generate any other updates upon returning this
+ * error code.
+ */
+ void setCallback(in IGnssMeasurementCallback callback, in boolean enableFullTracking);
+
+ /**
+ * Stops updates from the HAL, and unregisters the callback routines. After a call to close(),
+ * the previously registered callbacks must be considered invalid by the HAL.
+ *
+ * If close() is invoked without a previous setCallback, this function must perform
+ * no work.
+ */
+ void close();
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl b/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
new file mode 100644
index 0000000..93fdadc
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.IGnssPowerIndicationCallback;
+
+/**
+ * Extended interface for GNSS Power Indication support.
+ */
+@VintfStability
+interface IGnssPowerIndication {
+
+ /**
+ * Opens the IGnssPowerIndication interface and provides the callback routines to the HAL.
+ *
+ * @param callback Callback interface for IGnssPowerIndication.
+ */
+ void setCallback(in IGnssPowerIndicationCallback callback);
+
+ /**
+ * Requests the GNSS power statistics. One request call corresponds to one response callback
+ * from IGnssPowerIndicationCallback.gnssPowerStatsCb().
+ */
+ oneway void requestGnssPowerStats();
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
new file mode 100644
index 0000000..4474c0c
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 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.hardware.gnss;
+
+import android.hardware.gnss.GnssPowerStats;
+
+/**
+ * The callback interface to report GNSS Power Indication from the HAL.
+ */
+@VintfStability
+interface IGnssPowerIndicationCallback {
+
+ /** Capability bit mask indicating GNSS supports totalEnergyMilliJoule. */
+ const int CAPABILITY_TOTAL = 1 << 0;
+
+ /** Capability bit mask indicating GNSS supports singlebandTrackingModeEnergyMilliJoule. */
+ const int CAPABILITY_SINGLEBAND_TRACKING = 1 << 1;
+
+ /** Capability bit mask indicating GNSS supports multibandTrackingModeEnergyMilliJoule. */
+ const int CAPABILITY_MULTIBAND_TRACKING = 1 << 2;
+
+ /** Capability bit mask indicating GNSS supports singlebandAcquisitionModeEnergyMilliJoule. */
+ const int CAPABILITY_SINGLEBAND_ACQUISITION = 1 << 3;
+
+ /** Capability bit mask indicating GNSS supports multibandAcquisitionModeEnergyMilliJoule. */
+ const int CAPABILITY_MULTIBAND_ACQUISITION = 1 << 4;
+
+ /** Capability bit mask indicating GNSS supports otherModesEnergyMilliJoule. */
+ const int CAPABILITY_OTHER_MODES = 1 << 5;
+
+ /**
+ * Callback to inform framework the Power Indication specific capabilities of the GNSS HAL
+ * implementation.
+ *
+ * The GNSS HAL must call this method immediately after the framework opens the
+ * IGnssPowerIndication interface.
+ *
+ * @param capabilities Bitmask of CAPABILITY_* specifying the supported GNSS Power Indication
+ * capabilities.
+ */
+ void setCapabilitiesCb(in int capabilities);
+
+ /**
+ * Callback for the HAL to pass a GnssPowerStats structure back to the client.
+ *
+ * @param gnssPowerStats GNSS power statistics since boot.
+ */
+ oneway void gnssPowerStatsCb(in GnssPowerStats gnssPowerStats);
+}
\ No newline at end of file
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index 1fe43c3..6694ce6 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -47,8 +47,10 @@
srcs: [
"Gnss.cpp",
"GnssHidlHal.cpp",
+ "GnssPowerIndication.cpp",
"GnssPsds.cpp",
"GnssConfiguration.cpp",
+ "GnssMeasurementInterface.cpp",
"service.cpp",
],
static_libs: [
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index b4d92fd..02bad60 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -19,6 +19,8 @@
#include "Gnss.h"
#include <log/log.h>
#include "GnssConfiguration.h"
+#include "GnssMeasurementInterface.h"
+#include "GnssPowerIndication.h"
#include "GnssPsds.h"
namespace aidl::android::hardware::gnss {
@@ -65,4 +67,20 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Gnss::getExtensionGnssPowerIndication(
+ std::shared_ptr<IGnssPowerIndication>* iGnssPowerIndication) {
+ ALOGD("Gnss::getExtensionGnssPowerIndication");
+
+ *iGnssPowerIndication = SharedRefBase::make<GnssPowerIndication>();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionGnssMeasurement(
+ std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
+ ALOGD("Gnss::getExtensionGnssMeasurement");
+
+ *iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 61d7cf7..bccc7f2 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -18,6 +18,8 @@
#include <aidl/android/hardware/gnss/BnGnss.h>
#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
+#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
+#include <aidl/android/hardware/gnss/BnGnssPowerIndication.h>
#include <aidl/android/hardware/gnss/BnGnssPsds.h>
#include "GnssConfiguration.h"
@@ -30,6 +32,10 @@
ndk::ScopedAStatus getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) override;
ndk::ScopedAStatus getExtensionGnssConfiguration(
std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) override;
+ ndk::ScopedAStatus getExtensionGnssPowerIndication(
+ std::shared_ptr<IGnssPowerIndication>* iGnssPowerIndication) override;
+ ndk::ScopedAStatus getExtensionGnssMeasurement(
+ std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) override;
std::shared_ptr<GnssConfiguration> mGnssConfiguration;
diff --git a/gnss/aidl/default/GnssConfiguration.h b/gnss/aidl/default/GnssConfiguration.h
index 25fa16e..491733c 100644
--- a/gnss/aidl/default/GnssConfiguration.h
+++ b/gnss/aidl/default/GnssConfiguration.h
@@ -24,8 +24,6 @@
namespace aidl::android::hardware::gnss {
-using android::hardware::gnss::GnssConstellationType;
-
struct BlocklistedSourceHash {
inline int operator()(const BlocklistedSource& source) const {
return int(source.constellation) * 1000 + int(source.svid);
@@ -42,7 +40,8 @@
using std::vector;
using BlocklistedSourceSet =
std::unordered_set<BlocklistedSource, BlocklistedSourceHash, BlocklistedSourceEqual>;
-using BlocklistedConstellationSet = std::unordered_set<GnssConstellationType>;
+using BlocklistedConstellationSet =
+ std::unordered_set<android::hardware::gnss::GnssConstellationType>;
struct GnssConfiguration : public BnGnssConfiguration {
public:
diff --git a/gnss/aidl/default/GnssHidlHal.cpp b/gnss/aidl/default/GnssHidlHal.cpp
index 11fc806..9529ec9 100644
--- a/gnss/aidl/default/GnssHidlHal.cpp
+++ b/gnss/aidl/default/GnssHidlHal.cpp
@@ -17,11 +17,10 @@
#define LOG_TAG "GnssHidlHal"
#include "GnssHidlHal.h"
-//#include <android/hardware/gnss/1.0/IGnssCallback.h>
namespace aidl::android::hardware::gnss {
-namespace V1_0 = ::android::hardware::gnss::V1_0;
+using GnssSvInfo = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
GnssHidlHal::GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl) : mGnssAidl(gnssAidl) {
Gnss* iGnss = mGnssAidl.get();
@@ -45,8 +44,8 @@
if (mGnssConfigurationAidl->isBlocklistedV2_1(gnssSvInfoList[i])) {
ALOGD("Blocklisted constellation: %d, svid: %d",
(int)gnssSvInfoList[i].v2_0.constellation, gnssSvInfoList[i].v2_0.v1_0.svid);
- gnssSvInfoList[i].v2_0.v1_0.svFlag &=
- ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+ gnssSvInfoList[i].v2_0.v1_0.svFlag &= ~static_cast<uint8_t>(
+ ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
}
}
return gnssSvInfoList;
diff --git a/gnss/aidl/default/GnssHidlHal.h b/gnss/aidl/default/GnssHidlHal.h
index 50aad3a..93a79a1 100644
--- a/gnss/aidl/default/GnssHidlHal.h
+++ b/gnss/aidl/default/GnssHidlHal.h
@@ -22,16 +22,16 @@
namespace aidl::android::hardware::gnss {
-using ::android::hardware::gnss::common::implementation::GnssTemplate;
-using GnssSvInfo = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
-
-class GnssHidlHal : public GnssTemplate<::android::hardware::gnss::V2_1::IGnss> {
+class GnssHidlHal : public ::android::hardware::gnss::common::implementation::GnssTemplate<
+ ::android::hardware::gnss::V2_1::IGnss> {
public:
GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl);
private:
- hidl_vec<GnssSvInfo> filterBlocklistedSatellitesV2_1(
- hidl_vec<GnssSvInfo> gnssSvInfoList) override;
+ hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>
+ filterBlocklistedSatellitesV2_1(
+ hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo> gnssSvInfoList)
+ override;
std::shared_ptr<Gnss> mGnssAidl;
std::shared_ptr<GnssConfiguration> mGnssConfigurationAidl;
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
new file mode 100644
index 0000000..d726d95
--- /dev/null
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssMeasIfaceAidl"
+
+#include "GnssMeasurementInterface.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+#include "Utils.h"
+
+namespace aidl::android::hardware::gnss {
+
+using Utils = ::android::hardware::gnss::common::Utils;
+
+std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
+
+GnssMeasurementInterface::GnssMeasurementInterface() : mMinIntervalMillis(1000) {}
+
+GnssMeasurementInterface::~GnssMeasurementInterface() {
+ stop();
+}
+
+ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
+ const std::shared_ptr<IGnssMeasurementCallback>& callback, const bool enableFullTracking) {
+ ALOGD("setCallback: enableFullTracking: %d", (int)enableFullTracking);
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+ stop();
+ }
+ start();
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssMeasurementInterface::close() {
+ ALOGD("close");
+ stop();
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = nullptr;
+ return ndk::ScopedAStatus::ok();
+}
+
+void GnssMeasurementInterface::start() {
+ ALOGD("start");
+ mIsActive = true;
+ mThread = std::thread([this]() {
+ while (mIsActive == true) {
+ auto measurement = Utils::getMockMeasurement();
+ this->reportMeasurement(measurement);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
+ }
+ });
+}
+
+void GnssMeasurementInterface::stop() {
+ ALOGD("stop");
+ mIsActive = false;
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
+ ALOGD("reportMeasurement()");
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sCallback == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+ return;
+ }
+ sCallback->gnssMeasurementCb(data);
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
new file mode 100644
index 0000000..69cd871
--- /dev/null
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssMeasurementCallback.h>
+#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssMeasurementInterface : public BnGnssMeasurementInterface {
+ public:
+ GnssMeasurementInterface();
+ ~GnssMeasurementInterface();
+ ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssMeasurementCallback>& callback,
+ const bool enableFullTracking) override;
+ ndk::ScopedAStatus close() override;
+
+ private:
+ void start();
+ void stop();
+ void reportMeasurement(const GnssData&);
+
+ std::atomic<long> mMinIntervalMillis;
+ std::atomic<bool> mIsActive;
+ std::thread mThread;
+
+ // Guarded by mMutex
+ static std::shared_ptr<IGnssMeasurementCallback> sCallback;
+
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPowerIndication.cpp b/gnss/aidl/default/GnssPowerIndication.cpp
new file mode 100644
index 0000000..429cc8c
--- /dev/null
+++ b/gnss/aidl/default/GnssPowerIndication.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssPowerIndicationAidl"
+
+#include "GnssPowerIndication.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IGnssPowerIndicationCallback> GnssPowerIndication::sCallback = nullptr;
+
+ndk::ScopedAStatus GnssPowerIndication::setCallback(
+ const std::shared_ptr<IGnssPowerIndicationCallback>& callback) {
+ ALOGD("setCallback");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ sCallback->setCapabilitiesCb(IGnssPowerIndicationCallback::CAPABILITY_TOTAL |
+ IGnssPowerIndicationCallback::CAPABILITY_SINGLEBAND_TRACKING |
+ IGnssPowerIndicationCallback::CAPABILITY_MULTIBAND_TRACKING |
+ IGnssPowerIndicationCallback::CAPABILITY_SINGLEBAND_ACQUISITION |
+ IGnssPowerIndicationCallback::CAPABILITY_MULTIBAND_ACQUISITION |
+ IGnssPowerIndicationCallback::CAPABILITY_OTHER_MODES);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssPowerIndication::requestGnssPowerStats() {
+ ALOGD("requestGnssPowerStats");
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ ElapsedRealtime elapsedRealtime = {
+ .flags = ElapsedRealtime::HAS_TIMESTAMP_NS | ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = ::android::elapsedRealtimeNano(),
+ .timeUncertaintyNs = 1000,
+ };
+ GnssPowerStats gnssPowerStats = {
+ .elapsedRealtime = elapsedRealtime,
+ .totalEnergyMilliJoule = 1.59975e+3,
+ .singlebandTrackingModeEnergyMilliJoule = 1.2342e+3,
+ .multibandTrackingModeEnergyMilliJoule = 3.653e+2,
+ .otherModesEnergyMilliJoule = {1.232e+2, 3.234e+3},
+ };
+ sCallback->gnssPowerStatsCb(gnssPowerStats);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPowerIndication.h b/gnss/aidl/default/GnssPowerIndication.h
new file mode 100644
index 0000000..e32fd72
--- /dev/null
+++ b/gnss/aidl/default/GnssPowerIndication.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssPowerIndication.h>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssPowerIndication : public BnGnssPowerIndication {
+ public:
+ ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<IGnssPowerIndicationCallback>& callback) override;
+ ndk::ScopedAStatus requestGnssPowerStats() override;
+
+ private:
+ // Guarded by mMutex
+ static std::shared_ptr<IGnssPowerIndicationCallback> sCallback;
+
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index 48a0e21..c10e809 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -22,6 +22,8 @@
"gnss_hal_test.cpp",
"gnss_hal_test_cases.cpp",
"GnssCallbackAidl.cpp",
+ "GnssMeasurementCallbackAidl.cpp",
+ "GnssPowerIndicationCallback.cpp",
"VtsHalGnssTargetTest.cpp",
],
shared_libs: [
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
new file mode 100644
index 0000000..c4fad7f
--- /dev/null
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssMeasurementCallbackAidl"
+
+#include "GnssMeasurementCallbackAidl.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+using android::hardware::gnss::GnssData;
+
+android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
+ ALOGI("gnssMeasurementCb");
+ ALOGI("elapsedRealtime: flags = %d, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+ gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
+ gnssData.elapsedRealtime.timeUncertaintyNs);
+ for (const auto& measurement : gnssData.measurements) {
+ ALOGI("measurement.receivedSvTimeInNs=%" PRId64, measurement.receivedSvTimeInNs);
+ }
+ gnss_data_cbq_.store(gnssData);
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.h b/gnss/aidl/vts/GnssMeasurementCallbackAidl.h
new file mode 100644
index 0000000..f6c79cf
--- /dev/null
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnGnssMeasurementCallback.h>
+#include "GnssCallbackEventQueue.h"
+
+/** Implementation for IGnssMeasurementCallback. */
+class GnssMeasurementCallbackAidl : public android::hardware::gnss::BnGnssMeasurementCallback {
+ public:
+ GnssMeasurementCallbackAidl() : gnss_data_cbq_("gnss_data") {}
+ ~GnssMeasurementCallbackAidl() {}
+
+ android::binder::Status gnssMeasurementCb(
+ const android::hardware::gnss::GnssData& gnssData) override;
+
+ android::hardware::gnss::common::GnssCallbackEventQueue<android::hardware::gnss::GnssData>
+ gnss_data_cbq_;
+};
diff --git a/gnss/aidl/vts/GnssPowerIndicationCallback.cpp b/gnss/aidl/vts/GnssPowerIndicationCallback.cpp
new file mode 100644
index 0000000..1cbfc20
--- /dev/null
+++ b/gnss/aidl/vts/GnssPowerIndicationCallback.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssPwrIndCallback"
+
+#include "GnssPowerIndicationCallback.h"
+#include <log/log.h>
+
+using android::hardware::gnss::GnssPowerStats;
+
+android::binder::Status GnssPowerIndicationCallback::setCapabilitiesCb(const int capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return android::binder::Status::ok();
+}
+
+android::binder::Status GnssPowerIndicationCallback::gnssPowerStatsCb(
+ const GnssPowerStats& gnssPowerStats) {
+ ALOGI("gnssPowerStatsCb");
+ ALOGI("elapsedRealtime: %ld, totalEnergyMilliJoule: %f",
+ (long)gnssPowerStats.elapsedRealtime.timestampNs, gnssPowerStats.totalEnergyMilliJoule);
+ ALOGI("singlebandTrackingModeEnergyMilliJoule: %f, multibandTrackingModeEnergyMilliJoule: %f",
+ gnssPowerStats.singlebandTrackingModeEnergyMilliJoule,
+ gnssPowerStats.multibandTrackingModeEnergyMilliJoule);
+ ALOGI("singlebandAcquisitionModeEnergyMilliJoule: %f, "
+ "multibandAcquisitionModeEnergyMilliJoule: %f",
+ gnssPowerStats.singlebandAcquisitionModeEnergyMilliJoule,
+ gnssPowerStats.multibandAcquisitionModeEnergyMilliJoule);
+ for (const auto& otherModeEnergyMilliJoule : gnssPowerStats.otherModesEnergyMilliJoule) {
+ ALOGI("otherModeEnergyMilliJoule: %f", otherModeEnergyMilliJoule);
+ }
+ gnss_power_stats_cbq_.store(gnssPowerStats);
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssPowerIndicationCallback.h b/gnss/aidl/vts/GnssPowerIndicationCallback.h
new file mode 100644
index 0000000..3416f17
--- /dev/null
+++ b/gnss/aidl/vts/GnssPowerIndicationCallback.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnGnssPowerIndicationCallback.h>
+#include <android/hardware/gnss/GnssPowerStats.h>
+#include "GnssCallbackEventQueue.h"
+
+/** Implementation for IGnssPowerIndicationCallback. */
+class GnssPowerIndicationCallback : public android::hardware::gnss::BnGnssPowerIndicationCallback {
+ public:
+ GnssPowerIndicationCallback()
+ : capabilities_cbq_("capabilities"),
+ gnss_power_stats_cbq_("gnss_power_stats") {}
+ ~GnssPowerIndicationCallback() {}
+
+ android::binder::Status setCapabilitiesCb(const int capabilities) override;
+ android::binder::Status gnssPowerStatsCb(
+ const android::hardware::gnss::GnssPowerStats& gnssPowerStats) override;
+
+ android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+ int last_capabilities_;
+ android::hardware::gnss::common::GnssCallbackEventQueue<android::hardware::gnss::GnssPowerStats>
+ gnss_power_stats_cbq_;
+ android::hardware::gnss::GnssPowerStats last_gnss_power_stats_;
+};
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index eb5301e..f72f7fe 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -36,7 +36,7 @@
using android::hardware::gnss::IGnssConfiguration;
// The main test class for GNSS HAL.
-class GnssHalTest : public GnssHalTestTemplate<IGnss_V2_1> {
+class GnssHalTest : public android::hardware::gnss::common::GnssHalTestTemplate<IGnss_V2_1> {
public:
GnssHalTest(){};
~GnssHalTest(){};
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 2b8a447..857c742 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -16,16 +16,30 @@
#define LOG_TAG "GnssHalTestCases"
+#include <android/hardware/gnss/IGnss.h>
+#include <android/hardware/gnss/IGnssMeasurementCallback.h>
+#include <android/hardware/gnss/IGnssMeasurementInterface.h>
+#include <android/hardware/gnss/IGnssPowerIndication.h>
#include <android/hardware/gnss/IGnssPsds.h>
+#include "GnssMeasurementCallbackAidl.h"
+#include "GnssPowerIndicationCallback.h"
#include "gnss_hal_test.h"
using android::sp;
using android::hardware::gnss::BlocklistedSource;
-using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::ElapsedRealtime;
+using android::hardware::gnss::GnssClock;
+using android::hardware::gnss::GnssMeasurement;
+using android::hardware::gnss::IGnss;
using android::hardware::gnss::IGnssConfiguration;
+using android::hardware::gnss::IGnssMeasurementCallback;
+using android::hardware::gnss::IGnssMeasurementInterface;
+using android::hardware::gnss::IGnssPowerIndication;
using android::hardware::gnss::IGnssPsds;
using android::hardware::gnss::PsdsType;
+using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+
/*
* SetupTeardownCreateCleanup:
* Requests the gnss HAL then calls cleanup
@@ -37,7 +51,7 @@
/*
* TestPsdsExtension:
* 1. Gets the PsdsExtension and verifies that it returns a non-null extension.
- * 2. Injects empty PSDS data and verifies that it returns false.
+ * 2. Injects empty PSDS data and verifies that it returns an error.
*/
TEST_P(GnssHalTest, TestPsdsExtension) {
sp<IGnssPsds> iGnssPsds;
@@ -46,7 +60,91 @@
ASSERT_TRUE(iGnssPsds != nullptr);
status = iGnssPsds->injectPsdsData(PsdsType::LONG_TERM, std::vector<uint8_t>());
+ ASSERT_FALSE(status.isOk());
+}
+
+/*
+ * TestGnssMeasurementExtension:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Sets a GnssMeasurementCallback, waits for a measurement, and verifies fields are valid.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
+ const int kFirstGnssMeasurementTimeoutSeconds = 10;
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ status = iGnssMeasurement->setCallback(callback, /* enableFullTracking= */ true);
+ ASSERT_TRUE(status.isOk());
+
+ android::hardware::gnss::GnssData lastMeasurement;
+ ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
+ kFirstGnssMeasurementTimeoutSeconds));
+ EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), 1);
+ ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+
+ // Validity check GnssData fields
+ ASSERT_TRUE(
+ lastMeasurement.elapsedRealtime.flags >= 0 &&
+ lastMeasurement.elapsedRealtime.flags <=
+ (ElapsedRealtime::HAS_TIMESTAMP_NS | ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS));
+ if (lastMeasurement.elapsedRealtime.flags & ElapsedRealtime::HAS_TIMESTAMP_NS) {
+ ASSERT_TRUE(lastMeasurement.elapsedRealtime.timestampNs > 0);
+ }
+ if (lastMeasurement.elapsedRealtime.flags & ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS) {
+ ASSERT_TRUE(lastMeasurement.elapsedRealtime.timeUncertaintyNs > 0);
+ }
+ ASSERT_TRUE(lastMeasurement.clock.gnssClockFlags >= 0 &&
+ lastMeasurement.clock.gnssClockFlags <=
+ (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
+ GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
+ GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
+ GnssClock::HAS_DRIFT_UNCERTAINTY));
+ for (const auto& measurement : lastMeasurement.measurements) {
+ ASSERT_TRUE(
+ measurement.flags >= 0 &&
+ measurement.flags <=
+ (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
+ GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
+ GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
+ GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
+ GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
+ GnssMeasurement::HAS_SATELLITE_ISB |
+ GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY));
+ }
+
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestGnssPowerIndication
+ * 1. Gets the GnssPowerIndicationExtension.
+ * 2. Sets a GnssPowerIndicationCallback.
+ * 3.
+ */
+TEST_P(GnssHalTest, TestGnssPowerIndication) {
+ sp<IGnssPowerIndication> iGnssPowerIndication;
+ auto status = aidl_gnss_hal_->getExtensionGnssPowerIndication(&iGnssPowerIndication);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssPowerIndication != nullptr);
+
+ auto gnssPowerIndicationCallback = sp<GnssPowerIndicationCallback>::make();
+ status = iGnssPowerIndication->setCallback(gnssPowerIndicationCallback);
+ ASSERT_TRUE(status.isOk());
+
+ const int kTimeoutSec = 2;
+ EXPECT_TRUE(gnssPowerIndicationCallback->capabilities_cbq_.retrieve(
+ gnssPowerIndicationCallback->last_capabilities_, kTimeoutSec));
+
+ EXPECT_EQ(gnssPowerIndicationCallback->capabilities_cbq_.calledCount(), 1);
+
+ iGnssPowerIndication->requestGnssPowerStats();
+ EXPECT_TRUE(gnssPowerIndicationCallback->gnss_power_stats_cbq_.retrieve(
+ gnssPowerIndicationCallback->last_gnss_power_stats_, kTimeoutSec));
+ EXPECT_EQ(gnssPowerIndicationCallback->gnss_power_stats_cbq_.calledCount(), 1);
}
/*
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 730de4b..be1d532 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -42,5 +42,6 @@
"android.hardware.gnss@2.1",
"android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss-ndk_platform",
],
}
diff --git a/gnss/common/utils/default/MockLocation.cpp b/gnss/common/utils/default/MockLocation.cpp
index 2d8e7c5..c90075f 100644
--- a/gnss/common/utils/default/MockLocation.cpp
+++ b/gnss/common/utils/default/MockLocation.cpp
@@ -21,5 +21,7 @@
float gMockLatitudeDegrees{37.4219999};
float gMockLongitudeDegrees{-122.0840575};
float gMockAltitudeMeters{1.60062531};
+float gMockBearingDegrees{0};
+float gMockSpeedMetersPerSec{0};
} // namespace android::hardware::gnss::common
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index fa83634..dd932d4 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -17,6 +17,7 @@
#include <Constants.h>
#include <MockLocation.h>
#include <Utils.h>
+#include <aidl/android/hardware/gnss/BnGnss.h>
#include <utils/SystemClock.h>
namespace android {
@@ -24,16 +25,28 @@
namespace gnss {
namespace common {
+using IGnss = aidl::android::hardware::gnss::IGnss;
+using IGnssMeasurementCallback = aidl::android::hardware::gnss::IGnssMeasurementCallback;
+using GnssMeasurement = aidl::android::hardware::gnss::GnssMeasurement;
using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags;
using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
-using ElapsedRealtime = V2_0::ElapsedRealtime;
+using ElapsedRealtime = aidl::android::hardware::gnss::ElapsedRealtime;
using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags;
using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback;
using GnssSignalType = V2_1::GnssSignalType;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo;
+using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo;
+using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo;
+using Row = V2_1::IGnssAntennaInfoCallback::Row;
+using Coord = V2_1::IGnssAntennaInfoCallback::Coord;
+
GnssDataV2_1 Utils::getMockMeasurementV2_1() {
GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0();
V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = {
@@ -110,7 +123,7 @@
.driftUncertaintyNsps = 310.64968328491528,
.hwClockDiscontinuityCount = 1};
- ElapsedRealtime timestamp = {
+ V2_0::ElapsedRealtime timestamp = {
.flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
.timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
@@ -124,6 +137,52 @@
return gnssData;
}
+aidl::android::hardware::gnss::GnssData Utils::getMockMeasurement() {
+ aidl::android::hardware::gnss::GnssSignalType signalType = {
+ .constellation = aidl::android::hardware::gnss::GnssConstellationType::GLONASS,
+ .carrierFrequencyHz = 1.59975e+09,
+ .codeType = aidl::android::hardware::gnss::GnssSignalType::CODE_TYPE_C,
+ };
+ aidl::android::hardware::gnss::GnssMeasurement measurement = {
+ .flags = GnssMeasurement::HAS_CARRIER_FREQUENCY,
+ .svid = 6,
+ .signalType = signalType,
+ .timeOffsetNs = 0.0,
+ .receivedSvTimeInNs = 8195997131077,
+ .receivedSvTimeUncertaintyInNs = 15,
+ .antennaCN0DbHz = 30.0,
+ .pseudorangeRateMps = -484.13739013671875,
+ .pseudorangeRateUncertaintyMps = 1.0379999876022339,
+ .accumulatedDeltaRangeState = GnssMeasurement::ADR_STATE_UNKNOWN,
+ .accumulatedDeltaRangeM = 0.0,
+ .accumulatedDeltaRangeUncertaintyM = 0.0,
+ .multipathIndicator = aidl::android::hardware::gnss::GnssMultipathIndicator::UNKNOWN,
+ .state = GnssMeasurement::STATE_CODE_LOCK | GnssMeasurement::STATE_BIT_SYNC |
+ GnssMeasurement::STATE_SUBFRAME_SYNC | GnssMeasurement::STATE_TOW_DECODED |
+ GnssMeasurement::STATE_GLO_STRING_SYNC |
+ GnssMeasurement::STATE_GLO_TOD_DECODED};
+
+ aidl::android::hardware::gnss::GnssClock clock = {.timeNs = 2713545000000,
+ .fullBiasNs = -1226701900521857520,
+ .biasNs = 0.59689998626708984,
+ .biasUncertaintyNs = 47514.989972114563,
+ .driftNsps = -51.757811607455452,
+ .driftUncertaintyNsps = 310.64968328491528,
+ .hwClockDiscontinuityCount = 1};
+
+ ElapsedRealtime timestamp = {
+ .flags = ElapsedRealtime::HAS_TIMESTAMP_NS | ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = ::android::elapsedRealtimeNano(),
+ // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+ // In an actual implementation provide an estimate of the synchronization uncertainty
+ // or don't set the field.
+ .timeUncertaintyNs = 1000000};
+
+ aidl::android::hardware::gnss::GnssData gnssData = {
+ .measurements = {measurement}, .clock = clock, .elapsedRealtime = timestamp};
+ return gnssData;
+}
+
V2_0::GnssLocation Utils::getMockLocationV2_0() {
const V2_0::ElapsedRealtime timestamp = {
.flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
@@ -145,8 +204,8 @@
.latitudeDegrees = gMockLatitudeDegrees,
.longitudeDegrees = gMockLongitudeDegrees,
.altitudeMeters = gMockAltitudeMeters,
- .speedMetersPerSec = kMockSpeedMetersPerSec,
- .bearingDegrees = kMockBearingDegrees,
+ .speedMetersPerSec = gMockSpeedMetersPerSec,
+ .bearingDegrees = gMockBearingDegrees,
.horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
.verticalAccuracyMeters = kMockVerticalAccuracyMeters,
.speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h
index ad4e0eb..a290ed2 100644
--- a/gnss/common/utils/default/include/Constants.h
+++ b/gnss/common/utils/default/include/Constants.h
@@ -24,8 +24,6 @@
namespace gnss {
namespace common {
-const float kMockSpeedMetersPerSec = 0;
-const float kMockBearingDegrees = 0;
const float kMockHorizontalAccuracyMeters = 5;
const float kMockVerticalAccuracyMeters = 5;
const float kMockSpeedAccuracyMetersPerSecond = 1;
diff --git a/gnss/common/utils/default/include/MockLocation.h b/gnss/common/utils/default/include/MockLocation.h
index cd8cb5d..0bfdd1a 100644
--- a/gnss/common/utils/default/include/MockLocation.h
+++ b/gnss/common/utils/default/include/MockLocation.h
@@ -27,6 +27,8 @@
extern float gMockLatitudeDegrees;
extern float gMockLongitudeDegrees;
extern float gMockAltitudeMeters;
+extern float gMockBearingDegrees;
+extern float gMockSpeedMetersPerSec;
} // namespace common
} // namespace gnss
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
index fb2c1a4..06eae7e 100644
--- a/gnss/common/utils/default/include/NmeaFixInfo.h
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -26,11 +26,6 @@
namespace hardware {
namespace gnss {
namespace common {
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
constexpr char GPGA_RECORD_TAG[] = "$GPGGA";
constexpr char GPRMC_RECORD_TAG[] = "$GPRMC";
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index d9ad5a5..0ca1b00 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -17,6 +17,7 @@
#ifndef android_hardware_gnss_common_default_Utils_H_
#define android_hardware_gnss_common_default_Utils_H_
+#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
#include <android/hardware/gnss/1.0/IGnss.h>
#include <android/hardware/gnss/2.0/IGnss.h>
#include <android/hardware/gnss/2.1/IGnss.h>
@@ -28,28 +29,22 @@
namespace gnss {
namespace common {
-using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
-using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
-using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo;
-using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo;
-using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
-using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo;
-using Row = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Row;
-using Coord = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Coord;
-
struct Utils {
- static GnssDataV2_0 getMockMeasurementV2_0();
- static GnssDataV2_1 getMockMeasurementV2_1();
+ static aidl::android::hardware::gnss::GnssData getMockMeasurement();
+ static V2_0::IGnssMeasurementCallback::GnssData getMockMeasurementV2_0();
+ static V2_1::IGnssMeasurementCallback::GnssData getMockMeasurementV2_1();
static V2_0::GnssLocation getMockLocationV2_0();
static V1_0::GnssLocation getMockLocationV1_0();
- static hidl_vec<GnssSvInfoV2_1> getMockSvInfoListV2_1();
- static GnssSvInfoV2_1 getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz);
- static GnssSvInfoV2_0 getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
- V2_0::GnssConstellationType type);
- static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
- float cN0DbHz, float elevationDegrees,
- float azimuthDegrees);
- static hidl_vec<GnssAntennaInfo> getMockAntennaInfos();
+ static hidl_vec<V2_1::IGnssCallback::GnssSvInfo> getMockSvInfoListV2_1();
+ static V2_1::IGnssCallback::GnssSvInfo getMockSvInfoV2_1(
+ V2_0::IGnssCallback::GnssSvInfo gnssSvInfoV2_0, float basebandCN0DbHz);
+ static V2_0::IGnssCallback::GnssSvInfo getMockSvInfoV2_0(
+ V1_0::IGnssCallback::GnssSvInfo gnssSvInfoV1_0, V2_0::GnssConstellationType type);
+ static V1_0::IGnssCallback::GnssSvInfo getMockSvInfoV1_0(int16_t svid,
+ V1_0::GnssConstellationType type,
+ float cN0DbHz, float elevationDegrees,
+ float azimuthDegrees);
+ static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
};
} // namespace common
diff --git a/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
index e74ff54..a232499 100644
--- a/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
+++ b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
@@ -23,29 +23,25 @@
namespace android::hardware::gnss::V2_1::implementation {
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using IGnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfo;
-using IGnssAntennaInfoCallback = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
-
-struct GnssAntennaInfo : public IGnssAntennaInfo {
+struct GnssAntennaInfo : public ::android::hardware::gnss::V2_1::IGnssAntennaInfo {
GnssAntennaInfo();
~GnssAntennaInfo();
// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
Return<GnssAntennaInfoStatus> setCallback(
- const sp<IGnssAntennaInfoCallback>& callback) override;
+ const sp<::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback>& callback) override;
Return<void> close() override;
private:
void start();
void stop();
void reportAntennaInfo(
- const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+ const hidl_vec<
+ ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo>&
+ antennaInfo) const;
// Guarded by mMutex
- static sp<IGnssAntennaInfoCallback> sCallback;
+ static sp<::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback> sCallback;
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
diff --git a/gnss/common/utils/default/include/v2_1/GnssConfiguration.h b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
index 8463a5c..2cfb38f 100644
--- a/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
+++ b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
@@ -25,35 +25,27 @@
namespace android::hardware::gnss::V2_1::implementation {
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-using BlacklistedSourceV2_1 =
- ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource;
-using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
-using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
-
struct BlacklistedSourceHashV2_1 {
- inline int operator()(const BlacklistedSourceV2_1& source) const {
+ inline int operator()(
+ const ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource& source)
+ const {
return int(source.constellation) * 1000 + int(source.svid);
}
};
struct BlacklistedSourceEqualV2_1 {
- inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const {
+ inline bool operator()(
+ const ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource& s1,
+ const ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource& s2)
+ const {
return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
}
};
using BlacklistedSourceSetV2_1 =
- std::unordered_set<BlacklistedSourceV2_1, BlacklistedSourceHashV2_1,
- BlacklistedSourceEqualV2_1>;
-using BlacklistedConstellationSetV2_1 = std::unordered_set<GnssConstellationTypeV2_0>;
+ std::unordered_set<::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource,
+ BlacklistedSourceHashV2_1, BlacklistedSourceEqualV2_1>;
+using BlacklistedConstellationSetV2_1 = std::unordered_set<V2_0::GnssConstellationType>;
struct GnssConfiguration : public IGnssConfiguration {
// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
@@ -78,7 +70,7 @@
Return<bool> setBlacklist_2_1(
const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
- Return<bool> isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+ Return<bool> isBlacklistedV2_1(const V2_1::IGnssCallback::GnssSvInfo& gnssSvInfo) const;
private:
mutable std::recursive_mutex mMutex;
diff --git a/gnss/common/utils/default/include/v2_1/GnssDebug.h b/gnss/common/utils/default/include/v2_1/GnssDebug.h
index 8580989..481de59 100644
--- a/gnss/common/utils/default/include/v2_1/GnssDebug.h
+++ b/gnss/common/utils/default/include/v2_1/GnssDebug.h
@@ -21,15 +21,8 @@
namespace android::hardware::gnss::V1_1::implementation {
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using V1_0::IGnssDebug;
-
/* Interface for GNSS Debug support. */
-struct GnssDebug : public IGnssDebug {
+struct GnssDebug : public V1_0::IGnssDebug {
/*
* Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
* These declarations were generated from IGnssDebug.hal.
diff --git a/gnss/common/utils/default/include/v2_1/GnssMeasurement.h b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
index 1d1fc9d..db8407b 100644
--- a/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
@@ -25,17 +25,6 @@
namespace android::hardware::gnss::V2_1::implementation {
-using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
-using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
-
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
struct GnssMeasurement : public IGnssMeasurement {
GnssMeasurement();
~GnssMeasurement();
@@ -59,8 +48,8 @@
private:
void start();
void stop();
- void reportMeasurement(const GnssDataV2_0&);
- void reportMeasurement(const GnssDataV2_1&);
+ void reportMeasurement(const V2_0::IGnssMeasurementCallback::GnssData&);
+ void reportMeasurement(const V2_1::IGnssMeasurementCallback::GnssData&);
// Guarded by mMutex
static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
diff --git a/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
index eaa7659..54045ad 100644
--- a/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
@@ -22,9 +22,6 @@
namespace android::hardware::gnss::measurement_corrections::V1_1::implementation {
-using ::android::sp;
-using ::android::hardware::Return;
-
struct GnssMeasurementCorrections : public IMeasurementCorrections {
GnssMeasurementCorrections();
~GnssMeasurementCorrections();
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index cbf3933..4d4ec93 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -39,16 +39,6 @@
namespace android::hardware::gnss::common::implementation {
-using GnssSvInfo = V2_1::IGnssCallback::GnssSvInfo;
-
-using common::NmeaFixInfo;
-using common::Utils;
-using measurement_corrections::V1_1::implementation::GnssMeasurementCorrections;
-
-using V2_1::implementation::GnssAntennaInfo;
-using V2_1::implementation::GnssConfiguration;
-using V2_1::implementation::GnssMeasurement;
-
constexpr int INPUT_BUFFER_SIZE = 128;
constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION";
constexpr char GNSS_PATH[] = "/dev/gnss0";
@@ -120,7 +110,7 @@
std::unique_ptr<V2_0::GnssLocation> getLocationFromHW();
void reportLocation(const V2_0::GnssLocation&) const;
void reportLocation(const V1_0::GnssLocation&) const;
- void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
+ void reportSvStatus(const hidl_vec<V2_1::IGnssCallback::GnssSvInfo>&) const;
Return<void> help(const hidl_handle& fd);
Return<void> setLocation(const hidl_handle& fd, const hidl_vec<hidl_string>& options);
@@ -131,15 +121,15 @@
static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
std::atomic<long> mMinIntervalMs;
- sp<GnssConfiguration> mGnssConfiguration;
+ sp<V2_1::implementation::GnssConfiguration> mGnssConfiguration;
std::atomic<bool> mIsActive;
std::atomic<bool> mHardwareModeChecked;
std::atomic<int> mGnssFd;
std::thread mThread;
mutable std::mutex mMutex;
- virtual hidl_vec<GnssSvInfo> filterBlocklistedSatellitesV2_1(
- hidl_vec<GnssSvInfo> gnssSvInfoList);
+ virtual hidl_vec<V2_1::IGnssCallback::GnssSvInfo> filterBlocklistedSatellitesV2_1(
+ hidl_vec<V2_1::IGnssCallback::GnssSvInfo> gnssSvInfoList);
};
template <class T_IGnss>
@@ -154,7 +144,7 @@
template <class T_IGnss>
GnssTemplate<T_IGnss>::GnssTemplate()
: mMinIntervalMs(1000),
- mGnssConfiguration{new GnssConfiguration()},
+ mGnssConfiguration{new V2_1::implementation::GnssConfiguration()},
mHardwareModeChecked(false),
mGnssFd(-1) {}
@@ -237,8 +227,8 @@
}
template <class T_IGnss>
-hidl_vec<GnssSvInfo> GnssTemplate<T_IGnss>::filterBlocklistedSatellitesV2_1(
- hidl_vec<GnssSvInfo> gnssSvInfoList) {
+hidl_vec<V2_1::IGnssCallback::GnssSvInfo> GnssTemplate<T_IGnss>::filterBlocklistedSatellitesV2_1(
+ hidl_vec<V2_1::IGnssCallback::GnssSvInfo> gnssSvInfoList) {
ALOGD("filterBlocklistedSatellitesV2_1");
for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
@@ -348,7 +338,7 @@
template <class T_IGnss>
Return<sp<V1_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement() {
ALOGD("Gnss::getExtensionGnssMeasurement");
- return new GnssMeasurement();
+ return new V2_1::implementation::GnssMeasurement();
}
template <class T_IGnss>
@@ -501,14 +491,14 @@
template <class T_IGnss>
Return<sp<V2_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_0() {
ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
- return new GnssMeasurement();
+ return new V2_1::implementation::GnssMeasurement();
}
template <class T_IGnss>
Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections() {
ALOGD("Gnss::getExtensionMeasurementCorrections()");
- return new GnssMeasurementCorrections();
+ return new measurement_corrections::V1_1::implementation::GnssMeasurementCorrections();
}
template <class T_IGnss>
@@ -569,7 +559,7 @@
template <class T_IGnss>
Return<sp<V2_1::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_1() {
ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
- return new GnssMeasurement();
+ return new V2_1::implementation::GnssMeasurement();
}
template <class T_IGnss>
@@ -582,17 +572,18 @@
Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections_1_1() {
ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
- return new GnssMeasurementCorrections();
+ return new measurement_corrections::V1_1::implementation::GnssMeasurementCorrections();
}
template <class T_IGnss>
Return<sp<V2_1::IGnssAntennaInfo>> GnssTemplate<T_IGnss>::getExtensionGnssAntennaInfo() {
ALOGD("Gnss::getExtensionGnssAntennaInfo");
- return new GnssAntennaInfo();
+ return new V2_1::implementation::GnssAntennaInfo();
}
template <class T_IGnss>
-void GnssTemplate<T_IGnss>::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
+void GnssTemplate<T_IGnss>::reportSvStatus(
+ const hidl_vec<V2_1::IGnssCallback::GnssSvInfo>& svInfoList) const {
std::unique_lock<std::mutex> lock(mMutex);
// TODO(skz): update this to call 2_0 callback if non-null
if (sGnssCallback_2_1 == nullptr) {
@@ -651,6 +642,8 @@
auto lat = gMockLatitudeDegrees;
auto lon = gMockLongitudeDegrees;
auto ele = gMockAltitudeMeters;
+ auto bea = gMockBearingDegrees;
+ auto spd = gMockSpeedMetersPerSec;
for (size_t i = 1; i < options.size(); ++i) {
std::string option = options[i];
@@ -663,6 +656,12 @@
} else if (option.rfind("ele=", 0) == 0) {
option = option.substr(4);
ele = stof(option);
+ } else if (option.rfind("bea=", 0) == 0) {
+ option = option.substr(4);
+ bea = stof(option);
+ } else if (option.rfind("spd=", 0) == 0) {
+ option = option.substr(4);
+ spd = stof(option);
} else {
dprintf(fd->data[0], "unsupported location argument: %s\n", option.c_str());
}
@@ -671,9 +670,12 @@
gMockLatitudeDegrees = lat;
gMockLongitudeDegrees = lon;
gMockAltitudeMeters = ele;
+ gMockBearingDegrees = bea;
+ gMockSpeedMetersPerSec = spd;
- dprintf(fd->data[0], "mock location updated to lat=%f lon=%f ele=%f\n", gMockLatitudeDegrees,
- gMockLongitudeDegrees, gMockAltitudeMeters);
+ dprintf(fd->data[0], "mock location updated to lat=%f lon=%f ele=%f bea=%f spd=%f\n",
+ gMockLatitudeDegrees, gMockLongitudeDegrees, gMockAltitudeMeters, gMockBearingDegrees,
+ gMockSpeedMetersPerSec);
return Void();
}
@@ -682,7 +684,7 @@
Return<void> GnssTemplate<T_IGnss>::help(const hidl_handle& fd) {
dprintf(fd->data[0],
"invalid option for Gnss HAL; valid options are:\n"
- "location lat=.. lon=.. ele=..\n");
+ "location [lat=..] [lon=..] [ele=..] [bea=..] [spd=..]\n");
return Void();
}
diff --git a/gnss/common/utils/default/v2_1/GnssConfiguration.cpp b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
index 8b30701..be974bc 100644
--- a/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
+++ b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
@@ -21,6 +21,9 @@
namespace android::hardware::gnss::V2_1::implementation {
+using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+using BlacklistedSourceV2_1 = V2_1::IGnssConfiguration::BlacklistedSource;
+
// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setSuplEs(bool enable) {
ALOGD("setSuplEs enable: %d", enable);
@@ -69,7 +72,7 @@
// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setBlacklist_2_1(
- const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& sourceList) {
+ const hidl_vec<BlacklistedSourceV2_1>& sourceList) {
std::unique_lock<std::recursive_mutex> lock(mMutex);
mBlacklistedConstellationSet.clear();
mBlacklistedSourceSet.clear();
diff --git a/gnss/common/utils/default/v2_1/GnssDebug.cpp b/gnss/common/utils/default/v2_1/GnssDebug.cpp
index d78b0b6..537a90c 100644
--- a/gnss/common/utils/default/v2_1/GnssDebug.cpp
+++ b/gnss/common/utils/default/v2_1/GnssDebug.cpp
@@ -33,8 +33,8 @@
.latitudeDegrees = gMockLatitudeDegrees,
.longitudeDegrees = gMockLongitudeDegrees,
.altitudeMeters = gMockAltitudeMeters,
- .speedMetersPerSec = kMockSpeedMetersPerSec,
- .bearingDegrees = kMockBearingDegrees,
+ .speedMetersPerSec = gMockSpeedMetersPerSec,
+ .bearingDegrees = gMockBearingDegrees,
.horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
.verticalAccuracyMeters = kMockVerticalAccuracyMeters,
.speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
diff --git a/gnss/common/utils/default/v2_1/GnssMeasurement.cpp b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
index 7d3a002..887cb5a 100644
--- a/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
+++ b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
@@ -114,7 +114,7 @@
}
}
-void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) {
+void GnssMeasurement::reportMeasurement(const V2_0::IGnssMeasurementCallback::GnssData& data) {
ALOGD("reportMeasurement()");
std::unique_lock<std::mutex> lock(mMutex);
if (sCallback_2_0 == nullptr) {
@@ -127,7 +127,7 @@
}
}
-void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) {
+void GnssMeasurement::reportMeasurement(const V2_1::IGnssMeasurementCallback::GnssData& data) {
ALOGD("reportMeasurement()");
std::unique_lock<std::mutex> lock(mMutex);
if (sCallback_2_1 == nullptr) {
diff --git a/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
index 1439158..fec3503 100644
--- a/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
+++ b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
@@ -23,36 +23,10 @@
#include <gtest/gtest.h>
#include <chrono>
-using ::android::hardware::gnss::common::Utils;
-
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-
-using android::hardware::gnss::common::GnssCallback;
-using android::hardware::gnss::common::GnssCallbackEventQueue;
-using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
-using android::hardware::gnss::V1_0::GnssLocationFlags;
-using android::hardware::gnss::V2_0::GnssConstellationType;
-using android::hardware::gnss::V2_1::IGnssAntennaInfo;
-using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
-
-using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
-using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
-
-using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
-using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
-using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
-
-using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
-
-using android::sp;
-
#define TIMEOUT_SEC 2 // for basic commands/responses
+namespace android::hardware::gnss::common {
+
// The main test class for GNSS HAL.
template <class T_IGnss>
class GnssHalTestTemplate : public testing::TestWithParam<std::string> {
@@ -62,34 +36,37 @@
virtual void TearDown() override;
/* Callback class for GnssMeasurement. */
- class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
+ class GnssMeasurementCallback : public V2_1::IGnssMeasurementCallback {
public:
- GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::GnssData> measurement_cbq_;
+ GnssCallbackEventQueue<V2_1::IGnssMeasurementCallback::GnssData> measurement_cbq_;
GnssMeasurementCallback() : measurement_cbq_("measurement"){};
virtual ~GnssMeasurementCallback() = default;
// Methods from V1_0::IGnssMeasurementCallback follow.
- Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
+ Return<void> GnssMeasurementCb(const V1_0::IGnssMeasurementCallback::GnssData&) override {
return Void();
}
// Methods from V1_1::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+ Return<void> gnssMeasurementCb(const V1_1::IGnssMeasurementCallback::GnssData&) override {
return Void();
}
// Methods from V2_0::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
+ Return<void> gnssMeasurementCb_2_0(
+ const V2_0::IGnssMeasurementCallback::GnssData&) override {
return Void();
}
// Methods from V2_1::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
+ Return<void> gnssMeasurementCb_2_1(
+ const V2_1::IGnssMeasurementCallback::GnssData&) override;
};
/* Callback class for GnssMeasurementCorrections. */
- class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ class GnssMeasurementCorrectionsCallback
+ : public measurement_corrections::V1_0::IMeasurementCorrectionsCallback {
public:
uint32_t last_capabilities_;
GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
@@ -102,9 +79,9 @@
};
/* Callback class for GnssAntennaInfo. */
- class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
+ class GnssAntennaInfoCallback : public V2_1::IGnssAntennaInfoCallback {
public:
- GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+ GnssCallbackEventQueue<hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo>>
antenna_info_cbq_;
GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
@@ -112,7 +89,7 @@
// Methods from V2_1::GnssAntennaInfoCallback follow.
Return<void> gnssAntennaInfoCb(
- const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
+ const hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
};
/*
@@ -138,7 +115,7 @@
*
* check_speed: true if speed related fields are also verified.
*/
- void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
+ void CheckLocation(const V2_0::GnssLocation& location, const bool check_speed);
/*
* StartAndCheckLocations:
@@ -170,7 +147,7 @@
* Note that location is not stopped in this method. The client should call
* StopAndClearLocations() after the call.
*/
- GnssConstellationType startLocationAndGetNonGpsConstellation(
+ V2_0::GnssConstellationType startLocationAndGetNonGpsConstellation(
const int locations_to_await, const int gnss_sv_info_list_timeout);
sp<T_IGnss> gnss_hal_; // GNSS HAL to call into
@@ -283,7 +260,7 @@
}
template <class T_IGnss>
-void GnssHalTestTemplate<T_IGnss>::CheckLocation(const GnssLocation_2_0& location,
+void GnssHalTestTemplate<T_IGnss>::CheckLocation(const V2_0::GnssLocation& location,
bool check_speed) {
const bool check_more_accuracies =
(gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
@@ -315,7 +292,7 @@
}
template <class T_IGnss>
-GnssConstellationType GnssHalTestTemplate<T_IGnss>::startLocationAndGetNonGpsConstellation(
+V2_0::GnssConstellationType GnssHalTestTemplate<T_IGnss>::startLocationAndGetNonGpsConstellation(
const int locations_to_await, const int gnss_sv_info_list_timeout) {
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(locations_to_await);
@@ -328,29 +305,29 @@
sv_info_list_cbq_size, locations_to_await, location_called_count);
// Find first non-GPS constellation to blacklist
- GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+ V2_0::GnssConstellationType constellation_to_blacklist = V2_0::GnssConstellationType::UNKNOWN;
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
- hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ hidl_vec<V2_1::IGnssCallback::GnssSvInfo> sv_info_vec;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
- if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
- (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
- (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+ if ((gnss_sv.v2_0.v1_0.svFlag & V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+ (gnss_sv.v2_0.constellation != V2_0::GnssConstellationType::UNKNOWN) &&
+ (gnss_sv.v2_0.constellation != V2_0::GnssConstellationType::GPS)) {
// found a non-GPS constellation
constellation_to_blacklist = gnss_sv.v2_0.constellation;
break;
}
}
- if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+ if (constellation_to_blacklist != V2_0::GnssConstellationType::UNKNOWN) {
break;
}
}
- if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+ if (constellation_to_blacklist == V2_0::GnssConstellationType::UNKNOWN) {
ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
// Proceed functionally to blacklist something.
- constellation_to_blacklist = GnssConstellationType::GLONASS;
+ constellation_to_blacklist = V2_0::GnssConstellationType::GLONASS;
}
return constellation_to_blacklist;
@@ -358,7 +335,7 @@
template <class T_IGnss>
Return<void> GnssHalTestTemplate<T_IGnss>::GnssMeasurementCallback::gnssMeasurementCb_2_1(
- const IGnssMeasurementCallback_2_1::GnssData& data) {
+ const V2_1::IGnssMeasurementCallback::GnssData& data) {
ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
measurement_cbq_.store(data);
return Void();
@@ -374,8 +351,10 @@
template <class T_IGnss>
Return<void> GnssHalTestTemplate<T_IGnss>::GnssAntennaInfoCallback::gnssAntennaInfoCb(
- const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+ const hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
antenna_info_cbq_.store(gnssAntennaInfos);
return Void();
}
+
+} // namespace android::hardware::gnss::common
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
index dc20eae..d77bff0 100644
--- a/graphics/composer/2.1/utils/resources/Android.bp
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -15,6 +15,7 @@
cc_library {
name: "android.hardware.graphics.composer@2.1-resources",
+ system_ext_specific: true,
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index e137afb..9e703d8 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -21,6 +21,7 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
+ "libbase",
"libfmq",
"libsync",
"android.hardware.graphics.mapper@2.0",
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 4fee560..f0250c0 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <composer-vts/2.1/ComposerVts.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
@@ -1102,3 +1103,15 @@
} // namespace graphics
} // namespace hardware
} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ using namespace std::chrono_literals;
+ if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) {
+ ALOGE("Failed to stop init.svc.surfaceflinger");
+ return -1;
+ }
+
+ return RUN_ALL_TESTS();
+}
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 16e9138..6aa836c 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -31,6 +31,7 @@
"libEGL",
"libGLESv1_CM",
"libGLESv2",
+ "libbase",
"libfmq",
"libgui",
"libhidlbase",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 4d7df1c..31ec885 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
@@ -700,3 +701,15 @@
} // namespace graphics
} // namespace hardware
} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ using namespace std::chrono_literals;
+ if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) {
+ ALOGE("Failed to stop init.svc.surfaceflinger");
+ return -1;
+ }
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 1ab6b3b..1cbb60e 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -21,6 +21,7 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
+ "libbase",
"libfmq",
"libhidlbase",
"libsync",
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index a4c1b63..8b42654 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -19,6 +19,7 @@
#include <algorithm>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
@@ -630,3 +631,15 @@
} // namespace graphics
} // namespace hardware
} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ using namespace std::chrono_literals;
+ if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) {
+ ALOGE("Failed to stop init.svc.surfaceflinger");
+ return -1;
+ }
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 9e3cf0e..1a59bbd 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -34,7 +34,9 @@
/**
* The configuration group ID (as int32_t) this config is associated to.
* Switching between configurations within the same group may be done seamlessly
- * in some conditions via setActiveConfigWithConstraints.
+ * in some conditions via setActiveConfigWithConstraints. Configurations which
+ * share the same config group are similar in all attributes except for the
+ * vsync period.
*/
CONFIG_GROUP = 7,
};
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index d0209b7..cab549c 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -21,6 +21,7 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
+ "libbase",
"libfmq",
"libsync",
"android.hardware.graphics.mapper@2.0",
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index e6ecf93..d8312a2 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -21,6 +21,7 @@
#include <thread>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
#include <composer-vts/2.4/ComposerVts.h>
@@ -57,6 +58,25 @@
using ContentType = IComposerClient::ContentType;
using DisplayCapability = IComposerClient::DisplayCapability;
+class VtsDisplay {
+ public:
+ VtsDisplay(Display display, int32_t displayWidth, int32_t displayHeight)
+ : mDisplay(display), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight) {}
+
+ Display get() const { return mDisplay; }
+
+ IComposerClient::FRect getCrop() const {
+ return {0, 0, static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)};
+ }
+
+ IComposerClient::Rect getFrameRect() const { return {0, 0, mDisplayWidth, mDisplayHeight}; }
+
+ private:
+ const Display mDisplay;
+ const int32_t mDisplayWidth;
+ const int32_t mDisplayHeight;
+};
+
class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
protected:
void SetUp() override {
@@ -67,15 +87,19 @@
mComposerCallback = new GraphicsComposerCallback;
mComposerClient->registerCallback_2_4(mComposerCallback);
- // assume the first display is primary and is never removed
- mPrimaryDisplay = waitForFirstDisplay();
+ // assume the first displays are built-in and are never removed
+ mDisplays = waitForDisplays();
mInvalidDisplayId = GetInvalidDisplayId();
// explicitly disable vsync
- mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ for (const auto& display : mDisplays) {
+ mComposerClient->setVsyncEnabled(display.get(), false);
+ }
mComposerCallback->setVsyncAllowed(false);
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
mWriter = std::make_unique<CommandWriterBase>(1024);
mReader = std::make_unique<TestCommandReader>();
}
@@ -83,6 +107,7 @@
void TearDown() override {
ASSERT_EQ(0, mReader->mErrors.size());
ASSERT_EQ(0, mReader->mCompositionChanges.size());
+
if (mComposerCallback != nullptr) {
EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
@@ -97,10 +122,10 @@
// display. Currently assuming that a device will never have close to
// std::numeric_limit<uint64_t>::max() displays registered while running tests
Display GetInvalidDisplayId() {
- std::vector<Display> validDisplays = mComposerCallback->getDisplays();
uint64_t id = std::numeric_limits<uint64_t>::max();
while (id > 0) {
- if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+ if (std::none_of(mDisplays.begin(), mDisplays.end(),
+ [&](const VtsDisplay& display) { return id == display.get(); })) {
return id;
}
id--;
@@ -127,6 +152,30 @@
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+ const native_handle_t* allocate() {
+ return mGralloc->allocate(
+ /*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
+ static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
+ }
+
+ struct TestParameters {
+ nsecs_t delayForChange;
+ bool refreshMiss;
+ };
+
+ void Test_setActiveConfigWithConstraints(const TestParameters& params);
+
+ void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline*);
+
+ void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline,
+ int64_t desiredTimeNanos, int64_t oldPeriodNanos,
+ int64_t newPeriodNanos);
+
+ std::unique_ptr<ComposerClient> mComposerClient;
+ std::vector<VtsDisplay> mDisplays;
+ Display mInvalidDisplayId;
+
void forEachTwoConfigs(Display display, std::function<void(Config, Config)> func) {
const auto displayConfigs = mComposerClient->getDisplayConfigs(display);
for (const Config config1 : displayConfigs) {
@@ -138,88 +187,44 @@
}
}
- // use the slot count usually set by SF
- static constexpr uint32_t kBufferSlotCount = 64;
-
void Test_setContentType(const ContentType& contentType, const char* contentTypeStr);
void Test_setContentTypeForDisplay(const Display& display,
const std::vector<ContentType>& capabilities,
const ContentType& contentType, const char* contentTypeStr);
- std::unique_ptr<Composer> mComposer;
- std::unique_ptr<ComposerClient> mComposerClient;
- sp<GraphicsComposerCallback> mComposerCallback;
- // the first display and is assumed never to be removed
- Display mPrimaryDisplay;
- Display mInvalidDisplayId;
- std::unique_ptr<CommandWriterBase> mWriter;
- std::unique_ptr<TestCommandReader> mReader;
-
private:
- Display waitForFirstDisplay() {
+ // use the slot count usually set by SF
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ std::vector<VtsDisplay> waitForDisplays() {
while (true) {
+ // Sleep for a small period of time to allow all built-in displays
+ // to post hotplug events
+ std::this_thread::sleep_for(5ms);
std::vector<Display> displays = mComposerCallback->getDisplays();
if (displays.empty()) {
- usleep(5 * 1000);
continue;
}
- return displays[0];
+ std::vector<VtsDisplay> vtsDisplays;
+ vtsDisplays.reserve(displays.size());
+ for (Display display : displays) {
+ const Config activeConfig = mComposerClient->getActiveConfig(display);
+ const int32_t displayWidth = mComposerClient->getDisplayAttribute_2_4(
+ display, activeConfig, IComposerClient::Attribute::WIDTH);
+ const int32_t displayHeight = mComposerClient->getDisplayAttribute_2_4(
+ display, activeConfig, IComposerClient::Attribute::HEIGHT);
+ vtsDisplays.emplace_back(VtsDisplay{display, displayWidth, displayHeight});
+ }
+
+ return vtsDisplays;
}
}
-};
-// Tests for IComposerClient::Command.
-class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
- protected:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
-
- ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
-
- const Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
- mDisplayWidth = mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, activeConfig,
- IComposerClient::Attribute::WIDTH);
- mDisplayHeight = mComposerClient->getDisplayAttribute_2_4(
- mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT);
-
- mWriter = std::make_unique<CommandWriterBase>(1024);
- mReader = std::make_unique<TestCommandReader>();
- }
-
- void TearDown() override {
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
- }
-
- const native_handle_t* allocate() {
- return mGralloc->allocate(
- /*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
- static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
- }
-
- void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
-
- struct TestParameters {
- nsecs_t delayForChange;
- bool refreshMiss;
- };
-
- void Test_setActiveConfigWithConstraints(const TestParameters& params);
-
- void sendRefreshFrame(const VsyncPeriodChangeTimeline*);
-
- void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline,
- int64_t desiredTimeNanos, int64_t oldPeriodNanos,
- int64_t newPeriodNanos);
-
+ std::unique_ptr<Composer> mComposer;
std::unique_ptr<CommandWriterBase> mWriter;
std::unique_ptr<TestCommandReader> mReader;
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
-
- private:
+ sp<GraphicsComposerCallback> mComposerCallback;
std::unique_ptr<Gralloc> mGralloc;
};
@@ -230,9 +235,10 @@
}
TEST_P(GraphicsComposerHidlTest, getDisplayCapabilities) {
- for (Display display : mComposerCallback->getDisplays()) {
+ for (const auto& display : mDisplays) {
std::vector<IComposerClient::DisplayCapability> capabilities;
- EXPECT_EQ(Error::NONE, mComposerClient->getDisplayCapabilities(display, &capabilities));
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayCapabilities(display.get(), &capabilities));
}
}
@@ -241,38 +247,40 @@
EXPECT_EQ(Error::BAD_DISPLAY,
mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type));
- for (Display display : mComposerCallback->getDisplays()) {
- EXPECT_EQ(Error::NONE, mComposerClient->getDisplayConnectionType(display, &type));
+ for (const auto& display : mDisplays) {
+ EXPECT_EQ(Error::NONE, mComposerClient->getDisplayConnectionType(display.get(), &type));
}
}
TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) {
- std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
- for (auto config : configs) {
- const std::array<IComposerClient::Attribute, 4> requiredAttributes = {{
- IComposerClient::Attribute::WIDTH,
- IComposerClient::Attribute::HEIGHT,
- IComposerClient::Attribute::VSYNC_PERIOD,
- IComposerClient::Attribute::CONFIG_GROUP,
- }};
- for (auto attribute : requiredAttributes) {
- mComposerClient->getRaw()->getDisplayAttribute_2_4(
- mPrimaryDisplay, config, attribute,
- [&](const auto& tmpError, const auto& value) {
- EXPECT_EQ(Error::NONE, tmpError);
- EXPECT_NE(-1, value);
- });
- }
+ for (const auto& display : mDisplays) {
+ std::vector<Config> configs = mComposerClient->getDisplayConfigs(display.get());
+ for (auto config : configs) {
+ const std::array<IComposerClient::Attribute, 4> requiredAttributes = {{
+ IComposerClient::Attribute::WIDTH,
+ IComposerClient::Attribute::HEIGHT,
+ IComposerClient::Attribute::VSYNC_PERIOD,
+ IComposerClient::Attribute::CONFIG_GROUP,
+ }};
+ for (auto attribute : requiredAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute_2_4(
+ display.get(), config, attribute,
+ [&](const auto& tmpError, const auto& value) {
+ EXPECT_EQ(Error::NONE, tmpError);
+ EXPECT_NE(-1, value);
+ });
+ }
- const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
- IComposerClient::Attribute::DPI_X,
- IComposerClient::Attribute::DPI_Y,
- }};
- for (auto attribute : optionalAttributes) {
- mComposerClient->getRaw()->getDisplayAttribute_2_4(
- mPrimaryDisplay, config, attribute, [&](const auto& tmpError, const auto&) {
- EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED);
- });
+ const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
+ IComposerClient::Attribute::DPI_X,
+ IComposerClient::Attribute::DPI_Y,
+ }};
+ for (auto attribute : optionalAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute_2_4(
+ display.get(), config, attribute, [&](const auto& tmpError, const auto&) {
+ EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED);
+ });
+ }
}
}
}
@@ -283,11 +291,12 @@
mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos));
}
-TEST_P(GraphicsComposerHidlCommandTest, getDisplayVsyncPeriod) {
- for (Display display : mComposerCallback->getDisplays()) {
- for (Config config : mComposerClient->getDisplayConfigs(display)) {
+TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) {
+ for (const auto& display : mDisplays) {
+ for (Config config : mComposerClient->getDisplayConfigs(display.get())) {
VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4(
- display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+ display.get(), config,
+ IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
VsyncPeriodChangeTimeline timeline;
IComposerClient::VsyncPeriodChangeConstraints constraints;
@@ -295,12 +304,12 @@
constraints.desiredTimeNanos = systemTime();
constraints.seamlessRequired = false;
EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
- display, config, constraints, &timeline));
+ display.get(), config, constraints, &timeline));
if (timeline.refreshRequired) {
- sendRefreshFrame(&timeline);
+ sendRefreshFrame(display, &timeline);
}
- waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, 0,
+ waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos, 0,
expectedVsyncPeriodNanos);
VsyncPeriodNanos vsyncPeriodNanos;
@@ -309,7 +318,7 @@
std::this_thread::sleep_for(10ms);
vsyncPeriodNanos = 0;
EXPECT_EQ(Error::NONE,
- mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos));
--retryCount;
} while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0);
@@ -322,7 +331,7 @@
timeout *= 2;
vsyncPeriodNanos = 0;
EXPECT_EQ(Error::NONE,
- mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos));
EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
}
}
@@ -347,31 +356,34 @@
constraints.seamlessRequired = false;
constraints.desiredTimeNanos = systemTime();
- for (Display display : mComposerCallback->getDisplays()) {
- Config invalidConfigId = GetInvalidConfigId(display);
- EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigWithConstraints(
- display, invalidConfigId, constraints, &timeline));
+ for (const auto& display : mDisplays) {
+ Config invalidConfigId = GetInvalidConfigId(display.get());
+ EXPECT_EQ(Error::BAD_CONFIG,
+ mComposerClient->setActiveConfigWithConstraints(display.get(), invalidConfigId,
+ constraints, &timeline));
}
}
-TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
VsyncPeriodChangeTimeline timeline;
IComposerClient::VsyncPeriodChangeConstraints constraints;
constraints.seamlessRequired = true;
constraints.desiredTimeNanos = systemTime();
- for (Display display : mComposerCallback->getDisplays()) {
- forEachTwoConfigs(display, [&](Config config1, Config config2) {
+ for (const auto& display : mDisplays) {
+ forEachTwoConfigs(display.get(), [&](Config config1, Config config2) {
const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4(
- display, config1, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+ display.get(), config1,
+ IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
const auto configGroup2 = mComposerClient->getDisplayAttribute_2_4(
- display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+ display.get(), config2,
+ IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
if (configGroup1 != configGroup2) {
- mComposerClient->setActiveConfig(display, config1);
- sendRefreshFrame(nullptr);
+ mComposerClient->setActiveConfig(display.get(), config1);
+ sendRefreshFrame(display, nullptr);
EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
- mComposerClient->setActiveConfigWithConstraints(display, config2,
+ mComposerClient->setActiveConfigWithConstraints(display.get(), config2,
constraints, &timeline));
}
});
@@ -382,7 +394,8 @@
return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
}
-void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline* timeline) {
+void GraphicsComposerHidlTest::sendRefreshFrame(const VtsDisplay& display,
+ const VsyncPeriodChangeTimeline* timeline) {
if (timeline != nullptr) {
// Refresh time should be before newVsyncAppliedTimeNanos
EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos);
@@ -390,29 +403,25 @@
std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos));
}
- mWriter->selectDisplay(mPrimaryDisplay);
- mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON);
- mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE,
- RenderIntent::COLORIMETRIC);
+ mWriter->selectDisplay(display.get());
+ mComposerClient->setPowerMode(display.get(), V2_1::IComposerClient::PowerMode::ON);
+ mComposerClient->setColorMode_2_3(display.get(), ColorMode::NATIVE, RenderIntent::COLORIMETRIC);
auto handle = allocate();
ASSERT_NE(nullptr, handle);
- IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
-
Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(display.get(), kBufferSlotCount));
mWriter->selectLayer(layer);
mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
- mWriter->setLayerDisplayFrame(displayFrame);
+ mWriter->setLayerDisplayFrame(display.getFrameRect());
mWriter->setLayerPlaneAlpha(1);
- mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+ mWriter->setLayerSourceCrop(display.getCrop());
mWriter->setLayerTransform(static_cast<Transform>(0));
- mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, display.getFrameRect()));
mWriter->setLayerZOrder(10);
mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
- mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, display.getFrameRect()));
mWriter->setLayerBuffer(0, handle, -1);
mWriter->setLayerDataspace(Dataspace::UNKNOWN);
@@ -440,9 +449,11 @@
execute();
}
-void GraphicsComposerHidlCommandTest::waitForVsyncPeriodChange(
- Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos,
- int64_t oldPeriodNanos, int64_t newPeriodNanos) {
+void GraphicsComposerHidlTest::waitForVsyncPeriodChange(Display display,
+ const VsyncPeriodChangeTimeline& timeline,
+ int64_t desiredTimeNanos,
+ int64_t oldPeriodNanos,
+ int64_t newPeriodNanos) {
const auto CHANGE_DEADLINE = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms;
while (std::chrono::steady_clock::now() <= CHANGE_DEADLINE) {
VsyncPeriodNanos vsyncPeriodNanos;
@@ -456,17 +467,18 @@
}
}
-void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
- const TestParameters& params) {
- for (Display display : mComposerCallback->getDisplays()) {
- forEachTwoConfigs(display, [&](Config config1, Config config2) {
- mComposerClient->setActiveConfig(display, config1);
- sendRefreshFrame(nullptr);
+void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints(const TestParameters& params) {
+ for (const auto& display : mDisplays) {
+ forEachTwoConfigs(display.get(), [&](Config config1, Config config2) {
+ mComposerClient->setActiveConfig(display.get(), config1);
+ sendRefreshFrame(display, nullptr);
int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4(
- display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+ display.get(), config1,
+ IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
int32_t vsyncPeriod2 = mComposerClient->getDisplayAttribute_2_4(
- display, config2, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+ display.get(), config2,
+ IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
if (vsyncPeriod1 == vsyncPeriod2) {
return; // continue
@@ -477,7 +489,7 @@
.desiredTimeNanos = systemTime() + params.delayForChange,
.seamlessRequired = false};
EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
- display, config2, constraints, &timeline));
+ display.get(), config2, constraints, &timeline));
EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
// Refresh rate should change within a reasonable time
@@ -491,10 +503,10 @@
// callback
std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms);
}
- sendRefreshFrame(&timeline);
+ sendRefreshFrame(display, &timeline);
}
- waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1,
- vsyncPeriod2);
+ waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos,
+ vsyncPeriod1, vsyncPeriod2);
// At this point the refresh rate should have changed already, however in rare
// cases the implementation might have missed the deadline. In this case a new
@@ -506,30 +518,30 @@
if (newTimeline.has_value()) {
if (newTimeline->refreshRequired) {
- sendRefreshFrame(&newTimeline.value());
+ sendRefreshFrame(display, &newTimeline.value());
}
- waitForVsyncPeriodChange(display, newTimeline.value(), constraints.desiredTimeNanos,
- vsyncPeriod1, vsyncPeriod2);
+ waitForVsyncPeriodChange(display.get(), newTimeline.value(),
+ constraints.desiredTimeNanos, vsyncPeriod1, vsyncPeriod2);
}
VsyncPeriodNanos vsyncPeriodNanos;
EXPECT_EQ(Error::NONE,
- mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos));
EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
});
}
}
-TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) {
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints) {
Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
}
-TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) {
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_Delayed) {
Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000, // 300ms
.refreshMiss = false});
}
-TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_MissRefresh) {
Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true});
}
@@ -539,9 +551,9 @@
}
TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) {
- for (Display display : mComposerCallback->getDisplays()) {
+ for (const auto& display : mDisplays) {
std::vector<DisplayCapability> capabilities;
- const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+ const auto error = mComposerClient->getDisplayCapabilities(display.get(), &capabilities);
EXPECT_EQ(Error::NONE, error);
const bool allmSupport =
@@ -550,16 +562,16 @@
if (!allmSupport) {
EXPECT_EQ(Error::UNSUPPORTED,
- mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+ mComposerClient->setAutoLowLatencyMode(display.get(), true));
EXPECT_EQ(Error::UNSUPPORTED,
- mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ mComposerClient->setAutoLowLatencyMode(display.get(), false));
GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
- << std::to_string(display) << ", skipping test";
+ << std::to_string(display.get()) << ", skipping test";
return;
}
- EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
- EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(display.get(), true));
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(display.get(), false));
}
}
@@ -572,10 +584,10 @@
TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) {
std::vector<ContentType> supportedContentTypes;
- for (Display display : mComposerCallback->getDisplays()) {
+ for (const auto& display : mDisplays) {
supportedContentTypes.clear();
const auto error =
- mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ mComposerClient->getSupportedContentTypes(display.get(), &supportedContentTypes);
const bool noneSupported =
std::find(supportedContentTypes.begin(), supportedContentTypes.end(),
ContentType::NONE) != supportedContentTypes.end();
@@ -585,8 +597,8 @@
}
TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) {
- for (Display display : mComposerCallback->getDisplays()) {
- const auto error = mComposerClient->setContentType(display, ContentType::NONE);
+ for (const auto& display : mDisplays) {
+ const auto error = mComposerClient->setContentType(display.get(), ContentType::NONE);
EXPECT_NE(Error::UNSUPPORTED, error);
}
}
@@ -618,13 +630,14 @@
void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType,
const char* contentTypeStr) {
- for (Display display : mComposerCallback->getDisplays()) {
+ for (const auto& display : mDisplays) {
std::vector<ContentType> supportedContentTypes;
const auto error =
- mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ mComposerClient->getSupportedContentTypes(display.get(), &supportedContentTypes);
EXPECT_EQ(Error::NONE, error);
- Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr);
+ Test_setContentTypeForDisplay(display.get(), supportedContentTypes, contentType,
+ contentTypeStr);
}
}
@@ -650,13 +663,7 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, GraphicsComposerHidlCommandTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
- android::hardware::PrintInstanceNameToString);
-
-TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+TEST_P(GraphicsComposerHidlTest, getLayerGenericMetadataKeys) {
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
mComposerClient->getLayerGenericMetadataKeys(&keys);
@@ -685,3 +692,15 @@
} // namespace graphics
} // namespace hardware
} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ using namespace std::chrono_literals;
+ if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) {
+ ALOGE("Failed to stop init.svc.surfaceflinger");
+ return -1;
+ }
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 730b601..702334d 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -55,7 +55,7 @@
* This method may only be called once per instance. If called more than once, STATUS_FAILED
* will be returned.
*
- * @return the unencrypted key-pair in PKCS#8 format.
+ * @return the private key, in DER format as specified in RFC 5915.
*/
byte[] createEphemeralKeyPair();
@@ -88,10 +88,10 @@
* The setRequestedNamespaces() and setVerificationToken() methods will be called before
* this method is called.
*
- * This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
- * createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
- * multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally
- * finishRetrieval().
+ * This method is called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
+ * createAuthChallenge() (note that those calls are optional) and before startRetrieveEntry().
+ * This method call is followed by multiple calls of startRetrieveEntryValue(),
+ * retrieveEntryValue(), and finally finishRetrieval().
*
* It is permissible to perform data retrievals multiple times using the same instance (e.g.
* startRetrieval(), then multiple calls of startRetrieveEntryValue(), retrieveEntryValue(),
@@ -343,12 +343,13 @@
*
* - signature: must be set to ECDSA.
*
- * - subject: CN shall be set to "Android Identity Credential Authentication Key".
+ * - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+ * value: same on all certs)
*
- * - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
- * values returned in HardwareInformation.
+ * - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+ * same on all certs)
*
- * - validity: should be from current time and one year in the future.
+ * - validity: should be from current time and one year in the future (365 days).
*
* - subjectPublicKeyInfo: must contain attested public key.
*
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 297fd1d..c48cb66 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -37,12 +37,12 @@
*
* - signature: must be set to ECDSA.
*
- * - subject: CN shall be set to "Android Identity Credential Key".
+ * - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+ * same on all certs)
*
- * - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
- * values returned in HardwareInformation.
+ * - issuer: Same as the subject field of the batch attestation key.
*
- * - validity: should be from current time and expire at the same time as the
+ * - validity: Should be set to current time and expire at the same time as the
* attestation batch certificate used.
*
* - subjectPublicKeyInfo: must contain attested public key.
@@ -55,19 +55,14 @@
*
* - The attestationSecurityLevel field must be set to either Software (0),
* TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
- * implemented. Only the default AOSP implementation of this HAL may use
- * value 0 (additionally, this implementation must not be used on production
- * devices).
+ * implemented.
*
- * - The keymasterVersion field in the attestation extension must be set to (10*major + minor)
- * where major and minor are the Identity Credential interface major and minor versions.
- * Specifically for this version of the interface (1.0) this value is 10.
+ * - The keymasterVersion field in the attestation extension must be set to the.
+ * same value as used for Android Keystore keys.
*
* - The keymasterSecurityLevel field in the attestation extension must be set to
* either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
- * the Trusted Application backing the HAL implementation is implemented. Only
- * the default AOSP implementation of this HAL may use value 0 (additionally, this
- * implementation must not be used on production devices)
+ * the Trusted Application backing the HAL implementation is implemented.
*
* - The attestationChallenge field must be set to the passed-in challenge.
*
@@ -81,7 +76,8 @@
*
* - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
* Credential key (which can only sign/MAC very specific messages) and not an Android
- * Keystore key (which can be used to sign/MAC anything).
+ * Keystore key (which can be used to sign/MAC anything). This must not be set
+ * for test credentials.
*
* - Tag::PURPOSE must be set to SIGN
*
@@ -95,10 +91,13 @@
*
* - Tag::EC_CURVE must be set to P_256
*
- * Additional authorizations may be needed in the softwareEnforced and teeEnforced
- * fields - the above is not an exhaustive list. Specifically, authorizations containing
- * information about the root of trust, OS version, verified boot state, and so on should
- * be included.
+ * - Tag::ROOT_OF_TRUST must be set
+ *
+ * - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+ *
+ * Additional authorizations may be appear in the softwareEnforced and teeEnforced
+ * fields. For example if the device has a boot or vendor partitions, then BOOT_PATCHLEVEL
+ * and VENDOR_PATCHLEVEL should be set.
*
* Since the chain is required to be generated using Keymaster Attestation, the returned
* certificate chain has the following properties:
@@ -112,8 +111,8 @@
* As with any user of attestation, the Issuing Authority (as a relying party) wishing
* to issue a credential to a device using these APIs, must carefully examine the
* returned certificate chain for all of the above (and more). In particular, the Issuing
- * Authority should check the root of trust, verified boot state, patch level,
- * application id, etc.
+ * Authority should check the root of trust (which include verified boot state), patch level,
+ * attestation application id, etc.
*
* This all depends on the needs of the Issuing Authority and the kind of credential but
* in general an Issuing Authority should never issue a credential to a device without
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index 87d9a93..dfcd4f5 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -272,6 +272,7 @@
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
const vector<uint8_t>& signingKeyBlob, const vector<uint8_t>& sessionTranscript,
const vector<uint8_t>& readerSignature, const vector<int32_t>& requestCounts) {
+ std::unique_ptr<cppbor::Item> sessionTranscriptItem;
if (sessionTranscript.size() > 0) {
auto [item, _, message] = cppbor::parse(sessionTranscript);
if (item == nullptr) {
@@ -279,7 +280,7 @@
IIdentityCredentialStore::STATUS_INVALID_DATA,
"SessionTranscript contains invalid CBOR"));
}
- sessionTranscriptItem_ = std::move(item);
+ sessionTranscriptItem = std::move(item);
}
if (numStartRetrievalCalls_ > 0) {
if (sessionTranscript_ != sessionTranscript) {
@@ -319,7 +320,7 @@
vector<uint8_t> encodedReaderAuthentication =
cppbor::Array()
.add("ReaderAuthentication")
- .add(sessionTranscriptItem_->clone())
+ .add(std::move(sessionTranscriptItem))
.add(cppbor::Semantic(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
@@ -776,13 +777,6 @@
optional<vector<uint8_t>> mac;
if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
readerPublicKey_.size() > 0) {
- cppbor::Array array;
- array.add("DeviceAuthentication");
- array.add(sessionTranscriptItem_->clone());
- array.add(docType_);
- array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
- vector<uint8_t> deviceAuthenticationBytes = cppbor::Semantic(24, array.encode()).encode();
-
vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
optional<vector<uint8_t>> signingKey =
support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
@@ -792,31 +786,15 @@
"Error decrypting signingKeyBlob"));
}
- optional<vector<uint8_t>> sharedSecret =
- support::ecdh(readerPublicKey_, signingKey.value());
- if (!sharedSecret) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
- }
-
- // Mix-in SessionTranscriptBytes
vector<uint8_t> sessionTranscriptBytes = cppbor::Semantic(24, sessionTranscript_).encode();
- vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
- std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
- std::back_inserter(sharedSecretWithSessionTranscriptBytes));
-
- vector<uint8_t> salt = {0x00};
- vector<uint8_t> info = {};
- optional<vector<uint8_t>> derivedKey =
- support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
- if (!derivedKey) {
+ optional<vector<uint8_t>> eMacKey =
+ support::calcEMacKey(signingKey.value(), readerPublicKey_, sessionTranscriptBytes);
+ if (!eMacKey) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED,
- "Error deriving key from shared secret"));
+ IIdentityCredentialStore::STATUS_FAILED, "Error calculating EMacKey"));
}
-
- mac = support::coseMac0(derivedKey.value(), {}, // payload
- deviceAuthenticationBytes); // detached content
+ mac = support::calcMac(sessionTranscript_, docType_, encodedDeviceNameSpaces,
+ eMacKey.value());
if (!mac) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
@@ -830,9 +808,9 @@
ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
- string serialDecimal = "0"; // TODO: set serial to something unique
- string issuer = "Android Open Source Project";
- string subject = "Android IdentityCredential Reference Implementation";
+ string serialDecimal = "1";
+ string issuer = "Android Identity Credential Key";
+ string subject = "Android Identity Credential Authentication Key";
time_t validityNotBefore = time(nullptr);
time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index a82531d..a8a6409 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -103,7 +103,6 @@
map<int32_t, int> profileIdToAccessCheckResult_;
vector<uint8_t> signingKeyBlob_;
vector<uint8_t> sessionTranscript_;
- std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
vector<uint8_t> itemsRequest_;
vector<int32_t> requestCountsRemaining_;
map<string, set<string>> requestedNameSpacesAndNames_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index fea289b..141b4de 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -74,7 +74,7 @@
vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
- support::createEcKeyPairAndAttestation(challenge, appId);
+ support::createEcKeyPairAndAttestation(challenge, appId, testCredential_);
if (!keyAttestationPair) {
LOG(ERROR) << "Error creating credentialKey and attestation";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index c1f44e7..03966de 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -9,7 +9,6 @@
"VtsIWritableIdentityCredentialTests.cpp",
"VtsIdentityTestUtils.cpp",
"VtsAttestationTests.cpp",
- "VtsAttestationParserSupport.cpp",
"UserAuthTests.cpp",
"ReaderAuthTests.cpp",
],
@@ -20,13 +19,14 @@
static_libs: [
"libcppbor",
"libkeymaster_portable",
- "libsoft_attestation_cert",
"libpuresoftkeymasterdevice",
"android.hardware.keymaster@4.0",
"android.hardware.identity-support-lib",
"android.hardware.identity-cpp",
"android.hardware.keymaster-cpp",
"android.hardware.keymaster-ndk_platform",
+ "libkeymaster4support",
+ "libkeymaster4_1support",
],
test_suites: [
"general-tests",
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp
deleted file mode 100644
index 71fe733..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "VtsAttestationParserSupport.h"
-
-#include <aidl/Gtest.h>
-#include <map>
-
-namespace android::hardware::identity::test_utils {
-
-using std::endl;
-using std::map;
-using std::optional;
-using std::string;
-using std::vector;
-
-using ::android::sp;
-using ::android::String16;
-using ::android::binder::Status;
-
-using ::keymaster::ASN1_OBJECT_Ptr;
-using ::keymaster::AuthorizationSet;
-using ::keymaster::EVP_PKEY_Ptr;
-using ::keymaster::kAttestionRecordOid;
-using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
-using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
-using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
-using ::keymaster::TypedTag;
-using ::keymaster::X509_Ptr;
-
-using support::certificateChainSplit;
-
-optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
- const vector<Certificate>& certificates) {
- if (certificates.size() <= 0) {
- return {};
- }
-
- keymaster_cert_chain_t kCert;
- kCert.entry_count = certificates.size();
- kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);
-
- int index = 0;
- for (const auto& c : certificates) {
- kCert.entries[index].data_length = c.encodedCertificate.size();
- uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());
-
- memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
- kCert.entries[index].data = (const uint8_t*)data;
- index++;
- }
-
- return kCert;
-}
-
-bool AttestationCertificateParser::parse() {
- optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
- if (!cert_chain) {
- return false;
- }
-
- if (cert_chain.value().entry_count < 3) {
- return false;
- }
-
- if (!verifyChain(cert_chain.value())) {
- return false;
- }
-
- if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
- return false;
- }
-
- keymaster_free_cert_chain(&cert_chain.value());
- return true;
-}
-
-ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
- ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
- if (!oid.get()) return nullptr;
-
- int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
- if (location == -1) return nullptr;
-
- X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
- if (!attest_rec_ext) return nullptr;
-
- ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
- return attest_rec;
-}
-
-X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
- const uint8_t* p = blob.data;
- return d2i_X509(nullptr, &p, blob.data_length);
-}
-
-bool AttestationCertificateParser::verifyAttestationRecord(
- const keymaster_blob_t& attestation_cert) {
- X509_Ptr cert(parseCertBlob(attestation_cert));
- if (!cert.get()) {
- return false;
- }
-
- ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
- if (!attest_rec) {
- return false;
- }
-
- keymaster_blob_t att_unique_id = {};
- keymaster_blob_t att_challenge;
- keymaster_error_t ret = parse_attestation_record(
- attest_rec->data, attest_rec->length, &att_attestation_version_,
- &att_attestation_security_level_, &att_keymaster_version_,
- &att_keymaster_security_level_, &att_challenge, &att_sw_enforced_, &att_hw_enforced_,
- &att_unique_id);
- if (ret) {
- return false;
- }
-
- att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
- return true;
-}
-
-uint32_t AttestationCertificateParser::getKeymasterVersion() {
- return att_keymaster_version_;
-}
-
-uint32_t AttestationCertificateParser::getAttestationVersion() {
- return att_attestation_version_;
-}
-
-vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
- return att_challenge_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
- return att_keymaster_security_level_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
- return att_attestation_security_level_;
-}
-
-// Verify the Attestation certificates are correctly chained.
-bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
- for (size_t i = 0; i < chain.entry_count - 1; ++i) {
- keymaster_blob_t& key_cert_blob = chain.entries[i];
- keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
-
- X509_Ptr key_cert(parseCertBlob(key_cert_blob));
- X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
- if (!key_cert.get() || !signing_cert.get()) {
- return false;
- }
-
- EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
- if (!signing_pubkey.get()) return false;
-
- if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
- return false;
- }
-
- if (i + 1 == chain.entry_count - 1) {
- // Last entry is self-signed.
- if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-} // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h
deleted file mode 100644
index 7c7e1b6..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.h
+++ /dev/null
@@ -1,122 +0,0 @@
-
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H
-#define VTS_ATTESTATION_PARSER_SUPPORT_H
-
-//#include <aidl/Gtest.h>
-#include <android/hardware/identity/IIdentityCredentialStore.h>
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-#include <android/hardware/keymaster/4.0/types.h>
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/contexts/pure_soft_keymaster_context.h>
-#include <keymaster/contexts/soft_attestation_cert.h>
-#include <keymaster/keymaster_tags.h>
-#include <keymaster/km_openssl/attestation_utils.h>
-#include <vector>
-
-namespace android::hardware::identity::test_utils {
-
-using ::std::optional;
-using ::std::string;
-using ::std::vector;
-
-using ::keymaster::AuthorizationSet;
-using ::keymaster::TypedTag;
-
-class AttestationCertificateParser {
- public:
- AttestationCertificateParser(const vector<Certificate>& certChain)
- : origCertChain_(certChain) {}
-
- bool parse();
-
- uint32_t getKeymasterVersion();
- uint32_t getAttestationVersion();
- vector<uint8_t> getAttestationChallenge();
- keymaster_security_level_t getKeymasterSecurityLevel();
- keymaster_security_level_t getAttestationSecurityLevel();
-
- template <keymaster_tag_t Tag>
- bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
- if (att_sw_enforced_.GetTagValue(tag)) {
- return true;
- }
-
- return false;
- }
-
- template <keymaster_tag_t Tag>
- bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
- if (att_hw_enforced_.GetTagValue(tag)) {
- return true;
- }
-
- return false;
- }
-
- template <keymaster_tag_t Tag>
- optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
- keymaster_blob_t blob;
- if (att_hw_enforced_.GetTagValue(tag, &blob)) {
- return {};
- }
-
- vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
- return ret;
- }
-
- template <keymaster_tag_t Tag>
- optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
- keymaster_blob_t blob;
- if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
- return {};
- }
-
- vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
- return ret;
- }
-
- private:
- // Helper functions.
- bool verifyChain(const keymaster_cert_chain_t& chain);
-
- ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);
-
- X509* parseCertBlob(const keymaster_blob_t& blob);
-
- bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);
-
- optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
- const vector<Certificate>& certificates);
-
- // Private variables.
- vector<Certificate> origCertChain_;
- AuthorizationSet att_sw_enforced_;
- AuthorizationSet att_hw_enforced_;
- uint32_t att_attestation_version_;
- uint32_t att_keymaster_version_;
- keymaster_security_level_t att_attestation_security_level_;
- keymaster_security_level_t att_keymaster_security_level_;
- vector<uint8_t> att_challenge_;
-};
-
-} // namespace android::hardware::identity::test_utils
-
-#endif // VTS_ATTESTATION_PARSER_SUPPORT_H
diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp
index 673d08b..5529853 100644
--- a/identity/aidl/vts/VtsAttestationTests.cpp
+++ b/identity/aidl/vts/VtsAttestationTests.cpp
@@ -29,7 +29,6 @@
#include <future>
#include <map>
-#include "VtsAttestationParserSupport.h"
#include "VtsIdentityTestUtils.h"
namespace android::hardware::identity {
@@ -44,7 +43,6 @@
using ::android::String16;
using ::android::binder::Status;
-using test_utils::AttestationCertificateParser;
using test_utils::setupWritableCredential;
using test_utils::validateAttestationCertificate;
@@ -61,38 +59,12 @@
sp<IIdentityCredentialStore> credentialStore_;
};
-TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
- Status result;
-
- HardwareInformation hwInfo;
- ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
- sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
-
- string challenge = "NotSoRandomChallenge";
- vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
- vector<Certificate> attestationCertificate;
- vector<uint8_t> attestationApplicationId = {};
-
- result = writableCredential->getAttestationCertificate(
- attestationApplicationId, attestationChallenge, &attestationCertificate);
-
- ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
- << endl;
-
- EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
- attestationApplicationId, hwInfo));
-}
-
TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
Status result;
- HardwareInformation hwInfo;
- ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -106,18 +78,16 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
- attestationApplicationId, hwInfo));
+ validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, false);
}
TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
Status result;
- HardwareInformation hwInfo;
- ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "c";
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -131,8 +101,8 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
- attestationApplicationId, hwInfo));
+ validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, false);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsAttestationTests);
diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
index 500b79f..cdecb97 100644
--- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
@@ -174,16 +174,17 @@
string cborPretty;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ true /* testCredential */));
string challenge = "attestationChallenge";
- test_utils::AttestationData attData(writableCredential, challenge, {});
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {1} /* atteestationApplicationId */);
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
- attData.attestationChallenge,
- attData.attestationApplicationId, hwInfo));
+ validateAttestationCertificate(attData.attestationCertificate, attData.attestationChallenge,
+ attData.attestationApplicationId, true);
// This is kinda of a hack but we need to give the size of
// ProofOfProvisioning that we'll expect to receive.
@@ -368,6 +369,7 @@
optional<vector<uint8_t>> signingPubKey =
support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
EXPECT_TRUE(signingPubKey);
+ test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
// Since we're using a test-credential we know storageKey meaning we can get the
// private key. Do this, derive the public key from it, and check this matches what
@@ -418,9 +420,9 @@
}
vector<uint8_t> mac;
- vector<uint8_t> deviceNameSpacesBytes;
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+ vector<uint8_t> deviceNameSpacesEncoded;
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ(
"{\n"
" 'PersonalData' : {\n"
@@ -435,37 +437,19 @@
" },\n"
"}",
cborPretty);
- // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
- // deviceNameSpacesBytes] so build up that structure
- cppbor::Array deviceAuthentication;
- deviceAuthentication.add("DeviceAuthentication");
- deviceAuthentication.add(sessionTranscript.clone());
string docType = "org.iso.18013-5.2019.mdl";
- deviceAuthentication.add(docType);
- deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
- vector<uint8_t> deviceAuthenticationBytes =
- cppbor::Semantic(24, deviceAuthentication.encode()).encode();
- // Derive the key used for MACing.
optional<vector<uint8_t>> readerEphemeralPrivateKey =
support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
- optional<vector<uint8_t>> sharedSecret =
- support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
- ASSERT_TRUE(sharedSecret);
- // Mix-in SessionTranscriptBytes
- vector<uint8_t> sessionTranscriptBytes =
- cppbor::Semantic(24, sessionTranscript.encode()).encode();
- vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
- std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
- std::back_inserter(sharedSecretWithSessionTranscriptBytes));
- vector<uint8_t> salt = {0x00};
- vector<uint8_t> info = {};
- optional<vector<uint8_t>> derivedKey =
- support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
- ASSERT_TRUE(derivedKey);
+ optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
+ readerEphemeralPrivateKey.value(), // Private Key
+ signingPubKey.value(), // Public Key
+ cppbor::Semantic(24, sessionTranscript.encode()).encode()); // SessionTranscriptBytes
optional<vector<uint8_t>> calculatedMac =
- support::coseMac0(derivedKey.value(), {}, // payload
- deviceAuthenticationBytes); // detached content
+ support::calcMac(sessionTranscript.encode(), // SessionTranscript
+ docType, // DocType
+ deviceNameSpacesEncoded, // DeviceNamespaces
+ eMacKey.value()); // EMacKey
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
@@ -480,18 +464,14 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
- deviceAuthentication = cppbor::Array();
- deviceAuthentication.add("DeviceAuthentication");
- deviceAuthentication.add(sessionTranscript.clone());
- deviceAuthentication.add(docType);
- deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
- deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
- calculatedMac = support::coseMac0(derivedKey.value(), {}, // payload
- deviceAuthenticationBytes); // detached content
+ calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
+ docType, // DocType
+ deviceNameSpacesEncoded, // DeviceNamespaces
+ eMacKey.value()); // EMacKey
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
@@ -506,18 +486,14 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
- deviceAuthentication = cppbor::Array();
- deviceAuthentication.add("DeviceAuthentication");
- deviceAuthentication.add(sessionTranscript.clone());
- deviceAuthentication.add(docType);
- deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
- deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
- calculatedMac = support::coseMac0(derivedKey.value(), {}, // payload
- deviceAuthenticationBytes); // detached content
+ calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
+ docType, // DocType
+ deviceNameSpacesEncoded, // DeviceNamespaces
+ eMacKey.value()); // EMacKey
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
}
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index 8c35952..56e17ba 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -61,7 +61,8 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
vector<uint8_t> attestationChallenge;
vector<Certificate> attestationCertificate;
@@ -82,12 +83,13 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
vector<Certificate> attestationCertificate;
- vector<uint8_t> attestationApplicationId = {};
+ vector<uint8_t> attestationApplicationId = {1};
result = writableCredential->getAttestationCertificate(
attestationApplicationId, attestationChallenge, &attestationCertificate);
@@ -95,27 +97,27 @@
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(test_utils::validateAttestationCertificate(
- attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
+ test_utils::validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, false);
}
TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
Status result;
- HardwareInformation hwInfo;
- ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge1";
- test_utils::AttestationData attData(writableCredential, challenge, {});
- ASSERT_TRUE(test_utils::validateAttestationCertificate(
- attData.attestationCertificate, attData.attestationChallenge,
- attData.attestationApplicationId, hwInfo));
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {1} /* atteestationApplicationId */);
+ test_utils::validateAttestationCertificate(attData.attestationCertificate,
+ attData.attestationChallenge,
+ attData.attestationApplicationId, false);
string challenge2 = "NotSoRandomChallenge2";
- test_utils::AttestationData attData2(writableCredential, challenge2, {});
+ test_utils::AttestationData attData2(writableCredential, challenge2,
+ {} /* atteestationApplicationId */);
EXPECT_FALSE(attData2.result.isOk()) << attData2.result.exceptionCode() << "; "
<< attData2.result.exceptionMessage() << endl;
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, attData2.result.exceptionCode());
@@ -125,7 +127,8 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
// First call should go through
const vector<int32_t> entryCounts = {2, 4};
@@ -147,7 +150,8 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1, 1};
@@ -160,7 +164,8 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1};
@@ -173,7 +178,8 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
// Verify set a large number of profile count and entry count is ok
const vector<int32_t> entryCounts = {3000};
@@ -186,7 +192,8 @@
TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
// Enter mismatched entry and profile numbers
const vector<int32_t> entryCounts = {5, 6};
@@ -224,7 +231,8 @@
TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
const vector<int32_t> entryCounts = {3, 6};
writableCredential->setExpectedProofOfProvisioningSize(123456);
@@ -283,10 +291,12 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge1";
- test_utils::AttestationData attData(writableCredential, challenge, {});
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {} /* atteestationApplicationId */);
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
@@ -294,7 +304,7 @@
ASSERT_TRUE(readerCertificate1);
const vector<int32_t> entryCounts = {1u};
- size_t expectedPoPSize = 186 + readerCertificate1.value().size();
+ size_t expectedPoPSize = 185 + readerCertificate1.value().size();
// OK to fail, not available in v1 HAL
writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
result = writableCredential->startPersonalization(1, entryCounts);
@@ -308,7 +318,7 @@
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
- {"Name Space", "Last name", string("Turing"), vector<int32_t>{0, 1}},
+ {"Name Space", "Last name", string("Turing"), vector<int32_t>{1}},
};
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
@@ -347,11 +357,11 @@
" {\n"
" 'name' : 'Last name',\n"
" 'value' : 'Turing',\n"
- " 'accessControlProfiles' : [0, 1, ],\n"
+ " 'accessControlProfiles' : [1, ],\n"
" },\n"
" ],\n"
" },\n"
- " true,\n"
+ " false,\n"
"]",
cborPretty);
@@ -370,10 +380,12 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge";
- test_utils::AttestationData attData(writableCredential, challenge, {});
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {} /* atteestationApplicationId */);
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
@@ -510,7 +522,7 @@
" },\n"
" ],\n"
" },\n"
- " true,\n"
+ " false,\n"
"]",
cborPretty);
@@ -529,10 +541,12 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge";
- test_utils::AttestationData attData(writableCredential, challenge, {});
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {} /* atteestationApplicationId */);
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
@@ -591,10 +605,12 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
string challenge = "NotSoRandomChallenge";
- test_utils::AttestationData attData(writableCredential, challenge, {});
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {} /* atteestationApplicationId */);
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
@@ -667,7 +683,8 @@
TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ false /* testCredential */));
const vector<int32_t> entryCounts = {1};
writableCredential->setExpectedProofOfProvisioningSize(123456);
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp
index b6ed80f..3b10651 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.cpp
+++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp
@@ -14,13 +14,17 @@
* limitations under the License.
*/
+#define LOG_TAG "VtsIdentityTestUtils"
+
#include "VtsIdentityTestUtils.h"
#include <aidl/Gtest.h>
+#include <android-base/logging.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymasterV4_1/attestation_record.h>
+#include <charconv>
#include <map>
-#include "VtsAttestationParserSupport.h"
-
namespace android::hardware::identity::test_utils {
using std::endl;
@@ -32,15 +36,15 @@
using ::android::sp;
using ::android::String16;
using ::android::binder::Status;
+using ::keymaster::X509_Ptr;
bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
- sp<IIdentityCredentialStore>& credentialStore) {
+ sp<IIdentityCredentialStore>& credentialStore, bool testCredential) {
if (credentialStore == nullptr) {
return false;
}
string docType = "org.iso.18013-5.2019.mdl";
- bool testCredential = true;
Status result = credentialStore->createCredential(docType, testCredential, &writableCredential);
if (result.isOk() && writableCredential != nullptr) {
@@ -178,63 +182,269 @@
}
}
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
- const vector<uint8_t>& expectedChallenge,
- const vector<uint8_t>& expectedAppId,
- const HardwareInformation& hwInfo) {
- AttestationCertificateParser certParser_(inputCertificates);
- bool ret = certParser_.parse();
- EXPECT_TRUE(ret);
- if (!ret) {
+string x509NameToRfc2253String(X509_NAME* name) {
+ char* buf;
+ size_t bufSize;
+ BIO* bio;
+
+ bio = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+ bufSize = BIO_get_mem_data(bio, &buf);
+ string ret = string(buf, bufSize);
+ BIO_free(bio);
+
+ return ret;
+}
+
+int parseDigits(const char** s, int numDigits) {
+ int result;
+ auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+ if (ec != std::errc()) {
+ LOG(ERROR) << "Error parsing " << numDigits << " digits "
+ << " from " << s;
+ return 0;
+ }
+ *s += numDigits;
+ return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+ struct tm tm;
+
+ memset(&tm, '\0', sizeof(tm));
+ const char* timeStr = (const char*)asn1Time->data;
+ const char* s = timeStr;
+ if (asn1Time->type == V_ASN1_UTCTIME) {
+ tm.tm_year = parseDigits(&s, 2);
+ if (tm.tm_year < 70) {
+ tm.tm_year += 100;
+ }
+ } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+ tm.tm_year = parseDigits(&s, 4) - 1900;
+ tm.tm_year -= 1900;
+ } else {
+ LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+ return false;
+ }
+ tm.tm_mon = parseDigits(&s, 2) - 1;
+ tm.tm_mday = parseDigits(&s, 2);
+ tm.tm_hour = parseDigits(&s, 2);
+ tm.tm_min = parseDigits(&s, 2);
+ tm.tm_sec = parseDigits(&s, 2);
+ // This may need to be updated if someone create certificates using +/- instead of Z.
+ //
+ if (*s != 'Z') {
+ LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
return false;
}
- // As per the IC HAL, the version of the Identity
- // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
- // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
- // and integers greater or equal than 41 (for KM starting with 4.1).
- //
- // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
- // version isn't errornously returned.
- EXPECT_LE(10, certParser_.getKeymasterVersion());
- EXPECT_GT(40, certParser_.getKeymasterVersion());
- EXPECT_LE(3, certParser_.getAttestationVersion());
-
- // Verify the app id matches to whatever we set it to be.
- optional<vector<uint8_t>> appId =
- certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
- if (appId) {
- EXPECT_EQ(expectedAppId.size(), appId.value().size());
- EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
- } else {
- // app id not found
- EXPECT_EQ(0, expectedAppId.size());
+ time_t t = timegm(&tm);
+ if (t == -1) {
+ LOG(ERROR) << "Error converting broken-down time to time_t";
+ return false;
}
-
- EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
- EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
-
- // Verify the challenge always matches in size and data of what is passed
- // in.
- vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
- EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
- EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
-
- // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
- // for the reference implementation which cannot be implemented in secure hardware).
- if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
- hwInfo.credentialStoreAuthorName == "Google") {
- EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
- EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
-
- } else {
- // Actual devices should use TrustedEnvironment or StrongBox.
- EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
- EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
- }
+ *outTime = t;
return true;
}
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
+ const vector<uint8_t>& expectedChallenge,
+ const vector<uint8_t>& expectedAppId, bool isTestCredential) {
+ ASSERT_GE(credentialKeyCertChain.size(), 2);
+
+ vector<uint8_t> certBytes = credentialKeyCertChain[0].encodedCertificate;
+ const uint8_t* certData = certBytes.data();
+ X509_Ptr cert = X509_Ptr(d2i_X509(nullptr, &certData, certBytes.size()));
+
+ vector<uint8_t> batchCertBytes = credentialKeyCertChain[1].encodedCertificate;
+ const uint8_t* batchCertData = batchCertBytes.data();
+ X509_Ptr batchCert = X509_Ptr(d2i_X509(nullptr, &batchCertData, batchCertBytes.size()));
+
+ // First get some values from the batch certificate which is checked
+ // against the top-level certificate (subject, notAfter)
+ //
+
+ X509_NAME* batchSubject = X509_get_subject_name(batchCert.get());
+ ASSERT_NE(nullptr, batchSubject);
+ time_t batchNotAfter;
+ ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(batchCert.get()), &batchNotAfter));
+
+ // Check all the requirements from IWritableIdentityCredential::getAttestationCertificate()...
+ //
+
+ // - version: INTEGER 2 (means v3 certificate).
+ EXPECT_EQ(2, X509_get_version(cert.get()));
+
+ // - serialNumber: INTEGER 1 (fixed value: same on all certs).
+ EXPECT_EQ(1, ASN1_INTEGER_get(X509_get_serialNumber(cert.get())));
+
+ // - signature: must be set to ECDSA.
+ EXPECT_EQ(NID_ecdsa_with_SHA256, X509_get_signature_nid(cert.get()));
+
+ // - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+ // same on all certs)
+ X509_NAME* subject = X509_get_subject_name(cert.get());
+ ASSERT_NE(nullptr, subject);
+ EXPECT_EQ("CN=Android Identity Credential Key", x509NameToRfc2253String(subject));
+
+ // - issuer: Same as the subject field of the batch attestation key.
+ X509_NAME* issuer = X509_get_issuer_name(cert.get());
+ ASSERT_NE(nullptr, issuer);
+ EXPECT_EQ(x509NameToRfc2253String(batchSubject), x509NameToRfc2253String(issuer));
+
+ // - validity: Should be from current time and expire at the same time as the
+ // attestation batch certificate used.
+ //
+ // Allow for 10 seconds drift to account for the time drift between Secure HW
+ // and this environment plus the difference between when the certificate was
+ // created and until now
+ //
+ time_t notBefore;
+ ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), ¬Before));
+ uint64_t now = time(nullptr);
+ int64_t diffSecs = now - notBefore;
+ int64_t allowDriftSecs = 10;
+ EXPECT_LE(-allowDriftSecs, diffSecs);
+ EXPECT_GE(allowDriftSecs, diffSecs);
+
+ time_t notAfter;
+ ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), ¬After));
+ EXPECT_EQ(notAfter, batchNotAfter);
+
+ auto [err, attRec] = keymaster::V4_1::parse_attestation_record(certBytes);
+ ASSERT_EQ(keymaster::V4_1::ErrorCode::OK, err);
+
+ // - subjectPublicKeyInfo: must contain attested public key.
+
+ // - The attestationVersion field in the attestation extension must be at least 3.
+ EXPECT_GE(attRec.attestation_version, 3);
+
+ // - The attestationSecurityLevel field must be set to either Software (0),
+ // TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
+ // implemented.
+ EXPECT_GE(attRec.attestation_security_level,
+ keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+ // - The keymasterVersion field in the attestation extension must be set to the.
+ // same value as used for Android Keystore keys.
+ //
+ // Nothing to check here...
+
+ // - The keymasterSecurityLevel field in the attestation extension must be set to
+ // either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
+ // the Trusted Application backing the HAL implementation is implemented.
+ EXPECT_GE(attRec.keymaster_security_level, keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+ // - The attestationChallenge field must be set to the passed-in challenge.
+ EXPECT_EQ(expectedChallenge.size(), attRec.attestation_challenge.size());
+ EXPECT_TRUE(memcmp(expectedChallenge.data(), attRec.attestation_challenge.data(),
+ attRec.attestation_challenge.size()) == 0);
+
+ // - The uniqueId field must be empty.
+ EXPECT_EQ(attRec.unique_id.size(), 0);
+
+ // - The softwareEnforced field in the attestation extension must include
+ // Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
+ // attestationApplicationId.
+ EXPECT_TRUE(attRec.software_enforced.Contains(keymaster::V4_0::TAG_ATTESTATION_APPLICATION_ID,
+ expectedAppId));
+
+ // - The teeEnforced field in the attestation extension must include
+ //
+ // - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
+ // Credential key (which can only sign/MAC very specific messages) and not an Android
+ // Keystore key (which can be used to sign/MAC anything). This must not be set
+ // for test credentials.
+ bool hasIcKeyTag =
+ attRec.hardware_enforced.Contains(static_cast<android::hardware::keymaster::V4_0::Tag>(
+ keymaster::V4_1::Tag::IDENTITY_CREDENTIAL_KEY));
+ if (isTestCredential) {
+ EXPECT_FALSE(hasIcKeyTag);
+ } else {
+ EXPECT_TRUE(hasIcKeyTag);
+ }
+
+ // - Tag::PURPOSE must be set to SIGN
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_PURPOSE,
+ keymaster::V4_0::KeyPurpose::SIGN));
+
+ // - Tag::KEY_SIZE must be set to the appropriate key size, in bits (e.g. 256)
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_KEY_SIZE, 256));
+
+ // - Tag::ALGORITHM must be set to EC
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_ALGORITHM,
+ keymaster::V4_0::Algorithm::EC));
+
+ // - Tag::NO_AUTH_REQUIRED must be set
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_NO_AUTH_REQUIRED));
+
+ // - Tag::DIGEST must be include SHA_2_256
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_DIGEST,
+ keymaster::V4_0::Digest::SHA_2_256));
+
+ // - Tag::EC_CURVE must be set to P_256
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_EC_CURVE,
+ keymaster::V4_0::EcCurve::P_256));
+
+ // - Tag::ROOT_OF_TRUST must be set
+ //
+ EXPECT_GE(attRec.root_of_trust.security_level,
+ keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+ // - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_VERSION));
+ EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_PATCHLEVEL));
+
+ // TODO: we could retrieve osVersion and osPatchLevel from Android itself and compare it
+ // with what was reported in the certificate.
+}
+
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain) {
+ const uint8_t* data = authKeyCertChain.data();
+ auto cert = X509_Ptr(d2i_X509(nullptr, &data, authKeyCertChain.size()));
+
+ // - version: INTEGER 2 (means v3 certificate).
+ EXPECT_EQ(X509_get_version(cert.get()), 2);
+
+ // - serialNumber: INTEGER 1 (fixed value: same on all certs).
+ EXPECT_EQ(ASN1_INTEGER_get(X509_get_serialNumber(cert.get())), 1);
+
+ // - signature: must be set to ECDSA.
+ EXPECT_EQ(X509_get_signature_nid(cert.get()), NID_ecdsa_with_SHA256);
+
+ // - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+ // value: same on all certs)
+ X509_NAME* subject = X509_get_subject_name(cert.get());
+ ASSERT_NE(subject, nullptr);
+ EXPECT_EQ(x509NameToRfc2253String(subject),
+ "CN=Android Identity Credential Authentication Key");
+
+ // - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+ // same on all certs)
+ X509_NAME* issuer = X509_get_issuer_name(cert.get());
+ ASSERT_NE(issuer, nullptr);
+ EXPECT_EQ(x509NameToRfc2253String(issuer), "CN=Android Identity Credential Key");
+
+ // - subjectPublicKeyInfo: must contain attested public key.
+
+ // - validity: should be from current time and one year in the future (365 days).
+ time_t notBefore, notAfter;
+ ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), ¬After));
+ ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), ¬Before));
+
+ // Allow for 10 seconds drift to account for the time drift between Secure HW
+ // and this environment plus the difference between when the certificate was
+ // created and until now
+ //
+ uint64_t now = time(nullptr);
+ int64_t diffSecs = now - notBefore;
+ int64_t allowDriftSecs = 10;
+ EXPECT_LE(-allowDriftSecs, diffSecs);
+ EXPECT_GE(allowDriftSecs, diffSecs);
+ constexpr uint64_t kSecsInOneYear = 365 * 24 * 60 * 60;
+ EXPECT_EQ(notBefore + kSecsInOneYear, notAfter);
+}
+
vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
vector<RequestNamespace> ret;
RequestNamespace curNs;
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h
index 673b736..85c24f8 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.h
+++ b/identity/aidl/vts/VtsIdentityTestUtils.h
@@ -34,8 +34,8 @@
struct AttestationData {
AttestationData(sp<IWritableIdentityCredential>& writableCredential, string challenge,
- vector<uint8_t> applicationId)
- : attestationApplicationId(applicationId) {
+ vector<uint8_t> attestationAppId)
+ : attestationApplicationId(attestationAppId) {
// ASSERT_NE(writableCredential, nullptr);
if (!challenge.empty()) {
@@ -94,7 +94,7 @@
};
bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
- sp<IIdentityCredentialStore>& credentialStore);
+ sp<IIdentityCredentialStore>& credentialStore, bool testCredential);
optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
@@ -111,13 +111,17 @@
void setImageData(vector<uint8_t>& image);
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
const vector<uint8_t>& expectedChallenge,
- const vector<uint8_t>& expectedAppId,
- const HardwareInformation& hwInfo);
+ const vector<uint8_t>& expectedAppId, bool isTestCredential);
vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries);
+// Verifies that the X.509 certificate for a just created authentication key
+// is valid.
+//
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain);
+
} // namespace android::hardware::identity::test_utils
#endif // VTS_IDENTITY_TEST_UTILS_H
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index f7ec7c5..3aa5bb6 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -35,6 +35,9 @@
using ::std::vector;
using ::std::pair;
+// The semantic tag for a bstr which includes Encoded CBOR (RFC 7049, section 2.4)
+const int kSemanticTagEncodedCbor = 24;
+
// ---------------------------------------------------------------------------
// Miscellaneous utilities.
// ---------------------------------------------------------------------------
@@ -108,45 +111,47 @@
// ---------------------------------------------------------------------------
// EC crypto functionality / abstraction (only supports P-256).
// ---------------------------------------------------------------------------
+
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair. Also generates an attestation
-// certificate using the |challenge| and |applicationId|, and returns the generated
-// certificate in X.509 certificate chain format.
+// DER encoded private key. Also generates an attestation using the |challenge|
+// and |applicationId|, and returns the generated certificate chain.
//
-// The attestation time fields used will be the current time, and expires in one year.
+// The notBeffore field will be the current time and the notAfter will be the same
+// same time as the batch certificate.
//
// The first parameter of the return value is the keyPair generated, second return in
// the pair is the attestation certificate generated.
-optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
- const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
-
-// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
//
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+ const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+ bool isTestCredential);
+
+// (TODO: remove when no longer used by 3rd party.)
optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
const vector<uint8_t>& applicationId);
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair.
+// private key in DER format (as specified in RFC 5915).
//
optional<vector<uint8_t>> createEcKeyPair();
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the public key in
+// For an EC key |keyPair| encoded in DER format, extracts the public key in
// uncompressed point form.
//
optional<vector<uint8_t>> ecKeyPairGetPublicKey(const vector<uint8_t>& keyPair);
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the private key as
+// For an EC key |keyPair| encoded in DER format, extracts the private key as
// an EC uncompressed key.
//
optional<vector<uint8_t>> ecKeyPairGetPrivateKey(const vector<uint8_t>& keyPair);
-// Creates a PKCS#8 encoded key-pair from a private key (which must be uncompressed,
-// e.g. 32 bytes). The public key is derived from the given private key..
+// Creates a DER encoded representation from a private key (which must be uncompressed,
+// e.g. 32 bytes).
//
optional<vector<uint8_t>> ecPrivateKeyToKeyPair(const vector<uint8_t>& privateKey);
-// For an EC key |keyPair| encoded in PKCS#8 format, creates a PKCS#12 structure
+// For an EC key |keyPair| encoded in DER format, creates a PKCS#12 structure
// with the key-pair (not using a password to encrypt the data). The public key
// in the created structure is included as a certificate, using the given fields
// |serialDecimal|, |issuer|, |subject|, |validityNotBefore|, and
@@ -209,6 +214,13 @@
//
optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
+// Extracts notBefore and notAfter from the top-most certificate in |certificateChain
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Returns notBefore and notAfter in that order.
+//
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate);
+
// Generates a X.509 certificate for |publicKey| (which must be in the format
// returned by ecKeyPairGetPublicKey()).
//
@@ -351,6 +363,15 @@
// Utility functions specific to IdentityCredential.
// ---------------------------------------------------------------------------
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+ const string& docType,
+ const vector<uint8_t>& deviceNameSpacesEncoded,
+ const vector<uint8_t>& eMacKey);
+
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+ const vector<uint8_t>& publicKey,
+ const vector<uint8_t>& sessionTranscriptBytes);
+
// Returns the testing AES-128 key where all bits are set to 0.
const vector<uint8_t>& getTestHardwareBoundKey();
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 747f182..77b795b 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -44,6 +44,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <charconv>
#include <cppbor.h>
#include <cppbor_parse.h>
@@ -54,6 +55,7 @@
#include <keymaster/contexts/soft_attestation_cert.h>
#include <keymaster/keymaster_tags.h>
#include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
namespace android {
namespace hardware {
@@ -870,16 +872,109 @@
return hmac;
}
+int parseDigits(const char** s, int numDigits) {
+ int result;
+ auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+ if (ec != std::errc()) {
+ LOG(ERROR) << "Error parsing " << numDigits << " digits "
+ << " from " << s;
+ return 0;
+ }
+ *s += numDigits;
+ return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+ struct tm tm;
+
+ memset(&tm, '\0', sizeof(tm));
+ const char* timeStr = (const char*)asn1Time->data;
+ const char* s = timeStr;
+ if (asn1Time->type == V_ASN1_UTCTIME) {
+ tm.tm_year = parseDigits(&s, 2);
+ if (tm.tm_year < 70) {
+ tm.tm_year += 100;
+ }
+ } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+ tm.tm_year = parseDigits(&s, 4) - 1900;
+ tm.tm_year -= 1900;
+ } else {
+ LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+ return false;
+ }
+ tm.tm_mon = parseDigits(&s, 2) - 1;
+ tm.tm_mday = parseDigits(&s, 2);
+ tm.tm_hour = parseDigits(&s, 2);
+ tm.tm_min = parseDigits(&s, 2);
+ tm.tm_sec = parseDigits(&s, 2);
+ // This may need to be updated if someone create certificates using +/- instead of Z.
+ //
+ if (*s != 'Z') {
+ LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
+ return false;
+ }
+
+ time_t t = timegm(&tm);
+ if (t == -1) {
+ LOG(ERROR) << "Error converting broken-down time to time_t";
+ return false;
+ }
+ *outTime = t;
+ return true;
+}
+
// Generates the attestation certificate with the parameters passed in. Note
// that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
// milli seconds since epoch. We are setting them to milliseconds due to
// requirement in AuthorizationSet KM_DATE fields. The certificate created is
// actually in seconds.
-optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
- const vector<uint8_t>& applicationId,
- const vector<uint8_t>& challenge,
- uint64_t activeTimeMilliSeconds,
- uint64_t expireTimeMilliSeconds) {
+//
+// If 0 is passed for expiration time, the expiration time from batch
+// certificate will be used.
+//
+optional<vector<vector<uint8_t>>> createAttestation(
+ const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
+ uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+ const keymaster_cert_chain_t* attestation_chain =
+ ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+ if (attestation_chain == nullptr) {
+ LOG(ERROR) << "Error getting attestation chain";
+ return {};
+ }
+ if (expireTimeMilliSeconds == 0) {
+ if (attestation_chain->entry_count < 1) {
+ LOG(ERROR) << "Expected at least one entry in attestation chain";
+ return {};
+ }
+ keymaster_blob_t* bcBlob = &(attestation_chain->entries[0]);
+ const uint8_t* bcData = bcBlob->data;
+ auto bc = X509_Ptr(d2i_X509(nullptr, &bcData, bcBlob->data_length));
+ time_t bcNotAfter;
+ if (!parseAsn1Time(X509_get0_notAfter(bc.get()), &bcNotAfter)) {
+ LOG(ERROR) << "Error getting notAfter from batch certificate";
+ return {};
+ }
+ expireTimeMilliSeconds = bcNotAfter * 1000;
+ }
+ const keymaster_key_blob_t* attestation_signing_key =
+ ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+ if (attestation_signing_key == nullptr) {
+ LOG(ERROR) << "Error getting attestation key";
+ return {};
+ }
+
+ ::keymaster::X509_NAME_Ptr subjectName;
+ if (KM_ERROR_OK !=
+ ::keymaster::make_name_from_str("Android Identity Credential Key", &subjectName)) {
+ LOG(ERROR) << "Cannot create attestation subject";
+ return {};
+ }
+
+ vector<uint8_t> subject(i2d_X509_NAME(subjectName.get(), NULL));
+ unsigned char* subjectPtr = subject.data();
+
+ i2d_X509_NAME(subjectName.get(), &subjectPtr);
+
::keymaster::AuthorizationSet auth_set(
::keymaster::AuthorizationSetBuilder()
.Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
@@ -894,6 +989,8 @@
// includes app id.
.Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID,
applicationId.data(), applicationId.size())
+ .Authorization(::keymaster::TAG_CERTIFICATE_SUBJECT, subject.data(),
+ subject.size())
.Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds));
// Unique id and device id is not applicable for identity credential attestation,
@@ -901,7 +998,7 @@
::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
- ::keymaster::AuthorizationSet hwEnforced(
+ ::keymaster::AuthorizationSetBuilder hwEnforcedBuilder =
::keymaster::AuthorizationSetBuilder()
.Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
.Authorization(::keymaster::TAG_KEY_SIZE, 256)
@@ -909,34 +1006,29 @@
.Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
.Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
.Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
- .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+ .Authorization(::keymaster::TAG_OS_VERSION, 42)
+ .Authorization(::keymaster::TAG_OS_PATCHLEVEL, 43);
- const keymaster_cert_chain_t* attestation_chain =
- ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
-
- if (attestation_chain == nullptr) {
- LOG(ERROR) << "Error getting attestation chain";
- return {};
+ // Only include TAG_IDENTITY_CREDENTIAL_KEY if it's not a test credential
+ if (!isTestCredential) {
+ hwEnforcedBuilder.Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY);
}
-
- const keymaster_key_blob_t* attestation_signing_key =
- ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
- if (attestation_signing_key == nullptr) {
- LOG(ERROR) << "Error getting attestation key";
- return {};
- }
+ ::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
keymaster_error_t error;
::keymaster::CertChainPtr cert_chain_out;
- ::keymaster::PureSoftKeymasterContext context;
- // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
- // For now, the identity version in the attestation is set in the keymaster
- // version field in the portable keymaster lib, which is a bit misleading.
- uint identity_version = 10;
+ // Pretend to be implemented in a trusted environment just so we can pass
+ // the VTS tests. Of course, this is a pretend-only game since hopefully no
+ // relying party is ever going to trust our batch key and those keys above
+ // it.
+ //
+ ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+ KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
- identity_version, *attestation_chain,
- *attestation_signing_key, &cert_chain_out);
+ *attestation_chain, *attestation_signing_key,
+ &cert_chain_out);
if (KM_ERROR_OK != error || !cert_chain_out) {
LOG(ERROR) << "Error generate attestation from EVP key" << error;
@@ -957,7 +1049,8 @@
}
optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
- const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+ const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+ bool isTestCredential) {
auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
@@ -978,12 +1071,11 @@
return {};
}
- uint64_t now = time(nullptr);
- uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
- uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+ uint64_t nowMs = time(nullptr) * 1000;
+ uint64_t expireTimeMs = 0; // Set to same as batch certificate
- optional<vector<vector<uint8_t>>> attestationCert =
- createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+ optional<vector<vector<uint8_t>>> attestationCert = createAttestation(
+ pkey.get(), applicationId, challenge, nowMs, expireTimeMs, isTestCredential);
if (!attestationCert) {
LOG(ERROR) << "Error create attestation from key and challenge";
return {};
@@ -1031,14 +1123,12 @@
return {};
}
- uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch()).
- count()/ 1000000000);
- uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
- uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+ uint64_t nowMs = time(nullptr) * 1000;
+ uint64_t expireTimeMs = 0; // Set to same as batch certificate
optional<vector<vector<uint8_t>>> attestationCert =
- createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+ createAttestation(pkey.get(), applicationId, challenge, nowMs, expireTimeMs,
+ false /* isTestCredential */);
if (!attestationCert) {
LOG(ERROR) << "Error create attestation from key and challenge";
return {};
@@ -1646,6 +1736,32 @@
return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
}
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate) {
+ vector<X509_Ptr> certs;
+ if (!parseX509Certificates(x509Certificate, certs)) {
+ LOG(ERROR) << "Error parsing certificates";
+ return {};
+ }
+ if (certs.size() < 1) {
+ LOG(ERROR) << "No certificates in chain";
+ return {};
+ }
+
+ time_t notBefore;
+ time_t notAfter;
+ if (!parseAsn1Time(X509_get0_notBefore(certs[0].get()), ¬Before)) {
+ LOG(ERROR) << "Error parsing notBefore";
+ return {};
+ }
+
+ if (!parseAsn1Time(X509_get0_notAfter(certs[0].get()), ¬After)) {
+ LOG(ERROR) << "Error parsing notAfter";
+ return {};
+ }
+
+ return std::make_pair(notBefore, notAfter);
+}
+
optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
vector<X509_Ptr> certs;
if (!parseX509Certificates(x509Certificate, certs)) {
@@ -2218,6 +2334,49 @@
// Utility functions specific to IdentityCredential.
// ---------------------------------------------------------------------------
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+ const vector<uint8_t>& publicKey,
+ const vector<uint8_t>& sessionTranscriptBytes) {
+ optional<vector<uint8_t>> sharedSecret = support::ecdh(publicKey, privateKey);
+ if (!sharedSecret) {
+ LOG(ERROR) << "Error performing ECDH";
+ return {};
+ }
+ vector<uint8_t> salt = support::sha256(sessionTranscriptBytes);
+ vector<uint8_t> info = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+ optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
+ if (!derivedKey) {
+ LOG(ERROR) << "Error performing HKDF";
+ return {};
+ }
+ return derivedKey.value();
+}
+
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+ const string& docType,
+ const vector<uint8_t>& deviceNameSpacesEncoded,
+ const vector<uint8_t>& eMacKey) {
+ auto [sessionTranscriptItem, _, errMsg] = cppbor::parse(sessionTranscriptEncoded);
+ if (sessionTranscriptItem == nullptr) {
+ LOG(ERROR) << "Error parsing sessionTranscriptEncoded: " << errMsg;
+ return {};
+ }
+ // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
+ // deviceNameSpacesBytes] so build up that structure
+ cppbor::Array deviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(std::move(sessionTranscriptItem))
+ .add(docType)
+ .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+ optional<vector<uint8_t>> calculatedMac =
+ support::coseMac0(eMacKey, {}, // payload
+ deviceAuthenticationBytes); // detached content
+ return calculatedMac;
+}
+
vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize) {
vector<vector<uint8_t>> ret;
@@ -2244,7 +2403,6 @@
return ret;
}
-
vector<uint8_t> testHardwareBoundKey = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const vector<uint8_t>& getTestHardwareBoundKey() {
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index c356549..266f263 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -436,6 +436,300 @@
support::cborPrettyPrint(mac.value()));
}
+// Generates a private key in DER format for a small value of 'd'.
+//
+// Used for test vectors.
+//
+vector<uint8_t> p256PrivateKeyFromD(uint8_t d) {
+ vector<uint8_t> privateUncompressed;
+ privateUncompressed.resize(32);
+ privateUncompressed[31] = d;
+ optional<vector<uint8_t>> privateKey = support::ecPrivateKeyToKeyPair(privateUncompressed);
+ return privateKey.value();
+}
+
+std::pair<vector<uint8_t>, vector<uint8_t>> p256PrivateKeyGetXandY(
+ const vector<uint8_t> privateKey) {
+ optional<vector<uint8_t>> publicUncompressed = support::ecKeyPairGetPublicKey(privateKey);
+ vector<uint8_t> x = vector<uint8_t>(publicUncompressed.value().begin() + 1,
+ publicUncompressed.value().begin() + 33);
+ vector<uint8_t> y = vector<uint8_t>(publicUncompressed.value().begin() + 33,
+ publicUncompressed.value().begin() + 65);
+ return std::make_pair(x, y);
+}
+
+const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
+ // TODO: Need cast until libcppbor's Map::get() is marked as const
+ auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
+ if (!found) {
+ return nullptr;
+ }
+ return item.get();
+}
+
+const cppbor::Array* findArrayValueForTstr(const cppbor::Map* map, const string& keyValue) {
+ const cppbor::Item* item = findValueForTstr(map, keyValue);
+ if (item == nullptr) {
+ return nullptr;
+ }
+ return item->asArray();
+}
+
+const cppbor::Map* findMapValueForTstr(const cppbor::Map* map, const string& keyValue) {
+ const cppbor::Item* item = findValueForTstr(map, keyValue);
+ if (item == nullptr) {
+ return nullptr;
+ }
+ return item->asMap();
+}
+
+const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+ const cppbor::Item* item = findValueForTstr(map, keyValue);
+ if (item == nullptr) {
+ return nullptr;
+ }
+ return item->asSemantic();
+}
+
+const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
+ const cppbor::Item* item = findValueForTstr(map, keyValue);
+ if (item == nullptr) {
+ return nullptr;
+ }
+ const cppbor::Tstr* tstr = item->asTstr();
+ if (tstr == nullptr) {
+ return "";
+ }
+ return tstr->value();
+}
+
+TEST(IdentityCredentialSupport, testVectors_18013_5) {
+ // This is a test against known vectors for ISO 18013-5.
+ //
+ // The objective of this test is to verify that support::calcEMacKey() and
+ // support::calcMac() agree with the given test vectors.
+ //
+
+ // We're given static device key:
+ //
+ // x: 28412803729898893058558238221310261427084375743576167377786533380249859400145
+ // y: 65403602826180996396520286939226973026599920614829401631985882360676038096704
+ // d: 11
+ //
+ vector<uint8_t> deviceKey = p256PrivateKeyFromD(11);
+ auto [deviceKeyX, deviceKeyY] = p256PrivateKeyGetXandY(deviceKey);
+ EXPECT_EQ(support::encodeHex(deviceKeyX),
+ "3ed113b7883b4c590638379db0c21cda16742ed0255048bf433391d374bc21d1");
+ EXPECT_EQ(support::encodeHex(deviceKeyY),
+ "9099209accc4c8a224c843afa4f4c68a090d04da5e9889dae2f8eefce82a3740");
+
+ // We're given Ephemeral reader key:
+ //
+ // x: 59535862115950685744176693329402396749019581632805653266809849538337418304154
+ // y: 53776829996815113213100700404832701936765102413212294632483274374518863708344
+ // d: 20
+ //
+ vector<uint8_t> ephemeralReaderKey = p256PrivateKeyFromD(20);
+ auto [ephemeralReaderKeyX, ephemeralReaderKeyY] = p256PrivateKeyGetXandY(ephemeralReaderKey);
+ EXPECT_EQ(support::encodeHex(ephemeralReaderKeyX),
+ "83a01a9378395bab9bcd6a0ad03cc56d56e6b19250465a94a234dc4c6b28da9a");
+ EXPECT_EQ(support::encodeHex(ephemeralReaderKeyY),
+ "76e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923f54ff8240aaa86f640b8");
+ vector<uint8_t> ephemeralReaderKeyPublic =
+ support::ecKeyPairGetPublicKey(ephemeralReaderKey).value();
+
+ // We're given SessionEstablishment.
+ //
+ // SessionEstablishment = {
+ // "eReaderKey" : EReaderKeyBytes,
+ // "data" : bstr ; Encrypted mdoc request
+ // }
+ //
+ // Fish out EReaderKey from this.
+ //
+ // Note that the test vector below is incorrect insofar that it uses
+ // "eReaderKeyBytes" instead of just "eReaderKey". This will be corrected in
+ // the future.
+ //
+ optional<vector<uint8_t>> sessionEstablishmentEncoded = support::decodeHex(
+ "a26f655265616465724b65794279746573d818584ba40102200121582083a01a9378395bab9bcd6a0ad03c"
+ "c56d56e6b19250465a94a234dc4c6b28da9a22582076e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923"
+ "f54ff8240aaa86f640b864646174615902d945b31040c57491acb6d46a71f6c1f67a0b837df1bda9089fd0"
+ "3d0b1fdac3eeb2874a4ef6f90c97d03397186ba00a91102faae7e992e15f761d5662c3c37e3c6c2cfd2ebc"
+ "0bf59dbb8795e377bd7dd353230a41ba2d82294b45871a39b42ca531f26b52f46e356fbaf5075c8fd5b8b0"
+ "8a0df4a1d2e1bdd2e5d69169c1efbb51e393e608d833d325bebfbccb2e15ec08f94b264582fa7b93f7cebc"
+ "aa69f4f0cac2744d4fe35b04df26b2ae69273eed33024949080c1c95a6ef046beede959e9494297dd770af"
+ "4ac6fdd56783aa012555c213dc05cf0f41d1c95119720fcfe1621027f80e2ddd56ea3c1fc596f7b2579333"
+ "5a887ec788092b4a69d23b6219e27d0249b50b3fdcb95b5227007689362e0416b3bae3dae7cb56b4394666"
+ "4e3a3f60dce8d0b678fcd754bebf87bd2b0278dd782d952488a46f2874e34c2dd97bb74084a62b850e9719"
+ "252cd1dca7dbf1858193f6cf093cb3735312bbe1138cf29d8f350e285923f8ef07065299926720b42264e8"
+ "fd5d4b133e72f47c4e999ea689c353f8b41e50a59838e1a0d09eca4a557f77a9c389a0591ad1639119ce86"
+ "edc3320130480ee5101effae6066e8c85aac9ead2ae83e49c1e508aab02f753decbb522ea2200d62fd5d26"
+ "094bd35100bffaa1cdc6af9f7e9cfe7b63da6b5671cd5ac2cf5da450c72addc64cde441f3b7f7fdaf930ad"
+ "1e13388e8a7308d8ca4607e59e082db431a232e7e12cb692baeb4b2127e110ff24cea322ffdbc2e4d9c4c6"
+ "bed27753137d07897c8613627a799a560cf1a2d1edb3de029442862940a5ed7785eea8b6ace93aa6af0792"
+ "fd82877f62d07b757d0179ecbb7347004ecc9c0690d41f75f188cb17ffd2cec2ad8c9675466bb33b737a2a"
+ "e7592b2dcb8132aced2e572266f3f5413a5f9d6d4339a1e4662622af2e7e157a4ea3bfd5c4247e2ec91d8c"
+ "5c3c17427d5edfae673d0e0f782a8d40fa805fd8bc82ae3cb21a65cdad863e02309f6b01d1753fa884b778"
+ "f6e019a2004d8964deeb11f1fd478fcb");
+ ASSERT_TRUE(sessionEstablishmentEncoded);
+ auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
+ const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
+ ASSERT_NE(sessionEstablishment, nullptr);
+ const cppbor::Semantic* eReaderKeyBytes =
+ findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
+ ASSERT_NE(eReaderKeyBytes, nullptr);
+ ASSERT_EQ(eReaderKeyBytes->value(), 24);
+ const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+ ASSERT_NE(eReaderKeyBstr, nullptr);
+ vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
+ // TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
+
+ // We're given DeviceEngagement.
+ //
+ vector<uint8_t> deviceEngagementEncoded =
+ support::decodeHex(
+ "a20063312e30018201d818584ba401022001215820cef66d6b2a3a993e591214d1ea223fb545ca"
+ "6c471c48306e4c36069404c5723f225820878662a229aaae906e123cdd9d3b4c10590ded29fe75"
+ "1eeeca34bbaa44af0773")
+ .value();
+
+ // Now calculate SessionTranscriptBytes. It is defined as
+ //
+ // SessionTranscript = [
+ // DeviceEngagementBytes,
+ // EReaderKeyBytes,
+ // Handover
+ // ]
+ //
+ // SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
+ //
+ cppbor::Array sessionTranscript;
+ sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
+ sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+ sessionTranscript.add(cppbor::Null());
+ vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+ vector<uint8_t> sessionTranscriptBytes =
+ cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+
+ // The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
+ //
+ // Verify that support::calcEMacKey() gets the same result.
+ //
+ optional<vector<uint8_t>> eMacKey =
+ support::calcEMacKey(support::ecKeyPairGetPrivateKey(deviceKey).value(), // private key
+ ephemeralReaderKeyPublic, // public key
+ sessionTranscriptBytes); // sessionTranscriptBytes
+ ASSERT_TRUE(eMacKey);
+ ASSERT_EQ(support::encodeHex(eMacKey.value()),
+ "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+ // Also do it the other way around
+ //
+ optional<vector<uint8_t>> eMacKey2 = support::calcEMacKey(
+ support::ecKeyPairGetPrivateKey(ephemeralReaderKey).value(), // private key
+ support::ecKeyPairGetPublicKey(deviceKey).value(), // public key
+ sessionTranscriptBytes); // sessionTranscriptBytes
+ ASSERT_TRUE(eMacKey2);
+ ASSERT_EQ(support::encodeHex(eMacKey2.value()),
+ "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+ // We're given DeviceResponse
+ //
+ vector<uint8_t> deviceResponseEncoded =
+ support::decodeHex(
+ "a36776657273696f6e63312e3069646f63756d656e747381a367646f6354797065756f72672e69"
+ "736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d6553706163"
+ "6573a2716f72672e69736f2e31383031332e352e3181d8185863a4686469676573744944016672"
+ "616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e9"
+ "71656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456"
+ "616c756563446f656b636f6d2e6578616d706c6581d8185864a468646967657374494401667261"
+ "6e646f6d5820218ecf13521b53f4b96abaebe56417afec0e4c91fc8fb26086cd1e5cdc1a94ff71"
+ "656c656d656e744964656e7469666965726f616e6f746865725f656c656d656e746c656c656d65"
+ "6e7456616c75650a6a697373756572417574688443a10126a118215901d2308201ce30820174a0"
+ "0302010202141f7d44f4f107c5ee3f566049cf5d72de294b0d23300a06082a8648ce3d04030230"
+ "233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e17"
+ "0d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504"
+ "030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106"
+ "082a8648ce3d03010703420004301d9e502dc7e05da85da026a7ae9aa0fac9db7d52a95b3e3e3f"
+ "9aa0a1b45b8b6551b6f6b3061223e0d23c026b017d72298d9ae46887ca61d58db6aea17ee267a3"
+ "8187308184301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c"
+ "0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e04160414"
+ "7bef4db59a1ffb07592bfc57f4743b8a73aea792300e0603551d0f0101ff040403020780301506"
+ "03551d250101ff040b3009060728818c5d050102300a06082a8648ce3d04030203480030450220"
+ "21d52fb1fbda80e5bfda1e8dfb1bc7bf0acb7261d5c9ff54425af76eb21571c602210082bf301f"
+ "89e0a2cb9ca9c9050352de80b47956764f7a3e07bf6a8cd87528a3b55901d2d8185901cda66776"
+ "657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c75"
+ "6544696765737473a2716f72672e69736f2e31383031332e352e31a20058203b22af1126771f02"
+ "f0ea0d546d4ee3c5b51637381154f5211b79daf5f9facaa8015820f2cba0ce3cde5df901a3da75"
+ "13a4d7f7225fdfe5a306544529bf3dbcce655ca06b636f6d2e6578616d706c65a200582072636d"
+ "ddc282424a63499f4b3927aaa3b74da7b9c0134178bf735e949e4a761e01582006322d3cbe6603"
+ "876bdacc5b6679b51b0fc53d029c244fd5ea719d9028459c916d6465766963654b6579496e666f"
+ "a1696465766963654b6579a4010220012158203ed113b7883b4c590638379db0c21cda16742ed0"
+ "255048bf433391d374bc21d12258209099209accc4c8a224c843afa4f4c68a090d04da5e9889da"
+ "e2f8eefce82a374067646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c"
+ "76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a"
+ "30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c"
+ "6964556e74696cc074323032312d31302d30315431333a33303a30325a5840273ec1b59817d571"
+ "b5a2c5c0ab0ea213d42acb18547fd7097afcc888a22ecbb863c6461ce0e240880895b4aaa84308"
+ "784571c7be7aa3a2e7e3a2ea1a145ed1966c6465766963655369676e6564a26a6e616d65537061"
+ "636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f6582009"
+ "da7c964ac004ec36ec64edd0c1abf50c03433c215c3ddb144768abcdf20a60667374617475730"
+ "0")
+ .value();
+ auto [deviceResponseItem, _, _2] = cppbor::parse(deviceResponseEncoded);
+ const cppbor::Map* deviceResponse = deviceResponseItem->asMap();
+ ASSERT_NE(deviceResponse, nullptr);
+ const cppbor::Array* documents = findArrayValueForTstr(deviceResponse, "documents");
+ ASSERT_NE(documents, nullptr);
+ ASSERT_EQ(documents->size(), 1);
+ const cppbor::Map* document = ((*documents)[0])->asMap();
+ ASSERT_NE(document, nullptr);
+
+ // Get docType
+ string docType = findStringValueForTstr(document, "docType");
+ ASSERT_EQ(docType, "org.iso.18013.5.1.mDL");
+
+ // Drill down...
+ const cppbor::Map* deviceSigned = findMapValueForTstr(document, "deviceSigned");
+ ASSERT_NE(deviceSigned, nullptr);
+
+ // Dig out the encoded form of DeviceNameSpaces
+ //
+ const cppbor::Semantic* deviceNameSpacesBytes =
+ findSemanticValueForTstr(deviceSigned, "nameSpaces");
+ ASSERT_NE(deviceNameSpacesBytes, nullptr);
+ ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
+ const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+ ASSERT_NE(deviceNameSpacesBstr, nullptr);
+ vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
+
+ // (For this version of 18013-5, DeviceNameSpaces is always supposed to be empty, check that.)
+ EXPECT_EQ(deviceNameSpacesEncoded, cppbor::Map().encode());
+
+ const cppbor::Map* deviceAuth = findMapValueForTstr(deviceSigned, "deviceAuth");
+ ASSERT_NE(deviceAuth, nullptr);
+ // deviceMac is is the COSE_Mac0.. dig out the encoded form to check that
+ // support::calcMac() gives exactly the same bytes.
+ //
+ const cppbor::Array* deviceMac = findArrayValueForTstr(deviceAuth, "deviceMac");
+ ASSERT_NE(deviceMac, nullptr);
+ vector<uint8_t> deviceMacEncoded = deviceMac->encode();
+
+ // Now we calculate what it should be..
+ optional<vector<uint8_t>> calculatedMac =
+ support::calcMac(sessionTranscriptEncoded, // SessionTranscript
+ docType, // DocType
+ deviceNameSpacesEncoded, // DeviceNamespaces
+ eMacKey.value()); // EMacKey
+ ASSERT_TRUE(calculatedMac);
+
+ // ... and hopefully it's the same!
+ ASSERT_EQ(calculatedMac.value().size(), deviceMacEncoded.size());
+ EXPECT_TRUE(memcmp(calculatedMac.value().data(), deviceMacEncoded.data(),
+ deviceMacEncoded.size()) == 0);
+}
+
} // namespace identity
} // namespace hardware
} // namespace android
diff --git a/keymaster/3.0/IKeymasterDevice.hal b/keymaster/3.0/IKeymasterDevice.hal
index 2664765..9bd8602 100644
--- a/keymaster/3.0/IKeymasterDevice.hal
+++ b/keymaster/3.0/IKeymasterDevice.hal
@@ -20,6 +20,7 @@
* Keymaster device definition. For thorough documentation see the implementer's reference, at
* https://source.android.com/security/keystore/implementer-ref.html
*/
+@SensitiveData
interface IKeymasterDevice {
/**
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
index 7d3e6f2..8b416c3 100644
--- a/keymaster/3.0/default/KeymasterDevice.cpp
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -22,7 +22,6 @@
#include <log/log.h>
#include <AndroidKeymaster3Device.h>
-#include <hardware/keymaster0.h>
#include <hardware/keymaster1.h>
#include <hardware/keymaster2.h>
#include <hardware/keymaster_defs.h>
@@ -33,16 +32,6 @@
namespace V3_0 {
namespace implementation {
-static int get_keymaster0_dev(keymaster0_device_t** dev, const hw_module_t* mod) {
- int rc = keymaster0_open(mod, dev);
- if (rc) {
- ALOGE("Error opening keystore keymaster0 device.");
- *dev = nullptr;
- return rc;
- }
- return 0;
-}
-
static int get_keymaster1_dev(keymaster1_device_t** dev, const hw_module_t* mod) {
int rc = keymaster1_open(mod, dev);
if (rc) {
@@ -75,11 +64,7 @@
}
if (mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0) {
- keymaster0_device_t* dev = nullptr;
- if (get_keymaster0_dev(&dev, mod)) {
- return nullptr;
- }
- return ::keymaster::ng::CreateKeymasterDevice(dev);
+ return nullptr;
} else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
keymaster1_device_t* dev = nullptr;
if (get_keymaster1_dev(&dev, mod)) {
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index 3475f79..dfde060 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -195,7 +195,7 @@
* Tag::VENDOR_PATCHLEVEL, and Tag::BOOT_PATCHLEVEL must be cryptographically bound to every
* IKeymasterDevice key, as described in the Key Access Control section above.
*/
-
+@SensitiveData
interface IKeymasterDevice {
/**
diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal
index bbeccaa..ccb9f2e 100644
--- a/keymaster/4.1/IKeymasterDevice.hal
+++ b/keymaster/4.1/IKeymasterDevice.hal
@@ -37,6 +37,7 @@
* versions will be numbered as major_version * 10 + minor version. The addition of new attestable
* tags changes the attestation format again, slightly, so the attestationVersion must be 4.
*/
+@SensitiveData
interface IKeymasterDevice extends @4.0::IKeymasterDevice {
/**
* Called by client to notify the IKeymasterDevice that the device is now locked, and keys with
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 598b6b5..207a7e8 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -102,6 +102,7 @@
ASN1_INTEGER* boot_patchlevel;
ASN1_NULL* early_boot_only;
ASN1_NULL* device_unique_attestation;
+ ASN1_NULL* identity_credential_key;
} KM_AUTH_LIST;
ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -145,6 +146,8 @@
ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
+ TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
@@ -285,6 +288,7 @@
copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+ copyAuthTag(record->identity_credential_key, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
return ErrorCode::OK;
}
@@ -327,7 +331,10 @@
p = attest_rec->data;
KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
- if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+ if (!record.get()) {
+ LOG(ERROR) << "Unable to get key description";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
AttestationRecord result;
@@ -352,10 +359,12 @@
if (error != ErrorCode::OK) return {error, {}};
KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ SecurityLevel root_of_trust_security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
if (record->tee_enforced && record->tee_enforced->root_of_trust) {
root_of_trust = record->tee_enforced->root_of_trust;
} else if (record->software_enforced && record->software_enforced->root_of_trust) {
root_of_trust = record->software_enforced->root_of_trust;
+ root_of_trust_security_level = SecurityLevel::SOFTWARE;
} else {
LOG(ERROR) << AT << " Failed root of trust parsing";
return {ErrorCode::INVALID_ARGUMENT, {}};
@@ -373,6 +382,7 @@
rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
rot.device_locked = root_of_trust->device_locked;
+ rot.security_level = root_of_trust_security_level;
auto& vb_hash = root_of_trust->verified_boot_hash;
if (!vb_hash) {
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 5206721..56a3ca9 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -20,12 +20,3 @@
"2",
],
}
-
-// This is a reminder that the next version of keymaster should be frozen at
-// version "5" to avoid confusion with other versions of this interface.
-cc_library {
- name: "android.hardware.keymaster-V3-java",
-}
-cc_library {
- name: "android.hardware.keymaster-V4-java",
-}
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
index f129783..00578a4 100644
--- a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2020 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.
diff --git a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
index 4b2f108..19ea944 100644
--- a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
@@ -16,6 +16,14 @@
package android.hardware.keymaster;
+
+/**
+ * Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+
@VintfStability
parcelable Timestamp {
long milliSeconds;
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
index eff9ca6..f053254 100644
--- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -18,7 +18,6 @@
import android.hardware.keymaster.SecurityLevel;
import android.hardware.keymaster.Timestamp;
-import android.hardware.keymaster.HardwareAuthenticatorType;
/**
* VerificationToken instances are used for secure environments to authenticate one another.
@@ -40,6 +39,7 @@
*/
Timestamp timestamp;
+
/**
* SecurityLevel of the secure environment that generated the token.
*/
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
index 57a052f..4d61fc0 100644
--- a/neuralnetworks/1.0/utils/Android.bp
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -20,6 +20,7 @@
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal/1.0/"],
export_include_dirs: ["include"],
+ cflags: ["-Wthread-safety"],
static_libs: [
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h
new file mode 100644
index 0000000..65b75e5
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+ public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+ Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+ Return<void> notify(ErrorStatus status) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
index 8ad98cb..d3d933b 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
@@ -24,42 +24,59 @@
namespace android::nn {
-Result<OperandType> convert(const hal::V1_0::OperandType& operandType);
-Result<OperationType> convert(const hal::V1_0::OperationType& operationType);
-Result<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime);
-Result<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus);
-Result<Capabilities::PerformanceInfo> convert(const hal::V1_0::PerformanceInfo& performanceInfo);
-Result<Capabilities> convert(const hal::V1_0::Capabilities& capabilities);
-Result<DataLocation> convert(const hal::V1_0::DataLocation& location);
-Result<Operand> convert(const hal::V1_0::Operand& operand);
-Result<Operation> convert(const hal::V1_0::Operation& operation);
-Result<Model::OperandValues> convert(const hardware::hidl_vec<uint8_t>& operandValues);
-Result<Memory> convert(const hardware::hidl_memory& memory);
-Result<Model> convert(const hal::V1_0::Model& model);
-Result<Request::Argument> convert(const hal::V1_0::RequestArgument& requestArgument);
-Result<Request> convert(const hal::V1_0::Request& request);
-Result<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status);
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_0::OperandType& operandType);
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_0::OperationType& operationType);
+GeneralResult<Operand::LifeTime> unvalidatedConvert(const hal::V1_0::OperandLifeTime& lifetime);
+GeneralResult<DeviceStatus> unvalidatedConvert(const hal::V1_0::DeviceStatus& deviceStatus);
+GeneralResult<Capabilities::PerformanceInfo> unvalidatedConvert(
+ const hal::V1_0::PerformanceInfo& performanceInfo);
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_0::Capabilities& capabilities);
+GeneralResult<DataLocation> unvalidatedConvert(const hal::V1_0::DataLocation& location);
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_0::Operand& operand);
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_0::Operation& operation);
+GeneralResult<Model::OperandValues> unvalidatedConvert(
+ const hardware::hidl_vec<uint8_t>& operandValues);
+GeneralResult<Memory> unvalidatedConvert(const hardware::hidl_memory& memory);
+GeneralResult<Model> unvalidatedConvert(const hal::V1_0::Model& model);
+GeneralResult<Request::Argument> unvalidatedConvert(
+ const hal::V1_0::RequestArgument& requestArgument);
+GeneralResult<Request> unvalidatedConvert(const hal::V1_0::Request& request);
+GeneralResult<ErrorStatus> unvalidatedConvert(const hal::V1_0::ErrorStatus& status);
+
+GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus);
+GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities);
+GeneralResult<Model> convert(const hal::V1_0::Model& model);
+GeneralResult<Request> convert(const hal::V1_0::Request& request);
+GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status);
} // namespace android::nn
namespace android::hardware::neuralnetworks::V1_0::utils {
-nn::Result<OperandType> convert(const nn::OperandType& operandType);
-nn::Result<OperationType> convert(const nn::OperationType& operationType);
-nn::Result<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime);
-nn::Result<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
-nn::Result<PerformanceInfo> convert(const nn::Capabilities::PerformanceInfo& performanceInfo);
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities);
-nn::Result<DataLocation> convert(const nn::DataLocation& location);
-nn::Result<Operand> convert(const nn::Operand& operand);
-nn::Result<Operation> convert(const nn::Operation& operation);
-nn::Result<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues);
-nn::Result<hidl_memory> convert(const nn::Memory& memory);
-nn::Result<Model> convert(const nn::Model& model);
-nn::Result<RequestArgument> convert(const nn::Request::Argument& requestArgument);
-nn::Result<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool);
-nn::Result<Request> convert(const nn::Request& request);
-nn::Result<ErrorStatus> convert(const nn::ErrorStatus& status);
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType);
+nn::GeneralResult<OperandLifeTime> unvalidatedConvert(const nn::Operand::LifeTime& lifetime);
+nn::GeneralResult<DeviceStatus> unvalidatedConvert(const nn::DeviceStatus& deviceStatus);
+nn::GeneralResult<PerformanceInfo> unvalidatedConvert(
+ const nn::Capabilities::PerformanceInfo& performanceInfo);
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
+nn::GeneralResult<DataLocation> unvalidatedConvert(const nn::DataLocation& location);
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand);
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation);
+nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
+ const nn::Model::OperandValues& operandValues);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory);
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
+nn::GeneralResult<RequestArgument> unvalidatedConvert(const nn::Request::Argument& requestArgument);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool);
+nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request);
+nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& status);
+
+nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<Request> convert(const nn::Request& request);
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status);
} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
new file mode 100644
index 0000000..ee103ba
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class Device final : public nn::IDevice {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+ sp<V1_0::IDevice> device);
+
+ Device(PrivateConstructorTag tag, std::string name, nn::Capabilities capabilities,
+ sp<V1_0::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ const std::string kName;
+ const std::string kVersionString = "UNKNOWN";
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ const sp<V1_0::IDevice> kDevice;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
new file mode 100644
index 0000000..31f366d
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+ sp<V1_0::IPreparedModel> preparedModel);
+
+ PreparedModel(PrivateConstructorTag tag, sp<V1_0::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler);
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+ std::any getUnderlyingResource() const override;
+
+ private:
+ const sp<V1_0::IPreparedModel> kPreparedModel;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.h
new file mode 100644
index 0000000..11fbb9e
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
index ec8da06..4cec545 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
@@ -23,18 +23,14 @@
#include <android/hardware/neuralnetworks/1.0/types.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
namespace android::hardware::neuralnetworks::V1_0::utils {
-constexpr auto kVersion = nn::Version::ANDROID_OC_MR1;
-
template <typename Type>
nn::Result<void> validate(const Type& halObject) {
- const auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
+ const auto maybeCanonical = nn::convert(halObject);
+ if (!maybeCanonical.has_value()) {
+ return nn::error() << maybeCanonical.error().message;
}
return {};
}
@@ -48,16 +44,6 @@
return result.has_value();
}
-template <typename Type>
-decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
- auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
- }
- return canonical;
-}
-
} // namespace android::hardware::neuralnetworks::V1_0::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H
diff --git a/neuralnetworks/1.0/utils/src/Callbacks.cpp b/neuralnetworks/1.0/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..b1259c3
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Callbacks.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<IPreparedModel>& preparedModel) {
+ return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+} // namespace
+
+Return<void> PreparedModelCallback::notify(ErrorStatus status,
+ const sp<IPreparedModel>& preparedModel) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+ return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(ErrorStatus status) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal({});
+ }
+ return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+ return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp
index 4a58f3b..fde7346 100644
--- a/neuralnetworks/1.0/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.0/utils/src/Conversions.cpp
@@ -22,7 +22,9 @@
#include <nnapi/OperationTypes.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
+#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
#include <nnapi/hal/CommonUtils.h>
#include <algorithm>
@@ -40,6 +42,8 @@
return static_cast<std::underlying_type_t<Type>>(value);
}
+constexpr auto kVersion = android::nn::Version::ANDROID_OC_MR1;
+
} // namespace
namespace android::nn {
@@ -49,46 +53,64 @@
using hardware::hidl_vec;
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-Result<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
- std::vector<ConvertOutput<Type>> canonical;
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
- canonical.push_back(NN_TRY(nn::convert(argument)));
+ canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
+ }
+ return canonical;
+}
+
+template <typename Type>
+decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+ auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
+ const auto maybeVersion = validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
return canonical;
}
} // anonymous namespace
-Result<OperandType> convert(const hal::V1_0::OperandType& operandType) {
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_0::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-Result<OperationType> convert(const hal::V1_0::OperationType& operationType) {
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_0::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-Result<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime) {
+GeneralResult<Operand::LifeTime> unvalidatedConvert(const hal::V1_0::OperandLifeTime& lifetime) {
return static_cast<Operand::LifeTime>(lifetime);
}
-Result<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus) {
+GeneralResult<DeviceStatus> unvalidatedConvert(const hal::V1_0::DeviceStatus& deviceStatus) {
return static_cast<DeviceStatus>(deviceStatus);
}
-Result<Capabilities::PerformanceInfo> convert(const hal::V1_0::PerformanceInfo& performanceInfo) {
+GeneralResult<Capabilities::PerformanceInfo> unvalidatedConvert(
+ const hal::V1_0::PerformanceInfo& performanceInfo) {
return Capabilities::PerformanceInfo{
.execTime = performanceInfo.execTime,
.powerUsage = performanceInfo.powerUsage,
};
}
-Result<Capabilities> convert(const hal::V1_0::Capabilities& capabilities) {
- const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
- const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_0::Capabilities& capabilities) {
+ const auto quantized8Performance =
+ NN_TRY(unvalidatedConvert(capabilities.quantized8Performance));
+ const auto float32Performance = NN_TRY(unvalidatedConvert(capabilities.float32Performance));
auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
quantized8Performance);
@@ -100,7 +122,7 @@
};
}
-Result<DataLocation> convert(const hal::V1_0::DataLocation& location) {
+GeneralResult<DataLocation> unvalidatedConvert(const hal::V1_0::DataLocation& location) {
return DataLocation{
.poolIndex = location.poolIndex,
.offset = location.offset,
@@ -108,35 +130,35 @@
};
}
-Result<Operand> convert(const hal::V1_0::Operand& operand) {
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_0::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
};
}
-Result<Operation> convert(const hal::V1_0::Operation& operation) {
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_0::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-Result<Model::OperandValues> convert(const hidl_vec<uint8_t>& operandValues) {
+GeneralResult<Model::OperandValues> unvalidatedConvert(const hidl_vec<uint8_t>& operandValues) {
return Model::OperandValues(operandValues.data(), operandValues.size());
}
-Result<Memory> convert(const hidl_memory& memory) {
+GeneralResult<Memory> unvalidatedConvert(const hidl_memory& memory) {
return createSharedMemoryFromHidlMemory(memory);
}
-Result<Model> convert(const hal::V1_0::Model& model) {
- auto operations = NN_TRY(convert(model.operations));
+GeneralResult<Model> unvalidatedConvert(const hal::V1_0::Model& model) {
+ auto operations = NN_TRY(unvalidatedConvert(model.operations));
// Verify number of consumers.
const auto numberOfConsumers =
@@ -144,14 +166,14 @@
CHECK(model.operands.size() == numberOfConsumers.size());
for (size_t i = 0; i < model.operands.size(); ++i) {
if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
- return NN_ERROR() << "Invalid numberOfConsumers for operand " << i << ", expected "
- << numberOfConsumers[i] << " but found "
- << model.operands[i].numberOfConsumers;
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
+ << "Invalid numberOfConsumers for operand " << i << ", expected "
+ << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
}
}
auto main = Model::Subgraph{
- .operands = NN_TRY(convert(model.operands)),
+ .operands = NN_TRY(unvalidatedConvert(model.operands)),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
@@ -159,35 +181,35 @@
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
};
}
-Result<Request::Argument> convert(const hal::V1_0::RequestArgument& argument) {
+GeneralResult<Request::Argument> unvalidatedConvert(const hal::V1_0::RequestArgument& argument) {
const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
: Request::Argument::LifeTime::POOL;
return Request::Argument{
.lifetime = lifetime,
- .location = NN_TRY(convert(argument.location)),
+ .location = NN_TRY(unvalidatedConvert(argument.location)),
.dimensions = argument.dimensions,
};
}
-Result<Request> convert(const hal::V1_0::Request& request) {
- auto memories = NN_TRY(convert(request.pools));
+GeneralResult<Request> unvalidatedConvert(const hal::V1_0::Request& request) {
+ auto memories = NN_TRY(unvalidatedConvert(request.pools));
std::vector<Request::MemoryPool> pools;
pools.reserve(memories.size());
std::move(memories.begin(), memories.end(), std::back_inserter(pools));
return Request{
- .inputs = NN_TRY(convert(request.inputs)),
- .outputs = NN_TRY(convert(request.outputs)),
+ .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
+ .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
.pools = std::move(pools),
};
}
-Result<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status) {
+GeneralResult<ErrorStatus> unvalidatedConvert(const hal::V1_0::ErrorStatus& status) {
switch (status) {
case hal::V1_0::ErrorStatus::NONE:
case hal::V1_0::ErrorStatus::DEVICE_UNAVAILABLE:
@@ -196,7 +218,28 @@
case hal::V1_0::ErrorStatus::INVALID_ARGUMENT:
return static_cast<ErrorStatus>(status);
}
- return NN_ERROR() << "Invalid ErrorStatus " << underlyingType(status);
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
+ << "Invalid ErrorStatus " << underlyingType(status);
+}
+
+GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus) {
+ return validatedConvert(deviceStatus);
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+GeneralResult<Model> convert(const hal::V1_0::Model& model) {
+ return validatedConvert(model);
+}
+
+GeneralResult<Request> convert(const hal::V1_0::Request& request) {
+ return validatedConvert(request);
+}
+
+GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status) {
+ return validatedConvert(status);
}
} // namespace android::nn
@@ -205,55 +248,72 @@
namespace {
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-nn::Result<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
- hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
- halObject[i] = NN_TRY(utils::convert(arguments[i]));
+ halObject[i] = NN_TRY(utils::unvalidatedConvert(arguments[i]));
}
return halObject;
}
+template <typename Type>
+decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
+ const auto maybeVersion = nn::validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return nn::error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return utils::unvalidatedConvert(canonical);
+}
+
} // anonymous namespace
-nn::Result<OperandType> convert(const nn::OperandType& operandType) {
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-nn::Result<OperationType> convert(const nn::OperationType& operationType) {
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-nn::Result<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
+nn::GeneralResult<OperandLifeTime> unvalidatedConvert(const nn::Operand::LifeTime& lifetime) {
if (lifetime == nn::Operand::LifeTime::POINTER) {
- return NN_ERROR() << "Model cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
return static_cast<OperandLifeTime>(lifetime);
}
-nn::Result<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
+nn::GeneralResult<DeviceStatus> unvalidatedConvert(const nn::DeviceStatus& deviceStatus) {
return static_cast<DeviceStatus>(deviceStatus);
}
-nn::Result<PerformanceInfo> convert(const nn::Capabilities::PerformanceInfo& performanceInfo) {
+nn::GeneralResult<PerformanceInfo> unvalidatedConvert(
+ const nn::Capabilities::PerformanceInfo& performanceInfo) {
return PerformanceInfo{
.execTime = performanceInfo.execTime,
.powerUsage = performanceInfo.powerUsage,
};
}
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities) {
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
return Capabilities{
- .float32Performance = NN_TRY(convert(
+ .float32Performance = NN_TRY(unvalidatedConvert(
capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
- .quantized8Performance = NN_TRY(convert(
+ .quantized8Performance = NN_TRY(unvalidatedConvert(
capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
};
}
-nn::Result<DataLocation> convert(const nn::DataLocation& location) {
+nn::GeneralResult<DataLocation> unvalidatedConvert(const nn::DataLocation& location) {
return DataLocation{
.poolIndex = location.poolIndex,
.offset = location.offset,
@@ -261,43 +321,43 @@
};
}
-nn::Result<Operand> convert(const nn::Operand& operand) {
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
};
}
-nn::Result<Operation> convert(const nn::Operation& operation) {
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-nn::Result<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
+nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
+ const nn::Model::OperandValues& operandValues) {
return hidl_vec<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
}
-nn::Result<hidl_memory> convert(const nn::Memory& memory) {
- const auto hidlMemory = hidl_memory(memory.name, memory.handle->handle(), memory.size);
- // Copy memory to force the native_handle_t to be copied.
- auto copiedMemory = hidlMemory;
- return copiedMemory;
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+ return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)),
+ memory.size);
}
-nn::Result<Model> convert(const nn::Model& model) {
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
if (!hal::utils::hasNoPointerData(model)) {
- return NN_ERROR() << "Mdoel cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Mdoel cannot be unvalidatedConverted because it contains pointer-based memory";
}
- auto operands = NN_TRY(convert(model.main.operands));
+ auto operands = NN_TRY(unvalidatedConvert(model.main.operands));
// Update number of consumers.
const auto numberOfConsumers =
@@ -309,43 +369,46 @@
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(convert(model.main.operations)),
+ .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
};
}
-nn::Result<RequestArgument> convert(const nn::Request::Argument& requestArgument) {
+nn::GeneralResult<RequestArgument> unvalidatedConvert(
+ const nn::Request::Argument& requestArgument) {
if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
- return NN_ERROR() << "Request cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
return RequestArgument{
.hasNoValue = hasNoValue,
- .location = NN_TRY(convert(requestArgument.location)),
+ .location = NN_TRY(unvalidatedConvert(requestArgument.location)),
.dimensions = requestArgument.dimensions,
};
}
-nn::Result<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool) {
- return convert(std::get<nn::Memory>(memoryPool));
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) {
+ return unvalidatedConvert(std::get<nn::Memory>(memoryPool));
}
-nn::Result<Request> convert(const nn::Request& request) {
+nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
if (!hal::utils::hasNoPointerData(request)) {
- return NN_ERROR() << "Request cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
return Request{
- .inputs = NN_TRY(convert(request.inputs)),
- .outputs = NN_TRY(convert(request.outputs)),
- .pools = NN_TRY(convert(request.pools)),
+ .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
+ .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
+ .pools = NN_TRY(unvalidatedConvert(request.pools)),
};
}
-nn::Result<ErrorStatus> convert(const nn::ErrorStatus& status) {
+nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& status) {
switch (status) {
case nn::ErrorStatus::NONE:
case nn::ErrorStatus::DEVICE_UNAVAILABLE:
@@ -358,4 +421,24 @@
}
}
+nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
+ return validatedConvert(deviceStatus);
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+ return validatedConvert(model);
+}
+
+nn::GeneralResult<Request> convert(const nn::Request& request) {
+ return validatedConvert(request);
+}
+
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status) {
+ return validatedConvert(status);
+}
+
} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp
new file mode 100644
index 0000000..285c515
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Device.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Device.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_0::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities failed with " << toString(status);
+ } else {
+ result = nn::convert(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+ sp<V1_0::IDevice> device) {
+ if (name.empty()) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_0::utils::Device::create must have non-empty name";
+ }
+ if (device == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_0::utils::Device::create must have non-null device";
+ }
+
+ auto capabilities = NN_TRY(initCapabilities(device.get()));
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+ return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
+ std::move(capabilities), std::move(device),
+ std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
+ sp<V1_0::IDevice> device, hal::utils::DeathHandler deathHandler)
+ : kName(std::move(name)),
+ kCapabilities(std::move(capabilities)),
+ kDevice(std::move(device)),
+ kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+ return kName;
+}
+
+const std::string& Device::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+ return nn::Version::ANDROID_OC_MR1;
+}
+
+nn::DeviceType Device::getType() const {
+ return nn::DeviceType::OTHER;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+ return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
+}
+
+nn::GeneralResult<void> Device::wait() const {
+ const auto ret = kDevice->ping();
+ HANDLE_TRANSPORT_FAILURE(ret);
+ return {};
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+
+ nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical)
+ << "getSupportedOperations failed with " << toString(status);
+ } else if (supportedOperations.size() != model.main.operations.size()) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "getSupportedOperations returned vector of size "
+ << supportedOperations.size() << " but expected "
+ << model.main.operations.size();
+ } else {
+ result = supportedOperations;
+ }
+ };
+
+ const auto ret = kDevice->getSupportedOperations(hidlModel, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+ const nn::Model& model, nn::ExecutionPreference /*preference*/, nn::Priority /*priority*/,
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+
+ const auto cb = sp<PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kDevice->prepareModel(hidlModel, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::prepareModelFromCache not supported on 1.0 HAL service";
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+ const nn::BufferDesc& /*desc*/,
+ const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+ const std::vector<nn::BufferRole>& /*inputRoles*/,
+ const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::allocate not supported on 1.0 HAL service";
+}
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..46dd3f8
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+ sp<V1_0::IPreparedModel> preparedModel) {
+ if (preparedModel == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_0::utils::PreparedModel::create must have non-null preparedModel";
+ }
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+ return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+ std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_0::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler)
+ : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+ const nn::Request& request, nn::MeasureTiming /*measure*/,
+ const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+ const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+
+ const auto cb = sp<ExecutionCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kPreparedModel->execute(hidlRequest, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "execute failed with " << toString(status);
+ }
+
+ auto result = NN_TRY(cb->get());
+ NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+
+ return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+ const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+ nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+ const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IPreparedModel::executeFenced is not supported on 1.0 HAL service";
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+ sp<V1_0::IPreparedModel> resource = kPreparedModel;
+ return resource;
+}
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Service.cpp b/neuralnetworks/1.0/utils/src/Service.cpp
new file mode 100644
index 0000000..ec28b1d
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+ hal::utils::ResilientDevice::Factory makeDevice =
+ [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+ auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+ if (service == nullptr) {
+ return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+ }
+ return Device::create(name, std::move(service));
+ };
+
+ return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
index 85a32c5..909575b 100644
--- a/neuralnetworks/1.1/utils/Android.bp
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -20,6 +20,7 @@
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal/1.1/"],
export_include_dirs: ["include"],
+ cflags: ["-Wthread-safety"],
static_libs: [
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h
index d0c5397..f646462 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h
@@ -24,21 +24,32 @@
namespace android::nn {
-Result<OperationType> convert(const hal::V1_1::OperationType& operationType);
-Result<Capabilities> convert(const hal::V1_1::Capabilities& capabilities);
-Result<Operation> convert(const hal::V1_1::Operation& operation);
-Result<Model> convert(const hal::V1_1::Model& model);
-Result<ExecutionPreference> convert(const hal::V1_1::ExecutionPreference& executionPreference);
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_1::OperationType& operationType);
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_1::Capabilities& capabilities);
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_1::Operation& operation);
+GeneralResult<Model> unvalidatedConvert(const hal::V1_1::Model& model);
+GeneralResult<ExecutionPreference> unvalidatedConvert(
+ const hal::V1_1::ExecutionPreference& executionPreference);
+
+GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities);
+GeneralResult<Model> convert(const hal::V1_1::Model& model);
+GeneralResult<ExecutionPreference> convert(
+ const hal::V1_1::ExecutionPreference& executionPreference);
} // namespace android::nn
namespace android::hardware::neuralnetworks::V1_1::utils {
-nn::Result<OperationType> convert(const nn::OperationType& operationType);
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities);
-nn::Result<Operation> convert(const nn::Operation& operation);
-nn::Result<Model> convert(const nn::Model& model);
-nn::Result<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference);
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType);
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation);
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
+nn::GeneralResult<ExecutionPreference> unvalidatedConvert(
+ const nn::ExecutionPreference& executionPreference);
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference);
} // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
new file mode 100644
index 0000000..c1e95fe1a
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+class Device final : public nn::IDevice {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+ sp<V1_1::IDevice> device);
+
+ Device(PrivateConstructorTag tag, std::string name, nn::Capabilities capabilities,
+ sp<V1_1::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ const std::string kName;
+ const std::string kVersionString = "UNKNOWN";
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ const sp<V1_1::IDevice> kDevice;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.h
new file mode 100644
index 0000000..a3ad3cf
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+} // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
index 6f9aa60..052d88e 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
@@ -23,20 +23,17 @@
#include <android/hardware/neuralnetworks/1.1/types.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
namespace android::hardware::neuralnetworks::V1_1::utils {
constexpr auto kDefaultExecutionPreference = ExecutionPreference::FAST_SINGLE_ANSWER;
-constexpr auto kVersion = nn::Version::ANDROID_P;
template <typename Type>
nn::Result<void> validate(const Type& halObject) {
- const auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
+ const auto maybeCanonical = nn::convert(halObject);
+ if (!maybeCanonical.has_value()) {
+ return nn::error() << maybeCanonical.error().message;
}
return {};
}
@@ -50,16 +47,6 @@
return result.has_value();
}
-template <typename Type>
-decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
- auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
- }
- return canonical;
-}
-
} // namespace android::hardware::neuralnetworks::V1_1::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H
diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp
index 7fee16b..359f68a 100644
--- a/neuralnetworks/1.1/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.1/utils/src/Conversions.cpp
@@ -23,7 +23,9 @@
#include <nnapi/OperationTypes.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
+#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/CommonUtils.h>
@@ -33,35 +35,58 @@
#include <type_traits>
#include <utility>
+namespace {
+
+constexpr auto kVersion = android::nn::Version::ANDROID_P;
+
+} // namespace
+
namespace android::nn {
namespace {
using hardware::hidl_vec;
template <typename Input>
-using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-Result<std::vector<convertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
- std::vector<convertOutput<Type>> canonical;
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
- canonical.push_back(NN_TRY(nn::convert(argument)));
+ canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
+ }
+ return canonical;
+}
+
+template <typename Type>
+decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+ auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
+ const auto maybeVersion = validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
return canonical;
}
} // anonymous namespace
-Result<OperationType> convert(const hal::V1_1::OperationType& operationType) {
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_1::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-Result<Capabilities> convert(const hal::V1_1::Capabilities& capabilities) {
- const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
- const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_1::Capabilities& capabilities) {
+ const auto quantized8Performance =
+ NN_TRY(unvalidatedConvert(capabilities.quantized8Performance));
+ const auto float32Performance = NN_TRY(unvalidatedConvert(capabilities.float32Performance));
const auto relaxedFloat32toFloat16Performance =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16Performance));
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16Performance));
auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
quantized8Performance);
@@ -73,16 +98,16 @@
};
}
-Result<Operation> convert(const hal::V1_1::Operation& operation) {
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_1::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-Result<Model> convert(const hal::V1_1::Model& model) {
- auto operations = NN_TRY(convert(model.operations));
+GeneralResult<Model> unvalidatedConvert(const hal::V1_1::Model& model) {
+ auto operations = NN_TRY(unvalidatedConvert(model.operations));
// Verify number of consumers.
const auto numberOfConsumers =
@@ -90,14 +115,14 @@
CHECK(model.operands.size() == numberOfConsumers.size());
for (size_t i = 0; i < model.operands.size(); ++i) {
if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
- return NN_ERROR() << "Invalid numberOfConsumers for operand " << i << ", expected "
- << numberOfConsumers[i] << " but found "
- << model.operands[i].numberOfConsumers;
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid numberOfConsumers for operand " << i << ", expected "
+ << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
}
}
auto main = Model::Subgraph{
- .operands = NN_TRY(convert(model.operands)),
+ .operands = NN_TRY(unvalidatedConvert(model.operands)),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
@@ -105,83 +130,114 @@
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
};
}
-Result<ExecutionPreference> convert(const hal::V1_1::ExecutionPreference& executionPreference) {
+GeneralResult<ExecutionPreference> unvalidatedConvert(
+ const hal::V1_1::ExecutionPreference& executionPreference) {
return static_cast<ExecutionPreference>(executionPreference);
}
+GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+GeneralResult<Model> convert(const hal::V1_1::Model& model) {
+ return validatedConvert(model);
+}
+
+GeneralResult<ExecutionPreference> convert(
+ const hal::V1_1::ExecutionPreference& executionPreference) {
+ return validatedConvert(executionPreference);
+}
+
} // namespace android::nn
namespace android::hardware::neuralnetworks::V1_1::utils {
namespace {
-using utils::convert;
+using utils::unvalidatedConvert;
-nn::Result<V1_0::PerformanceInfo> convert(
+nn::GeneralResult<V1_0::PerformanceInfo> unvalidatedConvert(
const nn::Capabilities::PerformanceInfo& performanceInfo) {
- return V1_0::utils::convert(performanceInfo);
+ return V1_0::utils::unvalidatedConvert(performanceInfo);
}
-nn::Result<V1_0::Operand> convert(const nn::Operand& operand) {
- return V1_0::utils::convert(operand);
+nn::GeneralResult<V1_0::Operand> unvalidatedConvert(const nn::Operand& operand) {
+ return V1_0::utils::unvalidatedConvert(operand);
}
-nn::Result<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
- return V1_0::utils::convert(operandValues);
+nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
+ const nn::Model::OperandValues& operandValues) {
+ return V1_0::utils::unvalidatedConvert(operandValues);
}
-nn::Result<hidl_memory> convert(const nn::Memory& memory) {
- return V1_0::utils::convert(memory);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+ return V1_0::utils::unvalidatedConvert(memory);
}
template <typename Input>
-using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-nn::Result<hidl_vec<convertOutput<Type>>> convert(const std::vector<Type>& arguments) {
- hidl_vec<convertOutput<Type>> halObject(arguments.size());
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
- halObject[i] = NN_TRY(convert(arguments[i]));
+ halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
}
return halObject;
}
+template <typename Type>
+decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
+ const auto maybeVersion = nn::validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return nn::error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return utils::unvalidatedConvert(canonical);
+}
+
} // anonymous namespace
-nn::Result<OperationType> convert(const nn::OperationType& operationType) {
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities) {
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
return Capabilities{
- .float32Performance = NN_TRY(convert(
+ .float32Performance = NN_TRY(unvalidatedConvert(
capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
- .quantized8Performance = NN_TRY(convert(
+ .quantized8Performance = NN_TRY(unvalidatedConvert(
capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
- .relaxedFloat32toFloat16Performance =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .relaxedFloat32toFloat16Performance = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
};
}
-nn::Result<Operation> convert(const nn::Operation& operation) {
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-nn::Result<Model> convert(const nn::Model& model) {
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
if (!hal::utils::hasNoPointerData(model)) {
- return NN_ERROR() << "Mdoel cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Mdoel cannot be unvalidatedConverted because it contains pointer-based memory";
}
- auto operands = NN_TRY(convert(model.main.operands));
+ auto operands = NN_TRY(unvalidatedConvert(model.main.operands));
// Update number of consumers.
const auto numberOfConsumers =
@@ -193,17 +249,30 @@
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(convert(model.main.operations)),
+ .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
};
}
-nn::Result<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
+nn::GeneralResult<ExecutionPreference> unvalidatedConvert(
+ const nn::ExecutionPreference& executionPreference) {
return static_cast<ExecutionPreference>(executionPreference);
}
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+ return validatedConvert(model);
+}
+
+nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
+ return validatedConvert(executionPreference);
+}
+
} // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp
new file mode 100644
index 0000000..f73d3f8
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/Device.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Device.h"
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_1::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities_1_1 failed with " << toString(status);
+ } else {
+ result = nn::convert(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities_1_1(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+ sp<V1_1::IDevice> device) {
+ if (name.empty()) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_1::utils::Device::create must have non-empty name";
+ }
+ if (device == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_1::utils::Device::create must have non-null device";
+ }
+
+ auto capabilities = NN_TRY(initCapabilities(device.get()));
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+ return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
+ std::move(capabilities), std::move(device),
+ std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
+ sp<V1_1::IDevice> device, hal::utils::DeathHandler deathHandler)
+ : kName(std::move(name)),
+ kCapabilities(std::move(capabilities)),
+ kDevice(std::move(device)),
+ kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+ return kName;
+}
+
+const std::string& Device::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+ return nn::Version::ANDROID_P;
+}
+
+nn::DeviceType Device::getType() const {
+ return nn::DeviceType::UNKNOWN;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+ return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
+}
+
+nn::GeneralResult<void> Device::wait() const {
+ const auto ret = kDevice->ping();
+ HANDLE_TRANSPORT_FAILURE(ret);
+ return {};
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+
+ nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ auto cb = [&result, &model](V1_0::ErrorStatus status,
+ const hidl_vec<bool>& supportedOperations) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical)
+ << "getSupportedOperations_1_1 failed with " << toString(status);
+ } else if (supportedOperations.size() != model.main.operations.size()) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "getSupportedOperations_1_1 returned vector of size "
+ << supportedOperations.size() << " but expected "
+ << model.main.operations.size();
+ } else {
+ result = supportedOperations;
+ }
+ };
+
+ const auto ret = kDevice->getSupportedOperations_1_1(hidlModel, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+ const auto hidlPreference = NN_TRY(convert(preference));
+
+ const auto cb = sp<V1_0::utils::PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kDevice->prepareModel_1_1(hidlModel, hidlPreference, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::prepareModelFromCache not supported on 1.1 HAL service";
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+ const nn::BufferDesc& /*desc*/,
+ const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+ const std::vector<nn::BufferRole>& /*inputRoles*/,
+ const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::allocate not supported on 1.1 HAL service";
+}
+
+} // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.1/utils/src/Service.cpp b/neuralnetworks/1.1/utils/src/Service.cpp
new file mode 100644
index 0000000..e2d3240
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/Service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+ hal::utils::ResilientDevice::Factory makeDevice =
+ [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+ auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+ if (service == nullptr) {
+ return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+ }
+ return Device::create(name, std::move(service));
+ };
+
+ return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index a1dd3d0..22e8659 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -20,6 +20,7 @@
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal/1.2/"],
export_include_dirs: ["include"],
+ cflags: ["-Wthread-safety"],
static_libs: [
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h
new file mode 100644
index 0000000..bc7d92a
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+ public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+ Return<void> notify(V1_0::ErrorStatus status,
+ const sp<V1_0::IPreparedModel>& preparedModel) override;
+ Return<void> notify_1_2(V1_0::ErrorStatus status,
+ const sp<IPreparedModel>& preparedModel) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+ Return<void> notify(V1_0::ErrorStatus status) override;
+ Return<void> notify_1_2(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
index 81bf792..5dcbc0b 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
@@ -24,62 +24,78 @@
namespace android::nn {
-Result<OperandType> convert(const hal::V1_2::OperandType& operandType);
-Result<OperationType> convert(const hal::V1_2::OperationType& operationType);
-Result<DeviceType> convert(const hal::V1_2::DeviceType& deviceType);
-Result<Capabilities> convert(const hal::V1_2::Capabilities& capabilities);
-Result<Capabilities::OperandPerformance> convert(
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_2::OperandType& operandType);
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_2::OperationType& operationType);
+GeneralResult<DeviceType> unvalidatedConvert(const hal::V1_2::DeviceType& deviceType);
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_2::Capabilities& capabilities);
+GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_2::Capabilities::OperandPerformance& operandPerformance);
-Result<Operation> convert(const hal::V1_2::Operation& operation);
-Result<Operand::SymmPerChannelQuantParams> convert(
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_2::Operation& operation);
+GeneralResult<Operand::SymmPerChannelQuantParams> unvalidatedConvert(
const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams);
-Result<Operand> convert(const hal::V1_2::Operand& operand);
-Result<Operand::ExtraParams> convert(const hal::V1_2::Operand::ExtraParams& extraParams);
-Result<Model> convert(const hal::V1_2::Model& model);
-Result<Model::ExtensionNameAndPrefix> convert(
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_2::Operand& operand);
+GeneralResult<Operand::ExtraParams> unvalidatedConvert(
+ const hal::V1_2::Operand::ExtraParams& extraParams);
+GeneralResult<Model> unvalidatedConvert(const hal::V1_2::Model& model);
+GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
-Result<OutputShape> convert(const hal::V1_2::OutputShape& outputShape);
-Result<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming);
-Result<Timing> convert(const hal::V1_2::Timing& timing);
-Result<Extension> convert(const hal::V1_2::Extension& extension);
-Result<Extension::OperandTypeInformation> convert(
+GeneralResult<OutputShape> unvalidatedConvert(const hal::V1_2::OutputShape& outputShape);
+GeneralResult<MeasureTiming> unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming);
+GeneralResult<Timing> unvalidatedConvert(const hal::V1_2::Timing& timing);
+GeneralResult<Extension> unvalidatedConvert(const hal::V1_2::Extension& extension);
+GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation);
-Result<NativeHandle> convert(const hardware::hidl_handle& handle);
+GeneralResult<SharedHandle> unvalidatedConvert(const hardware::hidl_handle& handle);
-Result<std::vector<Extension>> convert(const hardware::hidl_vec<hal::V1_2::Extension>& extensions);
-Result<std::vector<NativeHandle>> convert(const hardware::hidl_vec<hardware::hidl_handle>& handles);
-Result<std::vector<OutputShape>> convert(
+GeneralResult<DeviceType> convert(const hal::V1_2::DeviceType& deviceType);
+GeneralResult<Capabilities> convert(const hal::V1_2::Capabilities& capabilities);
+GeneralResult<Model> convert(const hal::V1_2::Model& model);
+GeneralResult<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming);
+GeneralResult<Timing> convert(const hal::V1_2::Timing& timing);
+
+GeneralResult<std::vector<Extension>> convert(
+ const hardware::hidl_vec<hal::V1_2::Extension>& extensions);
+GeneralResult<std::vector<SharedHandle>> convert(
+ const hardware::hidl_vec<hardware::hidl_handle>& handles);
+GeneralResult<std::vector<OutputShape>> convert(
const hardware::hidl_vec<hal::V1_2::OutputShape>& outputShapes);
} // namespace android::nn
namespace android::hardware::neuralnetworks::V1_2::utils {
-nn::Result<OperandType> convert(const nn::OperandType& operandType);
-nn::Result<OperationType> convert(const nn::OperationType& operationType);
-nn::Result<DeviceType> convert(const nn::DeviceType& deviceType);
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities);
-nn::Result<Capabilities::OperandPerformance> convert(
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType);
+nn::GeneralResult<DeviceType> unvalidatedConvert(const nn::DeviceType& deviceType);
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance);
-nn::Result<Operation> convert(const nn::Operation& operation);
-nn::Result<SymmPerChannelQuantParams> convert(
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation);
+nn::GeneralResult<SymmPerChannelQuantParams> unvalidatedConvert(
const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams);
-nn::Result<Operand> convert(const nn::Operand& operand);
-nn::Result<Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams);
-nn::Result<Model> convert(const nn::Model& model);
-nn::Result<Model::ExtensionNameAndPrefix> convert(
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand);
+nn::GeneralResult<Operand::ExtraParams> unvalidatedConvert(
+ const nn::Operand::ExtraParams& extraParams);
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
+nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
-nn::Result<OutputShape> convert(const nn::OutputShape& outputShape);
-nn::Result<MeasureTiming> convert(const nn::MeasureTiming& measureTiming);
-nn::Result<Timing> convert(const nn::Timing& timing);
-nn::Result<Extension> convert(const nn::Extension& extension);
-nn::Result<Extension::OperandTypeInformation> convert(
+nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
+nn::GeneralResult<MeasureTiming> unvalidatedConvert(const nn::MeasureTiming& measureTiming);
+nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing);
+nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension);
+nn::GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const nn::Extension::OperandTypeInformation& operandTypeInformation);
-nn::Result<hidl_handle> convert(const nn::NativeHandle& handle);
+nn::GeneralResult<hidl_handle> unvalidatedConvert(const nn::SharedHandle& handle);
-nn::Result<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions);
-nn::Result<hidl_vec<hidl_handle>> convert(const std::vector<nn::NativeHandle>& handles);
-nn::Result<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes);
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<MeasureTiming> convert(const nn::MeasureTiming& measureTiming);
+nn::GeneralResult<Timing> convert(const nn::Timing& timing);
+
+nn::GeneralResult<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions);
+nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles);
+nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes);
} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
new file mode 100644
index 0000000..a68830d
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device);
+nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device);
+nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device);
+nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
+ V1_2::IDevice* device);
+
+class Device final : public nn::IDevice {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+ sp<V1_2::IDevice> device);
+
+ Device(PrivateConstructorTag tag, std::string name, std::string versionString,
+ nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
+ sp<V1_2::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ const std::string kName;
+ const std::string kVersionString;
+ const nn::DeviceType kDeviceType;
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+ const sp<V1_2::IDevice> kDevice;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
new file mode 100644
index 0000000..65e1e8a
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+ sp<V1_2::IPreparedModel> preparedModel);
+
+ PreparedModel(PrivateConstructorTag tag, sp<V1_2::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler);
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+ std::any getUnderlyingResource() const override;
+
+ private:
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeSynchronously(
+ const V1_0::Request& request, MeasureTiming measure) const;
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeAsynchronously(
+ const V1_0::Request& request, MeasureTiming measure) const;
+
+ const sp<V1_2::IPreparedModel> kPreparedModel;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.h
new file mode 100644
index 0000000..44f004f
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
index b1c2f1a..70149a2 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
@@ -23,7 +23,6 @@
#include <android/hardware/neuralnetworks/1.2/types.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/1.1/Conversions.h>
@@ -34,14 +33,12 @@
constexpr auto kDefaultMesaureTiming = MeasureTiming::NO;
constexpr auto kNoTiming = Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
.timeInDriver = std::numeric_limits<uint64_t>::max()};
-constexpr auto kVersion = nn::Version::ANDROID_Q;
template <typename Type>
nn::Result<void> validate(const Type& halObject) {
- const auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
+ const auto maybeCanonical = nn::convert(halObject);
+ if (!maybeCanonical.has_value()) {
+ return nn::error() << maybeCanonical.error().message;
}
return {};
}
@@ -55,16 +52,6 @@
return result.has_value();
}
-template <typename Type>
-decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
- auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
- }
- return canonical;
-}
-
} // namespace android::hardware::neuralnetworks::V1_2::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H
diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..39f88c2
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/PreparedModel.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<IPreparedModel>& preparedModel) {
+ return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResultsHelper(const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResults(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+ return hal::utils::makeExecutionFailure(
+ convertExecutionGeneralResultsHelper(outputShapes, timing));
+}
+
+} // namespace
+
+Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
+ const sp<IPreparedModel>& preparedModel) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+ return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal({});
+ }
+ return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+ }
+ return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+ return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index fed314b..f11474f 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -24,8 +24,10 @@
#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
#include <algorithm>
#include <functional>
@@ -41,6 +43,8 @@
return static_cast<std::underlying_type_t<Type>>(value);
}
+constexpr auto kVersion = android::nn::Version::ANDROID_Q;
+
} // namespace
namespace android::nn {
@@ -75,57 +79,86 @@
using hardware::hidl_vec;
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-Result<std::vector<ConvertOutput<Type>>> convertVec(const hidl_vec<Type>& arguments) {
- std::vector<ConvertOutput<Type>> canonical;
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
- canonical.push_back(NN_TRY(nn::convert(argument)));
+ canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
}
return canonical;
}
template <typename Type>
-Result<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
- return convertVec(arguments);
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const hidl_vec<Type>& arguments) {
+ return unvalidatedConvertVec(arguments);
+}
+
+template <typename Type>
+decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+ auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
+ const auto maybeVersion = validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return canonical;
+}
+
+template <typename Type>
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> validatedConvert(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
+ canonical.reserve(arguments.size());
+ for (const auto& argument : arguments) {
+ canonical.push_back(NN_TRY(validatedConvert(argument)));
+ }
+ return canonical;
}
} // anonymous namespace
-Result<OperandType> convert(const hal::V1_2::OperandType& operandType) {
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_2::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-Result<OperationType> convert(const hal::V1_2::OperationType& operationType) {
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_2::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-Result<DeviceType> convert(const hal::V1_2::DeviceType& deviceType) {
+GeneralResult<DeviceType> unvalidatedConvert(const hal::V1_2::DeviceType& deviceType) {
return static_cast<DeviceType>(deviceType);
}
-Result<Capabilities> convert(const hal::V1_2::Capabilities& capabilities) {
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_2::Capabilities& capabilities) {
const bool validOperandTypes = std::all_of(
capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
[](const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
- const auto maybeType = convert(operandPerformance.type);
+ const auto maybeType = unvalidatedConvert(operandPerformance.type);
return !maybeType.has_value() ? false : validOperandType(maybeType.value());
});
if (!validOperandTypes) {
- return NN_ERROR()
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
<< "Invalid OperandType when converting OperandPerformance in Capabilities";
}
const auto relaxedFloat32toFloat16PerformanceScalar =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
const auto relaxedFloat32toFloat16PerformanceTensor =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
- auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance));
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
- auto table =
- NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
+ auto table = NN_TRY(hal::utils::makeGeneralFailure(
+ Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
+ nn::ErrorStatus::GENERAL_FAILURE));
return Capabilities{
.relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
@@ -134,23 +167,23 @@
};
}
-Result<Capabilities::OperandPerformance> convert(
+GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
return Capabilities::OperandPerformance{
- .type = NN_TRY(convert(operandPerformance.type)),
- .info = NN_TRY(convert(operandPerformance.info)),
+ .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
+ .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
};
}
-Result<Operation> convert(const hal::V1_2::Operation& operation) {
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_2::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-Result<Operand::SymmPerChannelQuantParams> convert(
+GeneralResult<Operand::SymmPerChannelQuantParams> unvalidatedConvert(
const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
return Operand::SymmPerChannelQuantParams{
.scales = symmPerChannelQuantParams.scales,
@@ -158,34 +191,36 @@
};
}
-Result<Operand> convert(const hal::V1_2::Operand& operand) {
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_2::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
- .extraParams = NN_TRY(convert(operand.extraParams)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
};
}
-Result<Operand::ExtraParams> convert(const hal::V1_2::Operand::ExtraParams& extraParams) {
+GeneralResult<Operand::ExtraParams> unvalidatedConvert(
+ const hal::V1_2::Operand::ExtraParams& extraParams) {
using Discriminator = hal::V1_2::Operand::ExtraParams::hidl_discriminator;
switch (extraParams.getDiscriminator()) {
case Discriminator::none:
return Operand::NoParams{};
case Discriminator::channelQuant:
- return convert(extraParams.channelQuant());
+ return unvalidatedConvert(extraParams.channelQuant());
case Discriminator::extension:
return extraParams.extension();
}
- return NN_ERROR() << "Unrecognized Operand::ExtraParams discriminator: "
- << underlyingType(extraParams.getDiscriminator());
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Unrecognized Operand::ExtraParams discriminator: "
+ << underlyingType(extraParams.getDiscriminator());
}
-Result<Model> convert(const hal::V1_2::Model& model) {
- auto operations = NN_TRY(convert(model.operations));
+GeneralResult<Model> unvalidatedConvert(const hal::V1_2::Model& model) {
+ auto operations = NN_TRY(unvalidatedConvert(model.operations));
// Verify number of consumers.
const auto numberOfConsumers =
@@ -193,14 +228,14 @@
CHECK(model.operands.size() == numberOfConsumers.size());
for (size_t i = 0; i < model.operands.size(); ++i) {
if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
- return NN_ERROR() << "Invalid numberOfConsumers for operand " << i << ", expected "
- << numberOfConsumers[i] << " but found "
- << model.operands[i].numberOfConsumers;
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid numberOfConsumers for operand " << i << ", expected "
+ << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
}
}
auto main = Model::Subgraph{
- .operands = NN_TRY(convert(model.operands)),
+ .operands = NN_TRY(unvalidatedConvert(model.operands)),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
@@ -208,14 +243,14 @@
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
};
}
-Result<Model::ExtensionNameAndPrefix> convert(
+GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
return Model::ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
@@ -223,29 +258,29 @@
};
}
-Result<OutputShape> convert(const hal::V1_2::OutputShape& outputShape) {
+GeneralResult<OutputShape> unvalidatedConvert(const hal::V1_2::OutputShape& outputShape) {
return OutputShape{
.dimensions = outputShape.dimensions,
.isSufficient = outputShape.isSufficient,
};
}
-Result<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming) {
+GeneralResult<MeasureTiming> unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming) {
return static_cast<MeasureTiming>(measureTiming);
}
-Result<Timing> convert(const hal::V1_2::Timing& timing) {
+GeneralResult<Timing> unvalidatedConvert(const hal::V1_2::Timing& timing) {
return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver};
}
-Result<Extension> convert(const hal::V1_2::Extension& extension) {
+GeneralResult<Extension> unvalidatedConvert(const hal::V1_2::Extension& extension) {
return Extension{
.name = extension.name,
- .operandTypes = NN_TRY(convert(extension.operandTypes)),
+ .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
};
}
-Result<Extension::OperandTypeInformation> convert(
+GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation) {
return Extension::OperandTypeInformation{
.type = operandTypeInformation.type,
@@ -254,21 +289,41 @@
};
}
-Result<NativeHandle> convert(const hidl_handle& handle) {
- auto* cloned = native_handle_clone(handle.getNativeHandle());
- return ::android::NativeHandle::create(cloned, /*ownsHandle=*/true);
+GeneralResult<SharedHandle> unvalidatedConvert(const hidl_handle& hidlHandle) {
+ return hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle());
}
-Result<std::vector<Extension>> convert(const hidl_vec<hal::V1_2::Extension>& extensions) {
- return convertVec(extensions);
+GeneralResult<DeviceType> convert(const hal::V1_2::DeviceType& deviceType) {
+ return validatedConvert(deviceType);
}
-Result<std::vector<NativeHandle>> convert(const hidl_vec<hidl_handle>& handles) {
- return convertVec(handles);
+GeneralResult<Capabilities> convert(const hal::V1_2::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
}
-Result<std::vector<OutputShape>> convert(const hidl_vec<hal::V1_2::OutputShape>& outputShapes) {
- return convertVec(outputShapes);
+GeneralResult<Model> convert(const hal::V1_2::Model& model) {
+ return validatedConvert(model);
+}
+
+GeneralResult<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming) {
+ return validatedConvert(measureTiming);
+}
+
+GeneralResult<Timing> convert(const hal::V1_2::Timing& timing) {
+ return validatedConvert(timing);
+}
+
+GeneralResult<std::vector<Extension>> convert(const hidl_vec<hal::V1_2::Extension>& extensions) {
+ return validatedConvert(extensions);
+}
+
+GeneralResult<std::vector<SharedHandle>> convert(const hidl_vec<hidl_handle>& handles) {
+ return validatedConvert(handles);
+}
+
+GeneralResult<std::vector<OutputShape>> convert(
+ const hidl_vec<hal::V1_2::OutputShape>& outputShapes) {
+ return validatedConvert(outputShapes);
}
} // namespace android::nn
@@ -276,87 +331,116 @@
namespace android::hardware::neuralnetworks::V1_2::utils {
namespace {
-using utils::convert;
+using utils::unvalidatedConvert;
-nn::Result<V1_0::OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
- return V1_0::utils::convert(lifetime);
+nn::GeneralResult<V1_0::OperandLifeTime> unvalidatedConvert(const nn::Operand::LifeTime& lifetime) {
+ return V1_0::utils::unvalidatedConvert(lifetime);
}
-nn::Result<V1_0::PerformanceInfo> convert(
+nn::GeneralResult<V1_0::PerformanceInfo> unvalidatedConvert(
const nn::Capabilities::PerformanceInfo& performanceInfo) {
- return V1_0::utils::convert(performanceInfo);
+ return V1_0::utils::unvalidatedConvert(performanceInfo);
}
-nn::Result<V1_0::DataLocation> convert(const nn::DataLocation& location) {
- return V1_0::utils::convert(location);
+nn::GeneralResult<V1_0::DataLocation> unvalidatedConvert(const nn::DataLocation& location) {
+ return V1_0::utils::unvalidatedConvert(location);
}
-nn::Result<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
- return V1_0::utils::convert(operandValues);
+nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
+ const nn::Model::OperandValues& operandValues) {
+ return V1_0::utils::unvalidatedConvert(operandValues);
}
-nn::Result<hidl_memory> convert(const nn::Memory& memory) {
- return V1_0::utils::convert(memory);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+ return V1_0::utils::unvalidatedConvert(memory);
}
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-nn::Result<hidl_vec<ConvertOutput<Type>>> convertVec(const std::vector<Type>& arguments) {
- hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
- halObject[i] = NN_TRY(convert(arguments[i]));
+ halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
}
return halObject;
}
template <typename Type>
-nn::Result<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
- return convertVec(arguments);
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const std::vector<Type>& arguments) {
+ return unvalidatedConvertVec(arguments);
}
-nn::Result<Operand::ExtraParams> makeExtraParams(nn::Operand::NoParams /*noParams*/) {
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(nn::Operand::NoParams /*noParams*/) {
return Operand::ExtraParams{};
}
-nn::Result<Operand::ExtraParams> makeExtraParams(
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(
const nn::Operand::SymmPerChannelQuantParams& channelQuant) {
Operand::ExtraParams ret;
- ret.channelQuant(NN_TRY(convert(channelQuant)));
+ ret.channelQuant(NN_TRY(unvalidatedConvert(channelQuant)));
return ret;
}
-nn::Result<Operand::ExtraParams> makeExtraParams(const nn::Operand::ExtensionParams& extension) {
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(
+ const nn::Operand::ExtensionParams& extension) {
Operand::ExtraParams ret;
ret.extension(extension);
return ret;
}
+template <typename Type>
+decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
+ const auto maybeVersion = nn::validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return nn::error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return utils::unvalidatedConvert(canonical);
+}
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> validatedConvert(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ halObject[i] = NN_TRY(validatedConvert(arguments[i]));
+ }
+ return halObject;
+}
+
} // anonymous namespace
-nn::Result<OperandType> convert(const nn::OperandType& operandType) {
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-nn::Result<OperationType> convert(const nn::OperationType& operationType) {
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-nn::Result<DeviceType> convert(const nn::DeviceType& deviceType) {
+nn::GeneralResult<DeviceType> unvalidatedConvert(const nn::DeviceType& deviceType) {
switch (deviceType) {
case nn::DeviceType::UNKNOWN:
- return NN_ERROR() << "Invalid DeviceType UNKNOWN";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Invalid DeviceType UNKNOWN";
case nn::DeviceType::OTHER:
case nn::DeviceType::CPU:
case nn::DeviceType::GPU:
case nn::DeviceType::ACCELERATOR:
return static_cast<DeviceType>(deviceType);
}
- return NN_ERROR() << "Invalid DeviceType " << underlyingType(deviceType);
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid DeviceType " << underlyingType(deviceType);
}
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities) {
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
std::copy_if(capabilities.operandPerformance.asVector().begin(),
@@ -367,31 +451,31 @@
});
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
- .operandPerformance = NN_TRY(convert(operandPerformance)),
+ .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+ .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)),
};
}
-nn::Result<Capabilities::OperandPerformance> convert(
+nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance) {
return Capabilities::OperandPerformance{
- .type = NN_TRY(convert(operandPerformance.type)),
- .info = NN_TRY(convert(operandPerformance.info)),
+ .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
+ .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
};
}
-nn::Result<Operation> convert(const nn::Operation& operation) {
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-nn::Result<SymmPerChannelQuantParams> convert(
+nn::GeneralResult<SymmPerChannelQuantParams> unvalidatedConvert(
const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
return SymmPerChannelQuantParams{
.scales = symmPerChannelQuantParams.scales,
@@ -399,29 +483,31 @@
};
}
-nn::Result<Operand> convert(const nn::Operand& operand) {
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
- .extraParams = NN_TRY(convert(operand.extraParams)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
};
}
-nn::Result<Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams) {
+nn::GeneralResult<Operand::ExtraParams> unvalidatedConvert(
+ const nn::Operand::ExtraParams& extraParams) {
return std::visit([](const auto& x) { return makeExtraParams(x); }, extraParams);
}
-nn::Result<Model> convert(const nn::Model& model) {
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
if (!hal::utils::hasNoPointerData(model)) {
- return NN_ERROR() << "Model cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
- auto operands = NN_TRY(convert(model.main.operands));
+ auto operands = NN_TRY(unvalidatedConvert(model.main.operands));
// Update number of consumers.
const auto numberOfConsumers =
@@ -433,17 +519,17 @@
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(convert(model.main.operations)),
+ .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
};
}
-nn::Result<Model::ExtensionNameAndPrefix> convert(
+nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
return Model::ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
@@ -451,27 +537,27 @@
};
}
-nn::Result<OutputShape> convert(const nn::OutputShape& outputShape) {
+nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape) {
return OutputShape{.dimensions = outputShape.dimensions,
.isSufficient = outputShape.isSufficient};
}
-nn::Result<MeasureTiming> convert(const nn::MeasureTiming& measureTiming) {
+nn::GeneralResult<MeasureTiming> unvalidatedConvert(const nn::MeasureTiming& measureTiming) {
return static_cast<MeasureTiming>(measureTiming);
}
-nn::Result<Timing> convert(const nn::Timing& timing) {
+nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver};
}
-nn::Result<Extension> convert(const nn::Extension& extension) {
+nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension) {
return Extension{
.name = extension.name,
- .operandTypes = NN_TRY(convert(extension.operandTypes)),
+ .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
};
}
-nn::Result<Extension::OperandTypeInformation> convert(
+nn::GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const nn::Extension::OperandTypeInformation& operandTypeInformation) {
return Extension::OperandTypeInformation{
.type = operandTypeInformation.type,
@@ -480,23 +566,40 @@
};
}
-nn::Result<hidl_handle> convert(const nn::NativeHandle& handle) {
- const auto hidlHandle = hidl_handle(handle->handle());
- // Copy memory to force the native_handle_t to be copied.
- auto copiedHandle = hidlHandle;
- return copiedHandle;
+nn::GeneralResult<hidl_handle> unvalidatedConvert(const nn::SharedHandle& handle) {
+ return hal::utils::hidlHandleFromSharedHandle(handle);
}
-nn::Result<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions) {
- return convertVec(extensions);
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType) {
+ return validatedConvert(deviceType);
}
-nn::Result<hidl_vec<hidl_handle>> convert(const std::vector<nn::NativeHandle>& handles) {
- return convertVec(handles);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
}
-nn::Result<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes) {
- return convertVec(outputShapes);
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+ return validatedConvert(model);
+}
+
+nn::GeneralResult<MeasureTiming> convert(const nn::MeasureTiming& measureTiming) {
+ return validatedConvert(measureTiming);
+}
+
+nn::GeneralResult<Timing> convert(const nn::Timing& timing) {
+ return validatedConvert(timing);
+}
+
+nn::GeneralResult<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions) {
+ return validatedConvert(extensions);
+}
+
+nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles) {
+ return validatedConvert(handles);
+}
+
+nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes) {
+ return validatedConvert(outputShapes);
}
} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
new file mode 100644
index 0000000..0061065
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Device.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status);
+ } else {
+ result = nn::convert(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities_1_2(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+} // namespace
+
+nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<std::string> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const hidl_string& versionString) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getVersionString failed with " << toString(status);
+ } else {
+ result = versionString;
+ }
+ };
+
+ const auto ret = device->getVersionString(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::DeviceType> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, DeviceType deviceType) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getDeviceType failed with " << toString(status);
+ } else {
+ result = nn::convert(deviceType);
+ }
+ };
+
+ const auto ret = device->getType(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<std::vector<nn::Extension>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<Extension>& extensions) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getExtensions failed with " << toString(status);
+ } else {
+ result = nn::convert(extensions);
+ }
+ };
+
+ const auto ret = device->getSupportedExtensions(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
+ V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<std::pair<uint32_t, uint32_t>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, uint32_t numModelCache,
+ uint32_t numDataCache) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical)
+ << "getNumberOfCacheFilesNeeded failed with " << toString(status);
+ } else {
+ result = std::make_pair(numModelCache, numDataCache);
+ }
+ };
+
+ const auto ret = device->getNumberOfCacheFilesNeeded(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+ sp<V1_2::IDevice> device) {
+ if (name.empty()) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_2::utils::Device::create must have non-empty name";
+ }
+ if (device == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_2::utils::Device::create must have non-null device";
+ }
+
+ auto versionString = NN_TRY(initVersionString(device.get()));
+ const auto deviceType = NN_TRY(initDeviceType(device.get()));
+ auto extensions = NN_TRY(initExtensions(device.get()));
+ auto capabilities = NN_TRY(initCapabilities(device.get()));
+ const auto numberOfCacheFilesNeeded = NN_TRY(initNumberOfCacheFilesNeeded(device.get()));
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+ return std::make_shared<const Device>(
+ PrivateConstructorTag{}, std::move(name), std::move(versionString), deviceType,
+ std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
+ std::move(device), std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, std::string versionString,
+ nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities,
+ std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, sp<V1_2::IDevice> device,
+ hal::utils::DeathHandler deathHandler)
+ : kName(std::move(name)),
+ kVersionString(std::move(versionString)),
+ kDeviceType(deviceType),
+ kExtensions(std::move(extensions)),
+ kCapabilities(std::move(capabilities)),
+ kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded),
+ kDevice(std::move(device)),
+ kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+ return kName;
+}
+
+const std::string& Device::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+ return nn::Version::ANDROID_Q;
+}
+
+nn::DeviceType Device::getType() const {
+ return kDeviceType;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+ return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> Device::wait() const {
+ const auto ret = kDevice->ping();
+ HANDLE_TRANSPORT_FAILURE(ret);
+ return {};
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+
+ nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ auto cb = [&result, &model](V1_0::ErrorStatus status,
+ const hidl_vec<bool>& supportedOperations) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical)
+ << "getSupportedOperations_1_2 failed with " << toString(status);
+ } else if (supportedOperations.size() != model.main.operations.size()) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "getSupportedOperations_1_2 returned vector of size "
+ << supportedOperations.size() << " but expected "
+ << model.main.operations.size();
+ } else {
+ result = supportedOperations;
+ }
+ };
+
+ const auto ret = kDevice->getSupportedOperations_1_2(hidlModel, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+ const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
+ const auto hidlModelCache = NN_TRY(convert(modelCache));
+ const auto hidlDataCache = NN_TRY(convert(dataCache));
+ const auto hidlToken = token;
+
+ const auto cb = sp<PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kDevice->prepareModel_1_2(hidlModel, hidlPreference, hidlModelCache,
+ hidlDataCache, hidlToken, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModel_1_2 failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const auto hidlModelCache = NN_TRY(convert(modelCache));
+ const auto hidlDataCache = NN_TRY(convert(dataCache));
+ const auto hidlToken = token;
+
+ const auto cb = sp<PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kDevice->prepareModelFromCache(hidlModelCache, hidlDataCache, hidlToken, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModelFromCache failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+ const nn::BufferDesc& /*desc*/,
+ const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+ const std::vector<nn::BufferRole>& /*inputRoles*/,
+ const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::allocate not supported on 1.2 HAL service";
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..dad9a7e
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionResultsHelper(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+ return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
+ const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+ return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+ sp<V1_2::IPreparedModel> preparedModel) {
+ if (preparedModel == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_2::utils::PreparedModel::create must have non-null preparedModel";
+ }
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+ return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+ std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_2::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler)
+ : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeSynchronously(const V1_0::Request& request, MeasureTiming measure) const {
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
+ } else {
+ result = convertExecutionResults(outputShapes, timing);
+ }
+ };
+
+ const auto ret = kPreparedModel->executeSynchronously(request, measure, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeAsynchronously(const V1_0::Request& request, MeasureTiming measure) const {
+ const auto cb = sp<ExecutionCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kPreparedModel->execute_1_2(request, measure, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "execute failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+ const auto hidlRequest =
+ NN_TRY(hal::utils::makeExecutionFailure(V1_0::utils::convert(requestInShared)));
+ const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const bool preferSynchronous = true;
+
+ // Execute synchronously if allowed.
+ if (preferSynchronous) {
+ result = executeSynchronously(hidlRequest, hidlMeasure);
+ }
+
+ // Run asymchronous execution if execution has not already completed.
+ if (!result.has_value()) {
+ result = executeAsynchronously(hidlRequest, hidlMeasure);
+ }
+
+ // Flush output buffers if suxcessful execution.
+ if (result.has_value()) {
+ NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+ }
+
+ return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+ const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+ nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+ const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IPreparedModel::executeFenced is not supported on 1.2 HAL service";
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+ sp<V1_0::IPreparedModel> resource = kPreparedModel;
+ return resource;
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Service.cpp b/neuralnetworks/1.2/utils/src/Service.cpp
new file mode 100644
index 0000000..110188f
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+ hal::utils::ResilientDevice::Factory makeDevice =
+ [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+ auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+ if (service == nullptr) {
+ return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+ }
+ return Device::create(name, std::move(service));
+ };
+
+ return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index 279b250..d5d897d 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -20,6 +20,7 @@
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal/1.3/"],
export_include_dirs: ["include"],
+ cflags: ["-Wthread-safety"],
static_libs: [
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
new file mode 100644
index 0000000..637179d
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
+
+#include <android/hardware/neuralnetworks/1.3/IBuffer.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <memory>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class Buffer final : public nn::IBuffer {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Buffer>> create(
+ sp<V1_3::IBuffer> buffer, nn::Request::MemoryDomainToken token);
+
+ Buffer(PrivateConstructorTag tag, sp<V1_3::IBuffer> buffer,
+ nn::Request::MemoryDomainToken token);
+
+ nn::Request::MemoryDomainToken getToken() const override;
+
+ nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+ nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ const nn::Dimensions& dimensions) const override;
+
+ private:
+ const sp<V1_3::IBuffer> kBuffer;
+ const nn::Request::MemoryDomainToken kToken;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h
new file mode 100644
index 0000000..d46b111
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+ public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+ Return<void> notify(V1_0::ErrorStatus status,
+ const sp<V1_0::IPreparedModel>& preparedModel) override;
+ Return<void> notify_1_2(V1_0::ErrorStatus status,
+ const sp<V1_2::IPreparedModel>& preparedModel) override;
+ Return<void> notify_1_3(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+ public:
+ using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+ Return<void> notify(V1_0::ErrorStatus status) override;
+ Return<void> notify_1_2(V1_0::ErrorStatus status,
+ const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) override;
+ Return<void> notify_1_3(ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) override;
+
+ void notifyAsDeadObject() override;
+
+ Data get();
+
+ private:
+ void notifyInternal(Data result);
+
+ hal::utils::TransferValue<Data> mData;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
index 43987a9..9653a05 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
@@ -25,54 +25,83 @@
namespace android::nn {
-Result<OperandType> convert(const hal::V1_3::OperandType& operandType);
-Result<OperationType> convert(const hal::V1_3::OperationType& operationType);
-Result<Priority> convert(const hal::V1_3::Priority& priority);
-Result<Capabilities> convert(const hal::V1_3::Capabilities& capabilities);
-Result<Capabilities::OperandPerformance> convert(
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_3::OperandType& operandType);
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_3::OperationType& operationType);
+GeneralResult<Priority> unvalidatedConvert(const hal::V1_3::Priority& priority);
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_3::Capabilities& capabilities);
+GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_3::Capabilities::OperandPerformance& operandPerformance);
-Result<Operation> convert(const hal::V1_3::Operation& operation);
-Result<Operand::LifeTime> convert(const hal::V1_3::OperandLifeTime& operandLifeTime);
-Result<Operand> convert(const hal::V1_3::Operand& operand);
-Result<Model> convert(const hal::V1_3::Model& model);
-Result<Model::Subgraph> convert(const hal::V1_3::Subgraph& subgraph);
-Result<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc);
-Result<BufferRole> convert(const hal::V1_3::BufferRole& bufferRole);
-Result<Request> convert(const hal::V1_3::Request& request);
-Result<Request::MemoryPool> convert(const hal::V1_3::Request::MemoryPool& memoryPool);
-Result<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint);
-Result<OptionalTimeoutDuration> convert(
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_3::Operation& operation);
+GeneralResult<Operand::LifeTime> unvalidatedConvert(
+ const hal::V1_3::OperandLifeTime& operandLifeTime);
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_3::Operand& operand);
+GeneralResult<Model> unvalidatedConvert(const hal::V1_3::Model& model);
+GeneralResult<Model::Subgraph> unvalidatedConvert(const hal::V1_3::Subgraph& subgraph);
+GeneralResult<BufferDesc> unvalidatedConvert(const hal::V1_3::BufferDesc& bufferDesc);
+GeneralResult<BufferRole> unvalidatedConvert(const hal::V1_3::BufferRole& bufferRole);
+GeneralResult<Request> unvalidatedConvert(const hal::V1_3::Request& request);
+GeneralResult<Request::MemoryPool> unvalidatedConvert(
+ const hal::V1_3::Request::MemoryPool& memoryPool);
+GeneralResult<OptionalTimePoint> unvalidatedConvert(
+ const hal::V1_3::OptionalTimePoint& optionalTimePoint);
+GeneralResult<OptionalTimeoutDuration> unvalidatedConvert(
const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration);
-Result<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus);
+GeneralResult<ErrorStatus> unvalidatedConvert(const hal::V1_3::ErrorStatus& errorStatus);
-Result<std::vector<BufferRole>> convert(
+GeneralResult<Priority> convert(const hal::V1_3::Priority& priority);
+GeneralResult<Capabilities> convert(const hal::V1_3::Capabilities& capabilities);
+GeneralResult<Model> convert(const hal::V1_3::Model& model);
+GeneralResult<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc);
+GeneralResult<Request> convert(const hal::V1_3::Request& request);
+GeneralResult<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint);
+GeneralResult<OptionalTimeoutDuration> convert(
+ const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration);
+GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus);
+
+GeneralResult<SharedHandle> convert(const hardware::hidl_handle& handle);
+GeneralResult<Memory> convert(const hardware::hidl_memory& memory);
+GeneralResult<std::vector<BufferRole>> convert(
const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles);
} // namespace android::nn
namespace android::hardware::neuralnetworks::V1_3::utils {
-nn::Result<OperandType> convert(const nn::OperandType& operandType);
-nn::Result<OperationType> convert(const nn::OperationType& operationType);
-nn::Result<Priority> convert(const nn::Priority& priority);
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities);
-nn::Result<Capabilities::OperandPerformance> convert(
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType);
+nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority);
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance);
-nn::Result<Operation> convert(const nn::Operation& operation);
-nn::Result<OperandLifeTime> convert(const nn::Operand::LifeTime& operandLifeTime);
-nn::Result<Operand> convert(const nn::Operand& operand);
-nn::Result<Model> convert(const nn::Model& model);
-nn::Result<Subgraph> convert(const nn::Model::Subgraph& subgraph);
-nn::Result<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
-nn::Result<BufferRole> convert(const nn::BufferRole& bufferRole);
-nn::Result<Request> convert(const nn::Request& request);
-nn::Result<Request::MemoryPool> convert(const nn::Request::MemoryPool& memoryPool);
-nn::Result<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint);
-nn::Result<OptionalTimeoutDuration> convert(
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation);
+nn::GeneralResult<OperandLifeTime> unvalidatedConvert(const nn::Operand::LifeTime& operandLifeTime);
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand);
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
+nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph);
+nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc);
+nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole);
+nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request);
+nn::GeneralResult<Request::MemoryPool> unvalidatedConvert(
+ const nn::Request::MemoryPool& memoryPool);
+nn::GeneralResult<OptionalTimePoint> unvalidatedConvert(
+ const nn::OptionalTimePoint& optionalTimePoint);
+nn::GeneralResult<OptionalTimeoutDuration> unvalidatedConvert(
const nn::OptionalTimeoutDuration& optionalTimeoutDuration);
-nn::Result<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
+nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus);
-nn::Result<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
+nn::GeneralResult<Priority> convert(const nn::Priority& priority);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
+nn::GeneralResult<Request> convert(const nn::Request& request);
+nn::GeneralResult<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint);
+nn::GeneralResult<OptionalTimeoutDuration> convert(
+ const nn::OptionalTimeoutDuration& optionalTimeoutDuration);
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
+
+nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle);
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory);
+nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
new file mode 100644
index 0000000..0f5234b
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class Device final : public nn::IDevice {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+ sp<V1_3::IDevice> device);
+
+ Device(PrivateConstructorTag tag, std::string name, std::string versionString,
+ nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
+ sp<V1_3::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ const std::string kName;
+ const std::string kVersionString;
+ const nn::DeviceType kDeviceType;
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+ const sp<V1_3::IDevice> kDevice;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
new file mode 100644
index 0000000..e0d69dd
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+ sp<V1_3::IPreparedModel> preparedModel);
+
+ PreparedModel(PrivateConstructorTag tag, sp<V1_3::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler);
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+ std::any getUnderlyingResource() const override;
+
+ private:
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeSynchronously(
+ const Request& request, V1_2::MeasureTiming measure, const OptionalTimePoint& deadline,
+ const OptionalTimeoutDuration& loopTimeoutDuration) const;
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeAsynchronously(
+ const Request& request, V1_2::MeasureTiming measure, const OptionalTimePoint& deadline,
+ const OptionalTimeoutDuration& loopTimeoutDuration) const;
+
+ const sp<V1_3::IPreparedModel> kPreparedModel;
+ const hal::utils::DeathHandler kDeathHandler;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.h
new file mode 100644
index 0000000..2bc3257
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
index f8c975d..29b0c80 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
@@ -23,7 +23,6 @@
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/1.1/Conversions.h>
#include <nnapi/hal/1.2/Conversions.h>
@@ -31,14 +30,12 @@
namespace android::hardware::neuralnetworks::V1_3::utils {
constexpr auto kDefaultPriority = Priority::MEDIUM;
-constexpr auto kVersion = nn::Version::ANDROID_R;
template <typename Type>
nn::Result<void> validate(const Type& halObject) {
- const auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
+ const auto maybeCanonical = nn::convert(halObject);
+ if (!maybeCanonical.has_value()) {
+ return nn::error() << maybeCanonical.error().message;
}
return {};
}
@@ -52,16 +49,6 @@
return result.has_value();
}
-template <typename Type>
-decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
- auto canonical = NN_TRY(nn::convert(halObject));
- const auto version = NN_TRY(nn::validate(canonical));
- if (version > utils::kVersion) {
- return NN_ERROR() << "";
- }
- return canonical;
-}
-
} // namespace android::hardware::neuralnetworks::V1_3::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H
diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp
new file mode 100644
index 0000000..ffdeccd
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Buffer.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Buffer.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IBuffer.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/HandleError.h>
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <memory>
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<std::shared_ptr<const Buffer>> Buffer::create(
+ sp<V1_3::IBuffer> buffer, nn::Request::MemoryDomainToken token) {
+ if (buffer == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_3::utils::Buffer::create must have non-null buffer";
+ }
+ if (token == static_cast<nn::Request::MemoryDomainToken>(0)) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_3::utils::Buffer::create must have non-zero token";
+ }
+
+ return std::make_shared<const Buffer>(PrivateConstructorTag{}, std::move(buffer), token);
+}
+
+Buffer::Buffer(PrivateConstructorTag /*tag*/, sp<V1_3::IBuffer> buffer,
+ nn::Request::MemoryDomainToken token)
+ : kBuffer(std::move(buffer)), kToken(token) {
+ CHECK(kBuffer != nullptr);
+ CHECK(kToken != static_cast<nn::Request::MemoryDomainToken>(0));
+}
+
+nn::Request::MemoryDomainToken Buffer::getToken() const {
+ return kToken;
+}
+
+nn::GeneralResult<void> Buffer::copyTo(const nn::Memory& dst) const {
+ const auto hidlDst = NN_TRY(convert(dst));
+
+ const auto ret = kBuffer->copyTo(hidlDst);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "IBuffer::copyTo failed with " << toString(status);
+ }
+
+ return {};
+}
+
+nn::GeneralResult<void> Buffer::copyFrom(const nn::Memory& src,
+ const nn::Dimensions& dimensions) const {
+ const auto hidlSrc = NN_TRY(convert(src));
+ const auto hidlDimensions = hidl_vec<uint32_t>(dimensions);
+
+ const auto ret = kBuffer->copyFrom(hidlSrc, hidlDimensions);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "IBuffer::copyFrom failed with " << toString(status);
+ }
+
+ return {};
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..e3c6074
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/PreparedModel.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/PreparedModel.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<V1_2::IPreparedModel>& preparedModel) {
+ return NN_TRY(V1_2::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+ const sp<IPreparedModel>& preparedModel) {
+ return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResults(const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ return hal::utils::makeExecutionFailure(
+ convertExecutionGeneralResultsHelper(outputShapes, timing));
+}
+
+} // namespace
+
+Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
+ const sp<V1_2::IPreparedModel>& preparedModel) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_3(ErrorStatus status,
+ const sp<IPreparedModel>& preparedModel) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+ } else if (preparedModel == nullptr) {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Returned preparedModel is nullptr");
+ } else {
+ notifyInternal(convertPreparedModel(preparedModel));
+ }
+ return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+ return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal({});
+ }
+ return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
+ const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+ }
+ return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_3(ErrorStatus status,
+ const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+ } else {
+ notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+ }
+ return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+ notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+ return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+ mData.put(std::move(result));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 4c54e3b..949dd0d 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -24,9 +24,11 @@
#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/1.2/Conversions.h>
#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
#include <algorithm>
#include <chrono>
@@ -43,6 +45,8 @@
return static_cast<std::underlying_type_t<Type>>(value);
}
+constexpr auto kVersion = android::nn::Version::ANDROID_R;
+
} // namespace
namespace android::nn {
@@ -76,109 +80,140 @@
using hardware::hidl_vec;
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-Result<std::vector<ConvertOutput<Type>>> convertVec(const hidl_vec<Type>& arguments) {
- std::vector<ConvertOutput<Type>> canonical;
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
- canonical.push_back(NN_TRY(nn::convert(argument)));
+ canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
}
return canonical;
}
template <typename Type>
-Result<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
- return convertVec(arguments);
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const hidl_vec<Type>& arguments) {
+ return unvalidatedConvertVec(arguments);
+}
+
+template <typename Type>
+decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+ auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
+ const auto maybeVersion = validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return canonical;
+}
+
+template <typename Type>
+GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> validatedConvert(
+ const hidl_vec<Type>& arguments) {
+ std::vector<unvalidatedConvertOutput<Type>> canonical;
+ canonical.reserve(arguments.size());
+ for (const auto& argument : arguments) {
+ canonical.push_back(NN_TRY(validatedConvert(argument)));
+ }
+ return canonical;
}
} // anonymous namespace
-Result<OperandType> convert(const hal::V1_3::OperandType& operandType) {
+GeneralResult<OperandType> unvalidatedConvert(const hal::V1_3::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-Result<OperationType> convert(const hal::V1_3::OperationType& operationType) {
+GeneralResult<OperationType> unvalidatedConvert(const hal::V1_3::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-Result<Priority> convert(const hal::V1_3::Priority& priority) {
+GeneralResult<Priority> unvalidatedConvert(const hal::V1_3::Priority& priority) {
return static_cast<Priority>(priority);
}
-Result<Capabilities> convert(const hal::V1_3::Capabilities& capabilities) {
+GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_3::Capabilities& capabilities) {
const bool validOperandTypes = std::all_of(
capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
[](const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
- const auto maybeType = convert(operandPerformance.type);
+ const auto maybeType = unvalidatedConvert(operandPerformance.type);
return !maybeType.has_value() ? false : validOperandType(maybeType.value());
});
if (!validOperandTypes) {
- return NN_ERROR()
- << "Invalid OperandType when converting OperandPerformance in Capabilities";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid OperandType when unvalidatedConverting OperandPerformance in "
+ "Capabilities";
}
- auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance));
- auto table =
- NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
+ auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
+ auto table = NN_TRY(hal::utils::makeGeneralFailure(
+ Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
+ nn::ErrorStatus::GENERAL_FAILURE));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+ .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
.operandPerformance = std::move(table),
- .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)),
+ .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
+ .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
};
}
-Result<Capabilities::OperandPerformance> convert(
+GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
return Capabilities::OperandPerformance{
- .type = NN_TRY(convert(operandPerformance.type)),
- .info = NN_TRY(convert(operandPerformance.info)),
+ .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
+ .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
};
}
-Result<Operation> convert(const hal::V1_3::Operation& operation) {
+GeneralResult<Operation> unvalidatedConvert(const hal::V1_3::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-Result<Operand::LifeTime> convert(const hal::V1_3::OperandLifeTime& operandLifeTime) {
+GeneralResult<Operand::LifeTime> unvalidatedConvert(
+ const hal::V1_3::OperandLifeTime& operandLifeTime) {
return static_cast<Operand::LifeTime>(operandLifeTime);
}
-Result<Operand> convert(const hal::V1_3::Operand& operand) {
+GeneralResult<Operand> unvalidatedConvert(const hal::V1_3::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
- .extraParams = NN_TRY(convert(operand.extraParams)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
};
}
-Result<Model> convert(const hal::V1_3::Model& model) {
+GeneralResult<Model> unvalidatedConvert(const hal::V1_3::Model& model) {
return Model{
- .main = NN_TRY(convert(model.main)),
- .referenced = NN_TRY(convert(model.referenced)),
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .main = NN_TRY(unvalidatedConvert(model.main)),
+ .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
};
}
-Result<Model::Subgraph> convert(const hal::V1_3::Subgraph& subgraph) {
- auto operations = NN_TRY(convert(subgraph.operations));
+GeneralResult<Model::Subgraph> unvalidatedConvert(const hal::V1_3::Subgraph& subgraph) {
+ auto operations = NN_TRY(unvalidatedConvert(subgraph.operations));
// Verify number of consumers.
const auto numberOfConsumers =
@@ -186,25 +221,26 @@
CHECK(subgraph.operands.size() == numberOfConsumers.size());
for (size_t i = 0; i < subgraph.operands.size(); ++i) {
if (subgraph.operands[i].numberOfConsumers != numberOfConsumers[i]) {
- return NN_ERROR() << "Invalid numberOfConsumers for operand " << i << ", expected "
- << numberOfConsumers[i] << " but found "
- << subgraph.operands[i].numberOfConsumers;
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid numberOfConsumers for operand " << i << ", expected "
+ << numberOfConsumers[i] << " but found "
+ << subgraph.operands[i].numberOfConsumers;
}
}
return Model::Subgraph{
- .operands = NN_TRY(convert(subgraph.operands)),
+ .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
.operations = std::move(operations),
.inputIndexes = subgraph.inputIndexes,
.outputIndexes = subgraph.outputIndexes,
};
}
-Result<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc) {
+GeneralResult<BufferDesc> unvalidatedConvert(const hal::V1_3::BufferDesc& bufferDesc) {
return BufferDesc{.dimensions = bufferDesc.dimensions};
}
-Result<BufferRole> convert(const hal::V1_3::BufferRole& bufferRole) {
+GeneralResult<BufferRole> unvalidatedConvert(const hal::V1_3::BufferRole& bufferRole) {
return BufferRole{
.modelIndex = bufferRole.modelIndex,
.ioIndex = bufferRole.ioIndex,
@@ -212,15 +248,16 @@
};
}
-Result<Request> convert(const hal::V1_3::Request& request) {
+GeneralResult<Request> unvalidatedConvert(const hal::V1_3::Request& request) {
return Request{
- .inputs = NN_TRY(convert(request.inputs)),
- .outputs = NN_TRY(convert(request.outputs)),
- .pools = NN_TRY(convert(request.pools)),
+ .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
+ .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
+ .pools = NN_TRY(unvalidatedConvert(request.pools)),
};
}
-Result<Request::MemoryPool> convert(const hal::V1_3::Request::MemoryPool& memoryPool) {
+GeneralResult<Request::MemoryPool> unvalidatedConvert(
+ const hal::V1_3::Request::MemoryPool& memoryPool) {
using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
switch (memoryPool.getDiscriminator()) {
case Discriminator::hidlMemory:
@@ -228,16 +265,19 @@
case Discriminator::token:
return static_cast<Request::MemoryDomainToken>(memoryPool.token());
}
- return NN_ERROR() << "Invalid Request::MemoryPool discriminator "
- << underlyingType(memoryPool.getDiscriminator());
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid Request::MemoryPool discriminator "
+ << underlyingType(memoryPool.getDiscriminator());
}
-Result<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
+GeneralResult<OptionalTimePoint> unvalidatedConvert(
+ const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
constexpr auto kTimePointMaxCount = TimePoint::max().time_since_epoch().count();
- const auto makeTimePoint = [](uint64_t count) -> Result<OptionalTimePoint> {
+ const auto makeTimePoint = [](uint64_t count) -> GeneralResult<OptionalTimePoint> {
if (count > kTimePointMaxCount) {
- return NN_ERROR()
- << "Unable to convert OptionalTimePoint because the count exceeds the max";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Unable to unvalidatedConvert OptionalTimePoint because the count exceeds "
+ "the max";
}
const auto nanoseconds = std::chrono::nanoseconds{count};
return TimePoint{nanoseconds};
@@ -250,17 +290,19 @@
case Discriminator::nanosecondsSinceEpoch:
return makeTimePoint(optionalTimePoint.nanosecondsSinceEpoch());
}
- return NN_ERROR() << "Invalid OptionalTimePoint discriminator "
- << underlyingType(optionalTimePoint.getDiscriminator());
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid OptionalTimePoint discriminator "
+ << underlyingType(optionalTimePoint.getDiscriminator());
}
-Result<OptionalTimeoutDuration> convert(
+GeneralResult<OptionalTimeoutDuration> unvalidatedConvert(
const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) {
constexpr auto kTimeoutDurationMaxCount = TimeoutDuration::max().count();
- const auto makeTimeoutDuration = [](uint64_t count) -> Result<OptionalTimeoutDuration> {
+ const auto makeTimeoutDuration = [](uint64_t count) -> GeneralResult<OptionalTimeoutDuration> {
if (count > kTimeoutDurationMaxCount) {
- return NN_ERROR()
- << "Unable to convert OptionalTimeoutDuration because the count exceeds the max";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Unable to unvalidatedConvert OptionalTimeoutDuration because the count "
+ "exceeds the max";
}
return TimeoutDuration{count};
};
@@ -272,11 +314,12 @@
case Discriminator::nanoseconds:
return makeTimeoutDuration(optionalTimeoutDuration.nanoseconds());
}
- return NN_ERROR() << "Invalid OptionalTimeoutDuration discriminator "
- << underlyingType(optionalTimeoutDuration.getDiscriminator());
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid OptionalTimeoutDuration discriminator "
+ << underlyingType(optionalTimeoutDuration.getDiscriminator());
}
-Result<ErrorStatus> convert(const hal::V1_3::ErrorStatus& status) {
+GeneralResult<ErrorStatus> unvalidatedConvert(const hal::V1_3::ErrorStatus& status) {
switch (status) {
case hal::V1_3::ErrorStatus::NONE:
case hal::V1_3::ErrorStatus::DEVICE_UNAVAILABLE:
@@ -289,12 +332,54 @@
case hal::V1_3::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
return static_cast<ErrorStatus>(status);
}
- return NN_ERROR() << "Invalid ErrorStatus " << underlyingType(status);
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Invalid ErrorStatus " << underlyingType(status);
}
-Result<std::vector<BufferRole>> convert(
+GeneralResult<Priority> convert(const hal::V1_3::Priority& priority) {
+ return validatedConvert(priority);
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_3::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+GeneralResult<Model> convert(const hal::V1_3::Model& model) {
+ return validatedConvert(model);
+}
+
+GeneralResult<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc) {
+ return validatedConvert(bufferDesc);
+}
+
+GeneralResult<Request> convert(const hal::V1_3::Request& request) {
+ return validatedConvert(request);
+}
+
+GeneralResult<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
+ return validatedConvert(optionalTimePoint);
+}
+
+GeneralResult<OptionalTimeoutDuration> convert(
+ const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) {
+ return validatedConvert(optionalTimeoutDuration);
+}
+
+GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus) {
+ return validatedConvert(errorStatus);
+}
+
+GeneralResult<SharedHandle> convert(const hardware::hidl_handle& handle) {
+ return validatedConvert(handle);
+}
+
+GeneralResult<Memory> convert(const hardware::hidl_memory& memory) {
+ return validatedConvert(memory);
+}
+
+GeneralResult<std::vector<BufferRole>> convert(
const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles) {
- return convertVec(bufferRoles);
+ return validatedConvert(bufferRoles);
}
} // namespace android::nn
@@ -302,87 +387,120 @@
namespace android::hardware::neuralnetworks::V1_3::utils {
namespace {
-using utils::convert;
+using utils::unvalidatedConvert;
-nn::Result<V1_0::PerformanceInfo> convert(
+nn::GeneralResult<V1_0::PerformanceInfo> unvalidatedConvert(
const nn::Capabilities::PerformanceInfo& performanceInfo) {
- return V1_0::utils::convert(performanceInfo);
+ return V1_0::utils::unvalidatedConvert(performanceInfo);
}
-nn::Result<V1_0::DataLocation> convert(const nn::DataLocation& dataLocation) {
- return V1_0::utils::convert(dataLocation);
+nn::GeneralResult<V1_0::DataLocation> unvalidatedConvert(const nn::DataLocation& dataLocation) {
+ return V1_0::utils::unvalidatedConvert(dataLocation);
}
-nn::Result<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
- return V1_0::utils::convert(operandValues);
+nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
+ const nn::Model::OperandValues& operandValues) {
+ return V1_0::utils::unvalidatedConvert(operandValues);
}
-nn::Result<hidl_memory> convert(const nn::Memory& memory) {
- return V1_0::utils::convert(memory);
+nn::GeneralResult<hidl_handle> unvalidatedConvert(const nn::SharedHandle& handle) {
+ return V1_2::utils::unvalidatedConvert(handle);
}
-nn::Result<V1_0::RequestArgument> convert(const nn::Request::Argument& argument) {
- return V1_0::utils::convert(argument);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+ return V1_0::utils::unvalidatedConvert(memory);
}
-nn::Result<V1_2::Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams) {
- return V1_2::utils::convert(extraParams);
+nn::GeneralResult<V1_0::RequestArgument> unvalidatedConvert(const nn::Request::Argument& argument) {
+ return V1_0::utils::unvalidatedConvert(argument);
}
-nn::Result<V1_2::Model::ExtensionNameAndPrefix> convert(
+nn::GeneralResult<V1_2::Operand::ExtraParams> unvalidatedConvert(
+ const nn::Operand::ExtraParams& extraParams) {
+ return V1_2::utils::unvalidatedConvert(extraParams);
+}
+
+nn::GeneralResult<V1_2::Model::ExtensionNameAndPrefix> unvalidatedConvert(
const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
- return V1_2::utils::convert(extensionNameAndPrefix);
+ return V1_2::utils::unvalidatedConvert(extensionNameAndPrefix);
}
template <typename Input>
-using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+using unvalidatedConvertOutput =
+ std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
-nn::Result<hidl_vec<ConvertOutput<Type>>> convertVec(const std::vector<Type>& arguments) {
- hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
- halObject[i] = NN_TRY(convert(arguments[i]));
+ halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
}
return halObject;
}
template <typename Type>
-nn::Result<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
- return convertVec(arguments);
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+ const std::vector<Type>& arguments) {
+ return unvalidatedConvertVec(arguments);
}
-nn::Result<Request::MemoryPool> makeMemoryPool(const nn::Memory& memory) {
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Memory& memory) {
Request::MemoryPool ret;
- ret.hidlMemory(NN_TRY(convert(memory)));
+ ret.hidlMemory(NN_TRY(unvalidatedConvert(memory)));
return ret;
}
-nn::Result<Request::MemoryPool> makeMemoryPool(const nn::Request::MemoryDomainToken& token) {
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Request::MemoryDomainToken& token) {
Request::MemoryPool ret;
ret.token(underlyingType(token));
return ret;
}
-nn::Result<Request::MemoryPool> makeMemoryPool(
- const std::shared_ptr<const nn::IBuffer>& /*buffer*/) {
- return NN_ERROR() << "Unable to make memory pool from IBuffer";
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedBuffer& /*buffer*/) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Unable to make memory pool from IBuffer";
+}
+
+using utils::unvalidatedConvert;
+
+template <typename Type>
+decltype(unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
+ const auto maybeVersion = nn::validate(canonical);
+ if (!maybeVersion.has_value()) {
+ return nn::error() << maybeVersion.error();
+ }
+ const auto version = maybeVersion.value();
+ if (version > kVersion) {
+ return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+ }
+ return unvalidatedConvert(canonical);
+}
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> validatedConvert(
+ const std::vector<Type>& arguments) {
+ hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ halObject[i] = NN_TRY(validatedConvert(arguments[i]));
+ }
+ return halObject;
}
} // anonymous namespace
-nn::Result<OperandType> convert(const nn::OperandType& operandType) {
+nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
return static_cast<OperandType>(operandType);
}
-nn::Result<OperationType> convert(const nn::OperationType& operationType) {
+nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
return static_cast<OperationType>(operationType);
}
-nn::Result<Priority> convert(const nn::Priority& priority) {
+nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority) {
return static_cast<Priority>(priority);
}
-nn::Result<Capabilities> convert(const nn::Capabilities& capabilities) {
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
std::copy_if(capabilities.operandPerformance.asVector().begin(),
@@ -393,69 +511,72 @@
});
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor =
- NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
- .operandPerformance = NN_TRY(convert(operandPerformance)),
- .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)),
+ .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+ .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
+ unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)),
+ .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
+ .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
};
}
-nn::Result<Capabilities::OperandPerformance> convert(
+nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance) {
return Capabilities::OperandPerformance{
- .type = NN_TRY(convert(operandPerformance.type)),
- .info = NN_TRY(convert(operandPerformance.info)),
+ .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
+ .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
};
}
-nn::Result<Operation> convert(const nn::Operation& operation) {
+nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
return Operation{
- .type = NN_TRY(convert(operation.type)),
+ .type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = operation.inputs,
.outputs = operation.outputs,
};
}
-nn::Result<OperandLifeTime> convert(const nn::Operand::LifeTime& operandLifeTime) {
+nn::GeneralResult<OperandLifeTime> unvalidatedConvert(
+ const nn::Operand::LifeTime& operandLifeTime) {
if (operandLifeTime == nn::Operand::LifeTime::POINTER) {
- return NN_ERROR() << "Model cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
return static_cast<OperandLifeTime>(operandLifeTime);
}
-nn::Result<Operand> convert(const nn::Operand& operand) {
+nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
return Operand{
- .type = NN_TRY(convert(operand.type)),
+ .type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(convert(operand.lifetime)),
- .location = NN_TRY(convert(operand.location)),
- .extraParams = NN_TRY(convert(operand.extraParams)),
+ .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
+ .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
};
}
-nn::Result<Model> convert(const nn::Model& model) {
+nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
if (!hal::utils::hasNoPointerData(model)) {
- return NN_ERROR() << "Model cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
return Model{
- .main = NN_TRY(convert(model.main)),
- .referenced = NN_TRY(convert(model.referenced)),
- .operandValues = NN_TRY(convert(model.operandValues)),
- .pools = NN_TRY(convert(model.pools)),
+ .main = NN_TRY(unvalidatedConvert(model.main)),
+ .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
+ .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
+ .pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
};
}
-nn::Result<Subgraph> convert(const nn::Model::Subgraph& subgraph) {
- auto operands = NN_TRY(convert(subgraph.operands));
+nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph) {
+ auto operands = NN_TRY(unvalidatedConvert(subgraph.operands));
// Update number of consumers.
const auto numberOfConsumers =
@@ -467,17 +588,17 @@
return Subgraph{
.operands = std::move(operands),
- .operations = NN_TRY(convert(subgraph.operations)),
+ .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
.inputIndexes = subgraph.inputIndexes,
.outputIndexes = subgraph.outputIndexes,
};
}
-nn::Result<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
+nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc) {
return BufferDesc{.dimensions = bufferDesc.dimensions};
}
-nn::Result<BufferRole> convert(const nn::BufferRole& bufferRole) {
+nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole) {
return BufferRole{
.modelIndex = bufferRole.modelIndex,
.ioIndex = bufferRole.ioIndex,
@@ -485,50 +606,56 @@
};
}
-nn::Result<Request> convert(const nn::Request& request) {
+nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
if (!hal::utils::hasNoPointerData(request)) {
- return NN_ERROR() << "Request cannot be converted because it contains pointer-based memory";
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
return Request{
- .inputs = NN_TRY(convert(request.inputs)),
- .outputs = NN_TRY(convert(request.outputs)),
- .pools = NN_TRY(convert(request.pools)),
+ .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
+ .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
+ .pools = NN_TRY(unvalidatedConvert(request.pools)),
};
}
-nn::Result<Request::MemoryPool> convert(const nn::Request::MemoryPool& memoryPool) {
+nn::GeneralResult<Request::MemoryPool> unvalidatedConvert(
+ const nn::Request::MemoryPool& memoryPool) {
return std::visit([](const auto& o) { return makeMemoryPool(o); }, memoryPool);
}
-nn::Result<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint) {
+nn::GeneralResult<OptionalTimePoint> unvalidatedConvert(
+ const nn::OptionalTimePoint& optionalTimePoint) {
OptionalTimePoint ret;
if (optionalTimePoint.has_value()) {
const auto count = optionalTimePoint.value().time_since_epoch().count();
if (count < 0) {
- return NN_ERROR() << "Unable to convert OptionalTimePoint because time since epoch "
- "count is negative";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Unable to unvalidatedConvert OptionalTimePoint because time since epoch "
+ "count is "
+ "negative";
}
ret.nanosecondsSinceEpoch(count);
}
return ret;
}
-nn::Result<OptionalTimeoutDuration> convert(
+nn::GeneralResult<OptionalTimeoutDuration> unvalidatedConvert(
const nn::OptionalTimeoutDuration& optionalTimeoutDuration) {
OptionalTimeoutDuration ret;
if (optionalTimeoutDuration.has_value()) {
const auto count = optionalTimeoutDuration.value().count();
if (count < 0) {
- return NN_ERROR()
- << "Unable to convert OptionalTimeoutDuration because count is negative";
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Unable to unvalidatedConvert OptionalTimeoutDuration because count is "
+ "negative";
}
ret.nanoseconds(count);
}
return ret;
}
-nn::Result<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
+nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
switch (errorStatus) {
case nn::ErrorStatus::NONE:
case nn::ErrorStatus::DEVICE_UNAVAILABLE:
@@ -545,8 +672,49 @@
}
}
-nn::Result<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
- return convertVec(bufferRoles);
+nn::GeneralResult<Priority> convert(const nn::Priority& priority) {
+ return validatedConvert(priority);
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+ return validatedConvert(capabilities);
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+ return validatedConvert(model);
+}
+
+nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
+ return validatedConvert(bufferDesc);
+}
+
+nn::GeneralResult<Request> convert(const nn::Request& request) {
+ return validatedConvert(request);
+}
+
+nn::GeneralResult<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint) {
+ return validatedConvert(optionalTimePoint);
+}
+
+nn::GeneralResult<OptionalTimeoutDuration> convert(
+ const nn::OptionalTimeoutDuration& optionalTimeoutDuration) {
+ return validatedConvert(optionalTimeoutDuration);
+}
+
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
+ return validatedConvert(errorStatus);
+}
+
+nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle) {
+ return validatedConvert(handle);
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+ return validatedConvert(memory);
+}
+
+nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
+ return validatedConvert(bufferRoles);
}
} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
new file mode 100644
index 0000000..82837ba
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Device.h"
+
+#include "Buffer.h"
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/Device.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <any>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<hidl_vec<sp<IPreparedModel>>> convert(
+ const std::vector<nn::SharedPreparedModel>& preparedModels) {
+ hidl_vec<sp<IPreparedModel>> hidlPreparedModels(preparedModels.size());
+ for (size_t i = 0; i < preparedModels.size(); ++i) {
+ std::any underlyingResource = preparedModels[i]->getUnderlyingResource();
+ if (const auto* hidlPreparedModel =
+ std::any_cast<sp<IPreparedModel>>(&underlyingResource)) {
+ hidlPreparedModels[i] = *hidlPreparedModel;
+ } else {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "Unable to convert from nn::IPreparedModel to V1_3::IPreparedModel";
+ }
+ }
+ return hidlPreparedModels;
+}
+
+nn::GeneralResult<nn::SharedBuffer> convert(
+ nn::GeneralResult<std::shared_ptr<const Buffer>> result) {
+ return NN_TRY(std::move(result));
+}
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_3::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities_1_3 failed with " << toString(status);
+ } else {
+ result = nn::convert(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities_1_3(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+ sp<V1_3::IDevice> device) {
+ if (name.empty()) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_3::utils::Device::create must have non-empty name";
+ }
+ if (device == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_3::utils::Device::create must have non-null device";
+ }
+
+ auto versionString = NN_TRY(V1_2::utils::initVersionString(device.get()));
+ const auto deviceType = NN_TRY(V1_2::utils::initDeviceType(device.get()));
+ auto extensions = NN_TRY(V1_2::utils::initExtensions(device.get()));
+ auto capabilities = NN_TRY(initCapabilities(device.get()));
+ const auto numberOfCacheFilesNeeded =
+ NN_TRY(V1_2::utils::initNumberOfCacheFilesNeeded(device.get()));
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+ return std::make_shared<const Device>(
+ PrivateConstructorTag{}, std::move(name), std::move(versionString), deviceType,
+ std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
+ std::move(device), std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, std::string versionString,
+ nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities,
+ std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, sp<V1_3::IDevice> device,
+ hal::utils::DeathHandler deathHandler)
+ : kName(std::move(name)),
+ kVersionString(std::move(versionString)),
+ kDeviceType(deviceType),
+ kExtensions(std::move(extensions)),
+ kCapabilities(std::move(capabilities)),
+ kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded),
+ kDevice(std::move(device)),
+ kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+ return kName;
+}
+
+const std::string& Device::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+ return nn::Version::ANDROID_R;
+}
+
+nn::DeviceType Device::getType() const {
+ return kDeviceType;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+ return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> Device::wait() const {
+ const auto ret = kDevice->ping();
+ HANDLE_TRANSPORT_FAILURE(ret);
+ return {};
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+
+ nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical)
+ << "IDevice::getSupportedOperations_1_3 failed with " << toString(status);
+ } else if (supportedOperations.size() != model.main.operations.size()) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "IDevice::getSupportedOperations_1_3 returned vector of size "
+ << supportedOperations.size() << " but expected "
+ << model.main.operations.size();
+ } else {
+ result = supportedOperations;
+ }
+ };
+
+ const auto ret = kDevice->getSupportedOperations_1_3(hidlModel, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ // Ensure that model is ready for IPC.
+ std::optional<nn::Model> maybeModelInShared;
+ const nn::Model& modelInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+ const auto hidlModel = NN_TRY(convert(modelInShared));
+ const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
+ const auto hidlPriority = NN_TRY(convert(priority));
+ const auto hidlDeadline = NN_TRY(convert(deadline));
+ const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
+ const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
+ const auto hidlToken = token;
+
+ const auto cb = sp<PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret =
+ kDevice->prepareModel_1_3(hidlModel, hidlPreference, hidlPriority, hidlDeadline,
+ hidlModelCache, hidlDataCache, hidlToken, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModel_1_3 failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const auto hidlDeadline = NN_TRY(convert(deadline));
+ const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
+ const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
+ const auto hidlToken = token;
+
+ const auto cb = sp<PreparedModelCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret = kDevice->prepareModelFromCache_1_3(hidlDeadline, hidlModelCache, hidlDataCache,
+ hidlToken, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "prepareModelFromCache_1_3 failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const {
+ const auto hidlDesc = NN_TRY(convert(desc));
+ const auto hidlPreparedModels = NN_TRY(convert(preparedModels));
+ const auto hidlInputRoles = NN_TRY(convert(inputRoles));
+ const auto hidlOutputRoles = NN_TRY(convert(outputRoles));
+
+ nn::GeneralResult<nn::SharedBuffer> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ auto cb = [&result](ErrorStatus status, const sp<IBuffer>& buffer, uint32_t token) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "IDevice::allocate failed with " << toString(status);
+ } else if (buffer == nullptr) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned buffer is nullptr";
+ } else if (token == 0) {
+ result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned token is invalid (0)";
+ } else {
+ result = convert(
+ Buffer::create(buffer, static_cast<nn::Request::MemoryDomainToken>(token)));
+ }
+ };
+
+ const auto ret =
+ kDevice->allocate(hidlDesc, hidlPreparedModels, hidlInputRoles, hidlOutputRoles, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..49b9b0b
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
+ const hidl_vec<V1_2::OutputShape>& outputShapes, const V1_2::Timing& timing) {
+ return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
+}
+
+nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> convertFencedExecutionCallbackResults(
+ const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) {
+ return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced)));
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+convertExecuteFencedResults(const hidl_handle& syncFence,
+ const sp<IFencedExecutionCallback>& callback) {
+ auto resultSyncFence = nn::SyncFence::createAsSignaled();
+ if (syncFence.getNativeHandle() != nullptr) {
+ auto sharedHandle = NN_TRY(nn::convert(syncFence));
+ resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure(
+ nn::SyncFence::create(std::move(sharedHandle)), nn::ErrorStatus::GENERAL_FAILURE));
+ }
+
+ if (callback == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "callback is null";
+ }
+
+ // Create callback which can be used to retrieve the execution error status and timings.
+ nn::ExecuteFencedInfoCallback resultCallback =
+ [callback]() -> nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> {
+ nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ auto cb = [&result](ErrorStatus status, const V1_2::Timing& timingLaunched,
+ const V1_2::Timing& timingFenced) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical =
+ nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getExecutionInfo failed with " << toString(status);
+ } else {
+ result = convertFencedExecutionCallbackResults(timingLaunched, timingFenced);
+ }
+ };
+
+ const auto ret = callback->getExecutionInfo(cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+ };
+
+ return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+ sp<V1_3::IPreparedModel> preparedModel) {
+ if (preparedModel == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "V1_3::utils::PreparedModel::create must have non-null preparedModel";
+ }
+
+ auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+ return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+ std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_3::IPreparedModel> preparedModel,
+ hal::utils::DeathHandler deathHandler)
+ : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeSynchronously(const Request& request, V1_2::MeasureTiming measure,
+ const OptionalTimePoint& deadline,
+ const OptionalTimeoutDuration& loopTimeoutDuration) const {
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const auto cb = [&result](ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
+ } else {
+ result = convertExecutionResults(outputShapes, timing);
+ }
+ };
+
+ const auto ret = kPreparedModel->executeSynchronously_1_3(request, measure, deadline,
+ loopTimeoutDuration, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+
+ return result;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeAsynchronously(const Request& request, V1_2::MeasureTiming measure,
+ const OptionalTimePoint& deadline,
+ const OptionalTimeoutDuration& loopTimeoutDuration) const {
+ const auto cb = sp<ExecutionCallback>::make();
+ const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+ const auto ret =
+ kPreparedModel->execute_1_3(request, measure, deadline, loopTimeoutDuration, cb);
+ const auto status = HANDLE_TRANSPORT_FAILURE(ret);
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ return NN_ERROR(canonical) << "executeAsynchronously failed with " << toString(status);
+ }
+
+ return cb->get();
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+ const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+ const auto hidlMeasure =
+ NN_TRY(hal::utils::makeExecutionFailure(V1_2::utils::convert(measure)));
+ const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+ const auto hidlLoopTimeoutDuration =
+ NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ const bool preferSynchronous = true;
+
+ // Execute synchronously if allowed.
+ if (preferSynchronous) {
+ result = executeSynchronously(hidlRequest, hidlMeasure, hidlDeadline,
+ hidlLoopTimeoutDuration);
+ }
+
+ // Run asymchronous execution if execution has not already completed.
+ if (!result.has_value()) {
+ result = executeAsynchronously(hidlRequest, hidlMeasure, hidlDeadline,
+ hidlLoopTimeoutDuration);
+ }
+
+ // Flush output buffers if suxcessful execution.
+ if (result.has_value()) {
+ NN_TRY(hal::utils::makeExecutionFailure(
+ hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+ }
+
+ return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ const nn::Request& requestInShared =
+ NN_TRY(hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared));
+
+ const auto hidlRequest = NN_TRY(convert(requestInShared));
+ const auto hidlWaitFor = NN_TRY(hal::utils::convertSyncFences(waitFor));
+ const auto hidlMeasure = NN_TRY(V1_2::utils::convert(measure));
+ const auto hidlDeadline = NN_TRY(convert(deadline));
+ const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+ const auto hidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> result =
+ NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+ auto cb = [&result](ErrorStatus status, const hidl_handle& syncFence,
+ const sp<IFencedExecutionCallback>& callback) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "executeFenced failed with " << toString(status);
+ } else {
+ result = convertExecuteFencedResults(syncFence, callback);
+ }
+ };
+
+ const auto ret = kPreparedModel->executeFenced(hidlRequest, hidlWaitFor, hidlMeasure,
+ hidlDeadline, hidlLoopTimeoutDuration,
+ hidlTimeoutDurationAfterFence, cb);
+ HANDLE_TRANSPORT_FAILURE(ret);
+ auto [syncFence, callback] = NN_TRY(std::move(result));
+
+ // If executeFenced required the request memory to be moved into shared memory, block here until
+ // the fenced execution has completed and flush the memory back.
+ if (maybeRequestInShared.has_value()) {
+ const auto state = syncFence.syncWait({});
+ if (state != nn::SyncFence::FenceState::SIGNALED) {
+ return NN_ERROR() << "syncWait failed with " << state;
+ }
+ NN_TRY(hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared));
+ }
+
+ return std::make_pair(std::move(syncFence), std::move(callback));
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+ sp<V1_3::IPreparedModel> resource = kPreparedModel;
+ return resource;
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Service.cpp b/neuralnetworks/1.3/utils/src/Service.cpp
new file mode 100644
index 0000000..62887fb
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+ hal::utils::ResilientDevice::Factory makeDevice =
+ [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+ auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+ if (service == nullptr) {
+ return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+ }
+ return Device::create(name, std::move(service));
+ };
+
+ return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index 0cefffa..ca5041d 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -21,7 +21,9 @@
"include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
}
]
- },
+ }
+ ],
+ "presubmit-large": [
{
"name": "VtsHalNeuralnetworksV1_2TargetTest",
"options": [
diff --git a/neuralnetworks/utils/README.md b/neuralnetworks/utils/README.md
new file mode 100644
index 0000000..0dee103
--- /dev/null
+++ b/neuralnetworks/utils/README.md
@@ -0,0 +1,50 @@
+# NNAPI Conversions
+
+`convert` fails if either the source type or the destination type is invalid, and it yields a valid
+object if the conversion succeeds. For example, let's say that an enumeration in the current
+version has fewer possible values than the "same" canonical enumeration, such as `OperationType`.
+The new value of `HARD_SWISH` (introduced in Android R / NN HAL 1.3) does not map to any valid
+existing value in `OperationType`, but an older value of `ADD` (introduced in Android OC-MR1 / NN
+HAL 1.0) is valid. This can be seen in the following model conversions:
+
+```cpp
+// Unsuccessful conversion
+const nn::Model canonicalModel = createModelWhichHasV1_3Operations();
+const nn::Result<V1_0::Model> maybeVersionedModel = V1_0::utils::convert(canonicalModel);
+EXPECT_FALSE(maybeVersionedModel.has_value());
+```
+```cpp
+// Successful conversion
+const nn::Model canonicalModel = createModelWhichHasOnlyV1_0Operations();
+const nn::Result<V1_0::Model> maybeVersionedModel = V1_0::utils::convert(canonicalModel);
+ASSERT_TRUE(maybeVersionedModel.has_value());
+const V1_0::Model& versionedModel = maybeVersionedModel.value();
+EXPECT_TRUE(V1_0::utils::valid(versionedModel));
+```
+
+`V1_X::utils::convert` does not guarantee that all information is preserved. For example, In the
+case of `nn::ErrorStatus`, the new value of `MISSED_DEADLINE_TRANSIENT` can be represented by the
+existing value of `V1_0::GENERAL_FAILURE`:
+
+```cpp
+// Lossy Canonical -> HAL -> Canonical conversion
+const nn::ErrorStatus canonicalBefore = nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT;
+const V1_0::ErrorStatus versioned = V1_0::utils::convert(canonicalBefore).value();
+const nn::ErrorStatus canonicalAfter = nn::convert(versioned).value();
+EXPECT_NE(canonicalBefore, canonicalAfter);
+```
+
+However, `nn::convert` is guaranteed to preserve all information:
+
+```cpp
+// Lossless HAL -> Canonical -> HAL conversion
+const V1_0::ErrorStatus versionedBefore = V1_0::ErrorStatus::GENERAL_FAILURE;
+const nn::ErrorStatus canonical = nn::convert(versionedBefore).value();
+const V1_0::ErrorStatus versionedAfter = V1_0::utils::convert(canonical).value();
+EXPECT_EQ(versionedBefore, versionedAfter);
+```
+
+The `convert` functions operate only on types that used in a HIDL method call directly. The
+`unvalidatedConvert` functions operate on types that are either used in a HIDL method call directly
+(i.e., not as a nested class) or used in a subsequent version of the NN HAL. Prefer using `convert`
+over `unvalidatedConvert`.
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index b61dc97..21562cf 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -20,6 +20,7 @@
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal"],
export_include_dirs: ["include"],
+ cflags: ["-Wthread-safety"],
static_libs: [
"neuralnetworks_types",
],
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
index 8c01368..43bb0c6 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
@@ -17,8 +17,11 @@
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
+#include <cutils/native_handle.h>
+#include <hidl/HidlSupport.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
+#include <functional>
#include <vector>
// Shorthand
@@ -42,18 +45,27 @@
bool hasNoPointerData(const nn::Request& request);
// Relocate pointer-based data to shared memory.
-nn::Result<nn::Model> flushDataFromPointerToShared(const nn::Model& model);
-nn::Result<nn::Request> flushDataFromPointerToShared(const nn::Request& request);
+nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
+ const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut);
+nn::GeneralResult<std::reference_wrapper<const nn::Request>> flushDataFromPointerToShared(
+ const nn::Request* request, std::optional<nn::Request>* maybeRequestInSharedOut);
// Undoes `flushDataFromPointerToShared` on a Request object. More specifically,
// `unflushDataFromSharedToPointer` copies the output shared memory data from the transformed
// Request object back to the output pointer-based memory in the original Request object.
-nn::Result<void> unflushDataFromSharedToPointer(const nn::Request& request,
- const nn::Request& requestInShared);
+nn::GeneralResult<void> unflushDataFromSharedToPointer(
+ const nn::Request& request, const std::optional<nn::Request>& maybeRequestInShared);
std::vector<uint32_t> countNumberOfConsumers(size_t numberOfOperands,
const std::vector<nn::Operation>& operations);
+nn::GeneralResult<nn::Memory> createSharedMemoryFromHidlMemory(const hidl_memory& memory);
+
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle);
+nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle);
+nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
+ const std::vector<nn::SyncFence>& fences);
+
} // namespace android::hardware::neuralnetworks::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
new file mode 100644
index 0000000..78b2a12
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <type_traits>
+
+namespace android::hardware::neuralnetworks::utils {
+
+template <typename Type>
+nn::GeneralResult<Type> handleTransportError(const hardware::Return<Type>& ret) {
+ if (ret.isDeadObject()) {
+ return nn::error(nn::ErrorStatus::DEAD_OBJECT)
+ << "Return<>::isDeadObject returned true: " << ret.description();
+ }
+ if (!ret.isOk()) {
+ return nn::error(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Return<>::isOk returned false: " << ret.description();
+ }
+ if constexpr (!std::is_same_v<Type, void>) {
+ return static_cast<Type>(ret);
+ } else {
+ return {};
+ }
+}
+
+#define HANDLE_TRANSPORT_FAILURE(ret) \
+ ({ \
+ auto result = ::android::hardware::neuralnetworks::utils::handleTransportError(ret); \
+ if (!result.has_value()) { \
+ return NN_ERROR(result.error().code) << result.error().message; \
+ } \
+ std::move(result).value(); \
+ })
+
+template <typename Type>
+nn::GeneralResult<Type> makeGeneralFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+ if (!result.has_value()) {
+ return nn::error(status) << std::move(result).error();
+ }
+ if constexpr (!std::is_same_v<Type, void>) {
+ return std::move(result).value();
+ } else {
+ return {};
+ }
+}
+
+template <typename Type>
+nn::ExecutionResult<Type> makeExecutionFailure(nn::GeneralResult<Type> result) {
+ if (!result.has_value()) {
+ const auto [message, status] = std::move(result).error();
+ return nn::error(status) << message;
+ }
+ if constexpr (!std::is_same_v<Type, void>) {
+ return std::move(result).value();
+ } else {
+ return {};
+ }
+}
+
+template <typename Type>
+nn::ExecutionResult<Type> makeExecutionFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+ return makeExecutionFailure(makeGeneralFailure(result, status));
+}
+
+} // namespace android::hardware::neuralnetworks::utils
\ No newline at end of file
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
new file mode 100644
index 0000000..8c04b88
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidBuffer final : public nn::IBuffer {
+ public:
+ nn::Request::MemoryDomainToken getToken() const override;
+
+ nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+
+ nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ const nn::Dimensions& dimensions) const override;
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
new file mode 100644
index 0000000..5e62b9a
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidDevice final : public nn::IDevice {
+ public:
+ InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
+ nn::DeviceType type, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities,
+ std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ const std::string kName;
+ const std::string kVersionString;
+ const nn::Version kFeatureLevel;
+ const nn::DeviceType kType;
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
new file mode 100644
index 0000000..4b32b4e
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
+
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidPreparedModel final : public nn::IPreparedModel {
+ public:
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+ std::any getUnderlyingResource() const override;
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h
new file mode 100644
index 0000000..85bd613
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
+
+#include <android-base/scopeguard.h>
+#include <android-base/thread_annotations.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class IProtectedCallback {
+ public:
+ /**
+ * Marks this object as a dead object.
+ */
+ virtual void notifyAsDeadObject() = 0;
+
+ // Public virtual destructor to allow objects to be stored (and destroyed) as smart pointers.
+ // E.g., std::unique_ptr<IProtectedCallback>.
+ virtual ~IProtectedCallback() = default;
+
+ protected:
+ // Protect the non-destructor special member functions to prevent object slicing.
+ IProtectedCallback() = default;
+ IProtectedCallback(const IProtectedCallback&) = default;
+ IProtectedCallback(IProtectedCallback&&) noexcept = default;
+ IProtectedCallback& operator=(const IProtectedCallback&) = default;
+ IProtectedCallback& operator=(IProtectedCallback&&) noexcept = default;
+};
+
+// Thread safe class
+class DeathRecipient final : public hidl_death_recipient {
+ public:
+ void serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) override;
+ // Precondition: `killable` must be non-null.
+ void add(IProtectedCallback* killable) const;
+ // Precondition: `killable` must be non-null.
+ void remove(IProtectedCallback* killable) const;
+
+ private:
+ mutable std::mutex mMutex;
+ mutable std::vector<IProtectedCallback*> mObjects GUARDED_BY(mMutex);
+};
+
+class DeathHandler final {
+ public:
+ static nn::GeneralResult<DeathHandler> create(sp<hidl::base::V1_0::IBase> object);
+
+ DeathHandler(const DeathHandler&) = delete;
+ DeathHandler(DeathHandler&&) noexcept = default;
+ DeathHandler& operator=(const DeathHandler&) = delete;
+ DeathHandler& operator=(DeathHandler&&) noexcept = delete;
+ ~DeathHandler();
+
+ using Cleanup = std::function<void()>;
+ // Precondition: `killable` must be non-null.
+ [[nodiscard]] base::ScopeGuard<Cleanup> protectCallback(IProtectedCallback* killable) const;
+
+ private:
+ DeathHandler(sp<hidl::base::V1_0::IBase> object, sp<DeathRecipient> deathRecipient);
+
+ sp<hidl::base::V1_0::IBase> kObject;
+ sp<DeathRecipient> kDeathRecipient;
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
new file mode 100644
index 0000000..996ec1e
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientBuffer final : public nn::IBuffer {
+ struct PrivateConstructorTag {};
+
+ public:
+ using Factory = std::function<nn::GeneralResult<nn::SharedBuffer>(bool blocking)>;
+
+ static nn::GeneralResult<std::shared_ptr<const ResilientBuffer>> create(Factory makeBuffer);
+
+ explicit ResilientBuffer(PrivateConstructorTag tag, Factory makeBuffer,
+ nn::SharedBuffer buffer);
+
+ nn::SharedBuffer getBuffer() const;
+ nn::SharedBuffer recover(const nn::IBuffer* failingBuffer, bool blocking) const;
+
+ nn::Request::MemoryDomainToken getToken() const override;
+
+ nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+
+ nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ const nn::Dimensions& dimensions) const override;
+
+ private:
+ const Factory kMakeBuffer;
+ mutable std::mutex mMutex;
+ mutable nn::SharedBuffer mBuffer GUARDED_BY(mMutex);
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
new file mode 100644
index 0000000..4bfed6c
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientDevice final : public nn::IDevice,
+ public std::enable_shared_from_this<ResilientDevice> {
+ struct PrivateConstructorTag {};
+
+ public:
+ using Factory = std::function<nn::GeneralResult<nn::SharedDevice>(bool blocking)>;
+
+ static nn::GeneralResult<std::shared_ptr<const ResilientDevice>> create(Factory makeDevice);
+
+ explicit ResilientDevice(PrivateConstructorTag tag, Factory makeDevice, std::string name,
+ std::string versionString, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities, nn::SharedDevice device);
+
+ nn::SharedDevice getDevice() const EXCLUDES(mMutex);
+ nn::SharedDevice recover(const nn::IDevice* failingDevice, bool blocking) const
+ EXCLUDES(mMutex);
+
+ const std::string& getName() const override;
+ const std::string& getVersionString() const override;
+ nn::Version getFeatureLevel() const override;
+ nn::DeviceType getType() const override;
+ const std::vector<nn::Extension>& getSupportedExtensions() const override;
+ const nn::Capabilities& getCapabilities() const override;
+ std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+ nn::GeneralResult<void> wait() const override;
+
+ nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+ const nn::Model& model) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache,
+ const nn::CacheToken& token) const override;
+
+ nn::GeneralResult<nn::SharedBuffer> allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const override;
+
+ private:
+ bool isValidInternal() const EXCLUDES(mMutex);
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelInternal(
+ bool blocking, const nn::Model& model, nn::ExecutionPreference preference,
+ nn::Priority priority, nn::OptionalTimePoint deadline,
+ const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+ nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCacheInternal(
+ bool blocking, nn::OptionalTimePoint deadline,
+ const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+ nn::GeneralResult<nn::SharedBuffer> allocateInternal(
+ bool blocking, const nn::BufferDesc& desc,
+ const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const;
+
+ const Factory kMakeDevice;
+ const std::string kName;
+ const std::string kVersionString;
+ const std::vector<nn::Extension> kExtensions;
+ const nn::Capabilities kCapabilities;
+ mutable std::mutex mMutex;
+ mutable nn::SharedDevice mDevice GUARDED_BY(mMutex);
+ mutable bool mIsValid GUARDED_BY(mMutex) = true;
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
new file mode 100644
index 0000000..c2940d1
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientPreparedModel final : public nn::IPreparedModel {
+ struct PrivateConstructorTag {};
+
+ public:
+ using Factory = std::function<nn::GeneralResult<nn::SharedPreparedModel>(bool blocking)>;
+
+ static nn::GeneralResult<std::shared_ptr<const ResilientPreparedModel>> create(
+ Factory makePreparedModel);
+
+ explicit ResilientPreparedModel(PrivateConstructorTag tag, Factory makePreparedModel,
+ nn::SharedPreparedModel preparedModel);
+
+ nn::SharedPreparedModel getPreparedModel() const;
+ nn::SharedPreparedModel recover(const nn::IPreparedModel* failingPreparedModel,
+ bool blocking) const;
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+ std::any getUnderlyingResource() const override;
+
+ private:
+ const Factory kMakePreparedModel;
+ mutable std::mutex mMutex;
+ mutable nn::SharedPreparedModel mPreparedModel GUARDED_BY(mMutex);
+};
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h b/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h
new file mode 100644
index 0000000..7103c6b
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
+
+#include <android-base/thread_annotations.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <optional>
+
+namespace android::hardware::neuralnetworks::utils {
+
+// This class is thread safe.
+template <typename Type>
+class TransferValue final {
+ public:
+ void put(Type object) const;
+ [[nodiscard]] Type take() const;
+
+ private:
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ mutable std::optional<Type> mObject GUARDED_BY(mMutex);
+};
+
+// template implementation
+
+template <typename Type>
+void TransferValue<Type>::put(Type object) const {
+ {
+ std::lock_guard guard(mMutex);
+ // Immediately return if value already exists.
+ if (mObject.has_value()) return;
+ mObject.emplace(std::move(object));
+ }
+ mCondition.notify_all();
+}
+
+template <typename Type>
+Type TransferValue<Type>::take() const {
+ std::unique_lock lock(mMutex);
+ base::ScopedLockAssertion lockAssertion(mMutex);
+ mCondition.wait(lock, [this]() REQUIRES(mMutex) { return mObject.has_value(); });
+ std::optional<Type> object;
+ std::swap(object, mObject);
+ return std::move(object).value();
+}
+
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 667189b..c04c8df 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -16,7 +16,10 @@
#include "CommonUtils.h"
+#include "HandleError.h"
+
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
@@ -25,6 +28,7 @@
#include <algorithm>
#include <any>
+#include <functional>
#include <optional>
#include <variant>
#include <vector>
@@ -111,8 +115,18 @@
return hasNoPointerData(request.inputs) && hasNoPointerData(request.outputs);
}
-nn::Result<nn::Model> flushDataFromPointerToShared(const nn::Model& model) {
- auto modelInShared = model;
+nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
+ const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut) {
+ CHECK(model != nullptr);
+ CHECK(maybeModelInSharedOut != nullptr);
+
+ if (hasNoPointerData(*model)) {
+ return *model;
+ }
+
+ // Make a copy of the model in order to make modifications. The modified model is returned to
+ // the caller through `maybeModelInSharedOut` if the function succeeds.
+ nn::Model modelInShared = *model;
nn::ConstantMemoryBuilder memoryBuilder(modelInShared.pools.size());
copyPointersToSharedMemory(&modelInShared.main, &memoryBuilder);
@@ -126,11 +140,22 @@
modelInShared.pools.push_back(std::move(memory));
}
- return modelInShared;
+ *maybeModelInSharedOut = modelInShared;
+ return **maybeModelInSharedOut;
}
-nn::Result<nn::Request> flushDataFromPointerToShared(const nn::Request& request) {
- auto requestInShared = request;
+nn::GeneralResult<std::reference_wrapper<const nn::Request>> flushDataFromPointerToShared(
+ const nn::Request* request, std::optional<nn::Request>* maybeRequestInSharedOut) {
+ CHECK(request != nullptr);
+ CHECK(maybeRequestInSharedOut != nullptr);
+
+ if (hasNoPointerData(*request)) {
+ return *request;
+ }
+
+ // Make a copy of the request in order to make modifications. The modified request is returned
+ // to the caller through `maybeRequestInSharedOut` if the function succeeds.
+ nn::Request requestInShared = *request;
// Change input pointers to shared memory.
nn::ConstantMemoryBuilder inputBuilder(requestInShared.pools.size());
@@ -171,15 +196,17 @@
requestInShared.pools.push_back(std::move(memory));
}
- return requestInShared;
+ *maybeRequestInSharedOut = requestInShared;
+ return **maybeRequestInSharedOut;
}
-nn::Result<void> unflushDataFromSharedToPointer(const nn::Request& request,
- const nn::Request& requestInShared) {
- if (requestInShared.pools.empty() ||
- !std::holds_alternative<nn::Memory>(requestInShared.pools.back())) {
+nn::GeneralResult<void> unflushDataFromSharedToPointer(
+ const nn::Request& request, const std::optional<nn::Request>& maybeRequestInShared) {
+ if (!maybeRequestInShared.has_value() || maybeRequestInShared->pools.empty() ||
+ !std::holds_alternative<nn::Memory>(maybeRequestInShared->pools.back())) {
return {};
}
+ const auto& requestInShared = *maybeRequestInShared;
// Map the memory.
const auto& outputMemory = std::get<nn::Memory>(requestInShared.pools.back());
@@ -221,4 +248,67 @@
return nn::countNumberOfConsumers(numberOfOperands, operations);
}
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle) {
+ if (handle == nullptr) {
+ return {};
+ }
+
+ std::vector<base::unique_fd> fds;
+ fds.reserve(handle->fds.size());
+ for (const auto& fd : handle->fds) {
+ int dupFd = dup(fd);
+ if (dupFd == -1) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
+
+ native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size());
+ if (nativeHandle == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
+ }
+ for (size_t i = 0; i < fds.size(); ++i) {
+ nativeHandle->data[i] = fds[i].release();
+ }
+ std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]);
+
+ hidl_handle hidlHandle;
+ hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+ return hidlHandle;
+}
+
+nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
+ if (handle == nullptr) {
+ return nullptr;
+ }
+
+ std::vector<base::unique_fd> fds;
+ fds.reserve(handle->numFds);
+ for (int i = 0; i < handle->numFds; ++i) {
+ int dupFd = dup(handle->data[i]);
+ if (dupFd == -1) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
+
+ std::vector<int> ints(&handle->data[handle->numFds],
+ &handle->data[handle->numFds + handle->numInts]);
+
+ return std::make_shared<const nn::Handle>(nn::Handle{
+ .fds = std::move(fds),
+ .ints = std::move(ints),
+ });
+}
+
+nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
+ const std::vector<nn::SyncFence>& syncFences) {
+ hidl_vec<hidl_handle> handles(syncFences.size());
+ for (size_t i = 0; i < syncFences.size(); ++i) {
+ handles[i] =
+ NN_TRY(hal::utils::hidlHandleFromSharedHandle(syncFences[i].getSharedHandle()));
+ }
+ return handles;
+}
+
} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidBuffer.cpp b/neuralnetworks/utils/common/src/InvalidBuffer.cpp
new file mode 100644
index 0000000..c6f75d7
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidBuffer.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "InvalidBuffer.h"
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::Request::MemoryDomainToken InvalidBuffer::getToken() const {
+ return nn::Request::MemoryDomainToken{};
+}
+
+nn::GeneralResult<void> InvalidBuffer::copyTo(const nn::Memory& /*dst*/) const {
+ return NN_ERROR() << "InvalidBuffer";
+}
+
+nn::GeneralResult<void> InvalidBuffer::copyFrom(const nn::Memory& /*src*/,
+ const nn::Dimensions& /*dimensions*/) const {
+ return NN_ERROR() << "InvalidBuffer";
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidDevice.cpp b/neuralnetworks/utils/common/src/InvalidDevice.cpp
new file mode 100644
index 0000000..535ccb4
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidDevice.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "InvalidDevice.h"
+
+#include "InvalidBuffer.h"
+#include "InvalidPreparedModel.h"
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+InvalidDevice::InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
+ nn::DeviceType type, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities,
+ std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded)
+ : kName(std::move(name)),
+ kVersionString(std::move(versionString)),
+ kFeatureLevel(featureLevel),
+ kType(type),
+ kExtensions(std::move(extensions)),
+ kCapabilities(std::move(capabilities)),
+ kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded) {}
+
+const std::string& InvalidDevice::getName() const {
+ return kName;
+}
+
+const std::string& InvalidDevice::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version InvalidDevice::getFeatureLevel() const {
+ return kFeatureLevel;
+}
+
+nn::DeviceType InvalidDevice::getType() const {
+ return kType;
+}
+
+const std::vector<nn::Extension>& InvalidDevice::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& InvalidDevice::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> InvalidDevice::getNumberOfCacheFilesNeeded() const {
+ return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> InvalidDevice::wait() const {
+ return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<std::vector<bool>> InvalidDevice::getSupportedOperations(
+ const nn::Model& /*model*/) const {
+ return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> InvalidDevice::prepareModel(
+ const nn::Model& /*model*/, nn::ExecutionPreference /*preference*/,
+ nn::Priority /*priority*/, nn::OptionalTimePoint /*deadline*/,
+ const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> InvalidDevice::prepareModelFromCache(
+ nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedBuffer> InvalidDevice::allocate(
+ const nn::BufferDesc& /*desc*/,
+ const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+ const std::vector<nn::BufferRole>& /*inputRoles*/,
+ const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+ return NN_ERROR() << "InvalidDevice";
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
new file mode 100644
index 0000000..9ae7a63
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "InvalidPreparedModel.h"
+
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+InvalidPreparedModel::execute(const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
+ const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+ return NN_ERROR() << "InvalidPreparedModel";
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+InvalidPreparedModel::executeFenced(
+ const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+ nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+ const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+ return NN_ERROR() << "InvalidPreparedModel";
+}
+
+std::any InvalidPreparedModel::getUnderlyingResource() const {
+ return {};
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ProtectCallback.cpp b/neuralnetworks/utils/common/src/ProtectCallback.cpp
new file mode 100644
index 0000000..abe4cb6
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ProtectCallback.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "ProtectCallback.h"
+
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <android-base/thread_annotations.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/hal/HandleError.h>
+
+#include <algorithm>
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+void DeathRecipient::serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) {
+ std::lock_guard guard(mMutex);
+ std::for_each(mObjects.begin(), mObjects.end(),
+ [](IProtectedCallback* killable) { killable->notifyAsDeadObject(); });
+}
+
+void DeathRecipient::add(IProtectedCallback* killable) const {
+ CHECK(killable != nullptr);
+ std::lock_guard guard(mMutex);
+ mObjects.push_back(killable);
+}
+
+void DeathRecipient::remove(IProtectedCallback* killable) const {
+ CHECK(killable != nullptr);
+ std::lock_guard guard(mMutex);
+ const auto removedIter = std::remove(mObjects.begin(), mObjects.end(), killable);
+ mObjects.erase(removedIter);
+}
+
+nn::GeneralResult<DeathHandler> DeathHandler::create(sp<hidl::base::V1_0::IBase> object) {
+ if (object == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "utils::DeathHandler::create must have non-null object";
+ }
+ auto deathRecipient = sp<DeathRecipient>::make();
+
+ const auto ret = object->linkToDeath(deathRecipient, /*cookie=*/0);
+ const bool success = HANDLE_TRANSPORT_FAILURE(ret);
+ if (!success) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "IBase::linkToDeath returned false";
+ }
+
+ return DeathHandler(std::move(object), std::move(deathRecipient));
+}
+
+DeathHandler::DeathHandler(sp<hidl::base::V1_0::IBase> object, sp<DeathRecipient> deathRecipient)
+ : kObject(std::move(object)), kDeathRecipient(std::move(deathRecipient)) {
+ CHECK(kObject != nullptr);
+ CHECK(kDeathRecipient != nullptr);
+}
+
+DeathHandler::~DeathHandler() {
+ if (kObject != nullptr && kDeathRecipient != nullptr) {
+ const auto ret = kObject->unlinkToDeath(kDeathRecipient);
+ const auto maybeSuccess = handleTransportError(ret);
+ if (!maybeSuccess.has_value()) {
+ LOG(ERROR) << maybeSuccess.error().message;
+ } else if (!maybeSuccess.value()) {
+ LOG(ERROR) << "IBase::linkToDeath returned false";
+ }
+ }
+}
+
+[[nodiscard]] base::ScopeGuard<DeathHandler::Cleanup> DeathHandler::protectCallback(
+ IProtectedCallback* killable) const {
+ CHECK(killable != nullptr);
+ kDeathRecipient->add(killable);
+ return base::make_scope_guard(
+ [deathRecipient = kDeathRecipient, killable] { deathRecipient->remove(killable); });
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientBuffer.cpp b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
new file mode 100644
index 0000000..984295b
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "ResilientBuffer.h"
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::GeneralResult<std::shared_ptr<const ResilientBuffer>> ResilientBuffer::create(
+ Factory makeBuffer) {
+ if (makeBuffer == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "utils::ResilientBuffer::create must have non-empty makeBuffer";
+ }
+ auto buffer = NN_TRY(makeBuffer(/*blocking=*/true));
+ CHECK(buffer != nullptr);
+ return std::make_shared<const ResilientBuffer>(PrivateConstructorTag{}, std::move(makeBuffer),
+ std::move(buffer));
+}
+
+ResilientBuffer::ResilientBuffer(PrivateConstructorTag /*tag*/, Factory makeBuffer,
+ nn::SharedBuffer buffer)
+ : kMakeBuffer(std::move(makeBuffer)), mBuffer(std::move(buffer)) {
+ CHECK(kMakeBuffer != nullptr);
+ CHECK(mBuffer != nullptr);
+}
+
+nn::SharedBuffer ResilientBuffer::getBuffer() const {
+ std::lock_guard guard(mMutex);
+ return mBuffer;
+}
+nn::SharedBuffer ResilientBuffer::recover(const nn::IBuffer* /*failingBuffer*/,
+ bool /*blocking*/) const {
+ std::lock_guard guard(mMutex);
+ return mBuffer;
+}
+
+nn::Request::MemoryDomainToken ResilientBuffer::getToken() const {
+ return getBuffer()->getToken();
+}
+
+nn::GeneralResult<void> ResilientBuffer::copyTo(const nn::Memory& dst) const {
+ return getBuffer()->copyTo(dst);
+}
+
+nn::GeneralResult<void> ResilientBuffer::copyFrom(const nn::Memory& src,
+ const nn::Dimensions& dimensions) const {
+ return getBuffer()->copyFrom(src, dimensions);
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientDevice.cpp b/neuralnetworks/utils/common/src/ResilientDevice.cpp
new file mode 100644
index 0000000..2f83c5c
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientDevice.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "ResilientDevice.h"
+
+#include "InvalidBuffer.h"
+#include "InvalidDevice.h"
+#include "InvalidPreparedModel.h"
+#include "ResilientBuffer.h"
+#include "ResilientPreparedModel.h"
+
+#include <android-base/logging.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+namespace {
+
+template <typename FnType>
+auto protect(const ResilientDevice& resilientDevice, const FnType& fn, bool blocking)
+ -> decltype(fn(*resilientDevice.getDevice())) {
+ auto device = resilientDevice.getDevice();
+ auto result = fn(*device);
+
+ // Immediately return if device is not dead.
+ if (result.has_value() || result.error().code != nn::ErrorStatus::DEAD_OBJECT) {
+ return result;
+ }
+
+ device = resilientDevice.recover(device.get(), blocking);
+ return fn(*device);
+}
+
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const ResilientDevice>> ResilientDevice::create(
+ Factory makeDevice) {
+ if (makeDevice == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "utils::ResilientDevice::create must have non-empty makeDevice";
+ }
+ auto device = NN_TRY(makeDevice(/*blocking=*/true));
+ CHECK(device != nullptr);
+
+ auto name = device->getName();
+ auto versionString = device->getVersionString();
+ auto extensions = device->getSupportedExtensions();
+ auto capabilities = device->getCapabilities();
+
+ return std::make_shared<ResilientDevice>(PrivateConstructorTag{}, std::move(makeDevice),
+ std::move(name), std::move(versionString),
+ std::move(extensions), std::move(capabilities),
+ std::move(device));
+}
+
+ResilientDevice::ResilientDevice(PrivateConstructorTag /*tag*/, Factory makeDevice,
+ std::string name, std::string versionString,
+ std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities, nn::SharedDevice device)
+ : kMakeDevice(std::move(makeDevice)),
+ kName(std::move(name)),
+ kVersionString(std::move(versionString)),
+ kExtensions(std::move(extensions)),
+ kCapabilities(std::move(capabilities)),
+ mDevice(std::move(device)) {
+ CHECK(kMakeDevice != nullptr);
+ CHECK(mDevice != nullptr);
+}
+
+nn::SharedDevice ResilientDevice::getDevice() const {
+ std::lock_guard guard(mMutex);
+ return mDevice;
+}
+
+nn::SharedDevice ResilientDevice::recover(const nn::IDevice* failingDevice, bool blocking) const {
+ std::lock_guard guard(mMutex);
+
+ // Another caller updated the failing device.
+ if (mDevice.get() != failingDevice) {
+ return mDevice;
+ }
+
+ auto maybeDevice = kMakeDevice(blocking);
+ if (!maybeDevice.has_value()) {
+ const auto& [message, code] = maybeDevice.error();
+ LOG(ERROR) << "Failed to recover dead device with error " << code << ": " << message;
+ return mDevice;
+ }
+ auto device = std::move(maybeDevice).value();
+
+ // If recovered device has different metadata than what is cached (i.e., because it was
+ // updated), mark the device as invalid and preserve the cached data.
+ auto compare = [this, &device](auto fn) REQUIRES(mMutex) {
+ return std::invoke(fn, mDevice) != std::invoke(fn, device);
+ };
+ if (compare(&IDevice::getName) || compare(&IDevice::getVersionString) ||
+ compare(&IDevice::getFeatureLevel) || compare(&IDevice::getType) ||
+ compare(&IDevice::getSupportedExtensions) || compare(&IDevice::getCapabilities)) {
+ LOG(ERROR) << "Recovered device has different metadata than what is cached. Marking "
+ "IDevice object as invalid.";
+ device = std::make_shared<const InvalidDevice>(
+ kName, kVersionString, mDevice->getFeatureLevel(), mDevice->getType(), kExtensions,
+ kCapabilities, mDevice->getNumberOfCacheFilesNeeded());
+ mIsValid = false;
+ }
+
+ mDevice = std::move(device);
+ return mDevice;
+}
+
+const std::string& ResilientDevice::getName() const {
+ return kName;
+}
+
+const std::string& ResilientDevice::getVersionString() const {
+ return kVersionString;
+}
+
+nn::Version ResilientDevice::getFeatureLevel() const {
+ return getDevice()->getFeatureLevel();
+}
+
+nn::DeviceType ResilientDevice::getType() const {
+ return getDevice()->getType();
+}
+
+const std::vector<nn::Extension>& ResilientDevice::getSupportedExtensions() const {
+ return kExtensions;
+}
+
+const nn::Capabilities& ResilientDevice::getCapabilities() const {
+ return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> ResilientDevice::getNumberOfCacheFilesNeeded() const {
+ return getDevice()->getNumberOfCacheFilesNeeded();
+}
+
+nn::GeneralResult<void> ResilientDevice::wait() const {
+ const auto fn = [](const nn::IDevice& device) { return device.wait(); };
+ return protect(*this, fn, /*blocking=*/true);
+}
+
+nn::GeneralResult<std::vector<bool>> ResilientDevice::getSupportedOperations(
+ const nn::Model& model) const {
+ const auto fn = [&model](const nn::IDevice& device) {
+ return device.getSupportedOperations(model);
+ };
+ return protect(*this, fn, /*blocking=*/false);
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModel(
+ const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ auto self = shared_from_this();
+ ResilientPreparedModel::Factory makePreparedModel =
+ [device = std::move(self), model, preference, priority, deadline, modelCache, dataCache,
+ token](bool blocking) -> nn::GeneralResult<nn::SharedPreparedModel> {
+ return device->prepareModelInternal(blocking, model, preference, priority, deadline,
+ modelCache, dataCache, token);
+ };
+ return ResilientPreparedModel::create(std::move(makePreparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelFromCache(
+ nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ auto self = shared_from_this();
+ ResilientPreparedModel::Factory makePreparedModel =
+ [device = std::move(self), deadline, modelCache, dataCache,
+ token](bool blocking) -> nn::GeneralResult<nn::SharedPreparedModel> {
+ return device->prepareModelFromCacheInternal(blocking, deadline, modelCache, dataCache,
+ token);
+ };
+ return ResilientPreparedModel::create(std::move(makePreparedModel));
+}
+
+nn::GeneralResult<nn::SharedBuffer> ResilientDevice::allocate(
+ const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const {
+ auto self = shared_from_this();
+ ResilientBuffer::Factory makeBuffer =
+ [device = std::move(self), desc, preparedModels, inputRoles,
+ outputRoles](bool blocking) -> nn::GeneralResult<nn::SharedBuffer> {
+ return device->allocateInternal(blocking, desc, preparedModels, inputRoles, outputRoles);
+ };
+ return ResilientBuffer::create(std::move(makeBuffer));
+}
+
+bool ResilientDevice::isValidInternal() const {
+ std::lock_guard hold(mMutex);
+ return mIsValid;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelInternal(
+ bool blocking, const nn::Model& model, nn::ExecutionPreference preference,
+ nn::Priority priority, nn::OptionalTimePoint deadline,
+ const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ if (!isValidInternal()) {
+ return std::make_shared<const InvalidPreparedModel>();
+ }
+ const auto fn = [&model, preference, priority, deadline, &modelCache, &dataCache,
+ token](const nn::IDevice& device) {
+ return device.prepareModel(model, preference, priority, deadline, modelCache, dataCache,
+ token);
+ };
+ return protect(*this, fn, blocking);
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelFromCacheInternal(
+ bool blocking, nn::OptionalTimePoint deadline,
+ const std::vector<nn::SharedHandle>& modelCache,
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ if (!isValidInternal()) {
+ return std::make_shared<const InvalidPreparedModel>();
+ }
+ const auto fn = [deadline, &modelCache, &dataCache, token](const nn::IDevice& device) {
+ return device.prepareModelFromCache(deadline, modelCache, dataCache, token);
+ };
+ return protect(*this, fn, blocking);
+}
+
+nn::GeneralResult<nn::SharedBuffer> ResilientDevice::allocateInternal(
+ bool blocking, const nn::BufferDesc& desc,
+ const std::vector<nn::SharedPreparedModel>& preparedModels,
+ const std::vector<nn::BufferRole>& inputRoles,
+ const std::vector<nn::BufferRole>& outputRoles) const {
+ if (!isValidInternal()) {
+ return std::make_shared<const InvalidBuffer>();
+ }
+ const auto fn = [&desc, &preparedModels, &inputRoles, &outputRoles](const nn::IDevice& device) {
+ return device.allocate(desc, preparedModels, inputRoles, outputRoles);
+ };
+ return protect(*this, fn, blocking);
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
new file mode 100644
index 0000000..1c9ecba
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "ResilientPreparedModel.h"
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::GeneralResult<std::shared_ptr<const ResilientPreparedModel>> ResilientPreparedModel::create(
+ Factory makePreparedModel) {
+ if (makePreparedModel == nullptr) {
+ return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+ << "utils::ResilientPreparedModel::create must have non-empty makePreparedModel";
+ }
+ auto preparedModel = NN_TRY(makePreparedModel(/*blocking=*/true));
+ CHECK(preparedModel != nullptr);
+ return std::make_shared<ResilientPreparedModel>(
+ PrivateConstructorTag{}, std::move(makePreparedModel), std::move(preparedModel));
+}
+
+ResilientPreparedModel::ResilientPreparedModel(PrivateConstructorTag /*tag*/,
+ Factory makePreparedModel,
+ nn::SharedPreparedModel preparedModel)
+ : kMakePreparedModel(std::move(makePreparedModel)), mPreparedModel(std::move(preparedModel)) {
+ CHECK(kMakePreparedModel != nullptr);
+ CHECK(mPreparedModel != nullptr);
+}
+
+nn::SharedPreparedModel ResilientPreparedModel::getPreparedModel() const {
+ std::lock_guard guard(mMutex);
+ return mPreparedModel;
+}
+
+nn::SharedPreparedModel ResilientPreparedModel::recover(
+ const nn::IPreparedModel* /*failingPreparedModel*/, bool /*blocking*/) const {
+ std::lock_guard guard(mMutex);
+ return mPreparedModel;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+ResilientPreparedModel::execute(const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration) const {
+ return getPreparedModel()->execute(request, measure, deadline, loopTimeoutDuration);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+ResilientPreparedModel::executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+ const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const {
+ return getPreparedModel()->executeFenced(request, waitFor, measure, deadline,
+ loopTimeoutDuration, timeoutDurationAfterFence);
+}
+
+std::any ResilientPreparedModel::getUnderlyingResource() const {
+ return getPreparedModel()->getUnderlyingResource();
+}
+
+} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
new file mode 100644
index 0000000..402598c
--- /dev/null
+++ b/neuralnetworks/utils/service/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_library_static {
+ name: "neuralnetworks_utils_hal_service",
+ defaults: ["neuralnetworks_utils_defaults"],
+ srcs: ["src/*"],
+ local_include_dirs: ["include/nnapi/hal"],
+ export_include_dirs: ["include"],
+ static_libs: [
+ "neuralnetworks_types",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
+ "neuralnetworks_utils_hal_1_2",
+ "neuralnetworks_utils_hal_1_3",
+ "neuralnetworks_utils_hal_common",
+ ],
+ shared_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
+ "android.hardware.neuralnetworks@1.3",
+ ],
+}
diff --git a/neuralnetworks/utils/service/include/nnapi/hal/Service.h b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
new file mode 100644
index 0000000..e339627
--- /dev/null
+++ b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+#include <memory>
+#include <vector>
+
+namespace android::nn::hal {
+
+std::vector<nn::SharedDevice> getDevices();
+
+} // namespace android::nn::hal
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
new file mode 100644
index 0000000..a59549d
--- /dev/null
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "Service.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Service.h>
+#include <nnapi/hal/1.1/Service.h>
+#include <nnapi/hal/1.2/Service.h>
+#include <nnapi/hal/1.3/Service.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::service {
+namespace {
+
+using getDeviceFn = std::add_pointer_t<nn::GeneralResult<nn::SharedDevice>(const std::string&)>;
+
+void getDevicesForVersion(const std::string& descriptor, getDeviceFn getDevice,
+ std::vector<nn::SharedDevice>* devices,
+ std::unordered_set<std::string>* registeredDevices) {
+ CHECK(devices != nullptr);
+ CHECK(registeredDevices != nullptr);
+
+ const auto names = getAllHalInstanceNames(descriptor);
+ for (const auto& name : names) {
+ if (const auto [it, unregistered] = registeredDevices->insert(name); unregistered) {
+ auto maybeDevice = getDevice(name);
+ if (maybeDevice.has_value()) {
+ auto device = std::move(maybeDevice).value();
+ CHECK(device != nullptr);
+ devices->push_back(std::move(device));
+ } else {
+ LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
+ << ": " << maybeDevice.error().message;
+ }
+ }
+ }
+}
+
+std::vector<nn::SharedDevice> getDevices() {
+ std::vector<nn::SharedDevice> devices;
+ std::unordered_set<std::string> registeredDevices;
+
+ getDevicesForVersion(V1_3::IDevice::descriptor, &V1_3::utils::getDevice, &devices,
+ ®isteredDevices);
+ getDevicesForVersion(V1_2::IDevice::descriptor, &V1_2::utils::getDevice, &devices,
+ ®isteredDevices);
+ getDevicesForVersion(V1_1::IDevice::descriptor, &V1_1::utils::getDevice, &devices,
+ ®isteredDevices);
+ getDevicesForVersion(V1_0::IDevice::descriptor, &V1_0::utils::getDevice, &devices,
+ ®isteredDevices);
+
+ return devices;
+}
+
+} // namespace
+} // namespace android::hardware::neuralnetworks::service
+
+namespace android::nn::hal {
+
+std::vector<nn::SharedDevice> getDevices() {
+ return hardware::neuralnetworks::service::getDevices();
+}
+
+} // namespace android::nn::hal
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index 91709fa..4566558 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -114,6 +114,9 @@
* addresses of the existing data connection. The format is defined in RFC-4291 section 2.2.
* For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless reason
* is DataRequestReason:HANDOVER.
+ * @param pduSessionId The pdu session id to be used for this data call. A value of 0 means
+ * no pdu session id was attached to this call.
+ * Reference: 3GPP TS 24.007 section 11.2.3.1b
*
* Response function is IRadioResponse.setupDataCallResponse_1_6()
*
@@ -121,7 +124,8 @@
*/
oneway setupDataCall_1_6(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
- DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
+ DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses,
+ int32_t pduSessionId);
/**
* Send an SMS message
@@ -213,6 +217,13 @@
* Each subsequent request to this method is processed only after the
* completion of the previous one.
*
+ * When the SIM is in POWER_DOWN, the modem should send an empty vector of
+ * AppStatus in CardStatus.applications. If a SIM in the POWER_DOWN state
+ * is removed and a new SIM is inserted, the new SIM should be in POWER_UP
+ * mode by default. If the device is turned off or restarted while the SIM
+ * is in POWER_DOWN, then the SIM should turn on normally in POWER_UP mode
+ * when the device turns back on.
+ *
* Response callback is IRadioResponse.setSimCardPowerResponse_1_6().
* Note that this differs from setSimCardPower_1_1 in that the response
* callback should only be sent once the device has finished executing
@@ -290,12 +301,12 @@
* @param serial Serial number of request.
* @param id callId The identifier of the data call which is provided in SetupDataCallResult
*
- * Response function is IRadioResponse.beginHandoverResponse()
+ * Response function is IRadioResponse.startHandoverResponse()
*/
- oneway beginHandover(int32_t serial, int32_t callId);
+ oneway startHandover(int32_t serial, int32_t callId);
/**
- * Indicates that a handover was cancelled after a call to IRadio::beginHandover.
+ * Indicates that a handover was cancelled after a call to IRadio::startHandover.
*
* Since the handover was unsuccessful, the modem retains ownership over any of the resources
* being transferred and is still responsible for releasing them.
@@ -316,12 +327,26 @@
* @param serial Serial number of request.
* @param networkTypeBitmap a 32-bit bearer bitmap of RadioAccessFamily
*
- * Response callbask is IRadioResponse.setNetworkTypeBitmapResponse()
+ * Response callback is IRadioResponse.setNetworkTypeBitmapResponse()
*/
oneway setAllowedNetworkTypeBitmap(
uint32_t serial, bitfield<RadioAccessFamily> networkTypeBitmap);
/**
+ * Requests bitmap representing the currently allowed network types.
+ *
+ * Requests the bitmap set by the corresponding method
+ * setAllowedNetworkTypeBitmap, which sets a strict set of RATs for the
+ * radio to use. Differs from getPreferredNetworkType and getPreferredNetworkTypeBitmap
+ * in that those request *preferences*.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getNetworkTypeBitmapResponse()
+ */
+ oneway getAllowedNetworkTypeBitmap(uint32_t serial);
+
+ /**
* Control data throttling at modem.
* - DataThrottlingAction:NO_DATA_THROTTLING should clear any existing
* data throttling within the requested completion window.
@@ -336,13 +361,63 @@
*
* @param serial Serial number of request.
* @param dataThrottlingAction DataThrottlingAction as defined in types.hal
- * @param completionWindowSecs window, in seconds, in which the requested
- * throttling action has to be achieved. This must be 0 when
+ * @param completionDurationMillis window, in milliseconds, in which the
+ * requested throttling action has to be achieved. This must be 0 when
* dataThrottlingAction is DataThrottlingAction:HOLD.
*
* Response function is IRadioResponse.setDataThrottlingResponse()
*/
oneway setDataThrottling(int32_t serial,
DataThrottlingAction dataThrottlingAction,
- int32_t completionWindowSecs);
+ int64_t completionDurationMillis);
+
+ /**
+ * Get which bands the modem's background scan is acting on.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getSystemSelectionChannelsResponse()
+ */
+ oneway getSystemSelectionChannels(int32_t serial);
+
+ /**
+ * Request all of the current cell information known to the radio. The radio
+ * must return list of all current cells, including the neighboring cells. If for a particular
+ * cell information isn't known then the appropriate unknown value will be returned.
+ * This does not cause or change the rate of unsolicited cellInfoList().
+ *
+ * This is identitcal to getCellInfoList in V1.0, but it requests updated version of CellInfo.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getCellInfoListResponse()
+ */
+ oneway getCellInfoList_1_6(int32_t serial);
+
+ /**
+ * Request current voice registration state.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response function is IRadioResponse.getVoiceRegistrationStateResponse_1_6()
+ */
+ oneway getVoiceRegistrationState_1_6(int32_t serial);
+
+ /**
+ * Requests current signal strength and associated information. Must succeed if radio is on.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response function is IRadioResponse.getSignalStrengthResponse_1_6()
+ */
+ oneway getSignalStrength_1_6(int32_t serial);
+
+ /**
+ * Request current data registration state.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response function is IRadioResponse.getDataRegistrationStateResponse_1_6()
+ */
+ oneway getDataRegistrationState_1_6(int32_t serial);
};
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index f195c0e..1b56d40 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -18,8 +18,11 @@
import @1.0::RadioIndicationType;
import @1.5::IRadioIndication;
-import @1.6::SetupDataCallResult;
+import @1.6::CellInfo;
import @1.6::LinkCapacityEstimate;
+import @1.6::NetworkScanResult;
+import @1.6::SignalStrength;
+import @1.6::SetupDataCallResult;
/**
* Interface declaring unsolicited radio indications.
@@ -67,4 +70,35 @@
* @param lce LinkCapacityEstimate
*/
oneway currentLinkCapacityEstimate_1_6(RadioIndicationType type, LinkCapacityEstimate lce);
+
+
+ /**
+ * Indicates current signal strength of the radio.
+ *
+ * This is identical to currentSignalStrength_1_4 but uses an updated version of
+ * SignalStrength.
+ *
+ * @param type Type of radio indication
+ * @param signalStrength SignalStrength information
+ */
+ oneway currentSignalStrength_1_6(RadioIndicationType type, SignalStrength signalStrength);
+
+ /**
+ * Report all of the current cell information known to the radio.
+ *
+ * This indication is updated from IRadioIndication@1.5 to report the @1.6 version of
+ * CellInfo.
+ *
+ * @param type Type of radio indication
+ * @param records Current cell information
+ */
+ oneway cellInfoList_1_6(RadioIndicationType type, vec<CellInfo> records);
+
+ /**
+ * Incremental network scan results.
+ *
+ * This indication is updated from IRadioIndication@1.5 to report the @1.6 version of
+ * CellInfo.
+ */
+ oneway networkScanResult_1_6(RadioIndicationType type, NetworkScanResult result);
};
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index acae5c7..f13ee2b 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -17,9 +17,13 @@
package android.hardware.radio@1.6;
import @1.0::SendSmsResult;
-import @1.6::RadioResponseInfo;
+import @1.4::RadioAccessFamily;
import @1.5::IRadioResponse;
+import @1.6::CellInfo;
+import @1.6::RegStateResult;
+import @1.6::RadioResponseInfo;
import @1.6::SetupDataCallResult;
+import @1.6::SignalStrength;
/**
* Interface declaring response functions to solicited radio requests.
@@ -207,7 +211,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:SIM_ERR (indicates a timeout or other issue making the SIM unresponsive)
*
@@ -241,7 +244,7 @@
/**
* @param info Response info struct containing response type, serial no. and error
- * @param id The allocated id. On an error, this is set to -1
+ * @param id The allocated id. On an error, this is set to 0.
*
* Valid errors returned:
* RadioError:NONE
@@ -275,7 +278,7 @@
* RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_CALL_ID
*/
- oneway beginHandoverResponse(RadioResponseInfo info);
+ oneway startHandoverResponse(RadioResponseInfo info);
/**
* @param info Response info struct containing response type, serial no. and error
@@ -308,6 +311,23 @@
oneway setAllowedNetworkTypeBitmapResponse(RadioResponseInfo info);
/**
+ * Callback of IRadio.getAllowedNetworkTypeBitmap(int, bitfield<RadioAccessFamily>)
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:OPERATION_NOT_ALLOWED
+ * RadioError:MODE_NOT_SUPPORTED
+ * RadioError:INTERNAL_ERR
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:MODEM_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:NO_RESOURCES
+ */
+ oneway getAllowedNetworkTypeBitmapResponse(
+ RadioResponseInfo info, bitfield<RadioAccessFamily> networkTypeBitmap);
+
+ /**
* @param info Response info struct containing response type, serial no. and error
*
* Valid errors returned:
@@ -317,4 +337,68 @@
* RadioError:INVALID_ARGUMENTS
*/
oneway setDataThrottlingResponse(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ oneway getSystemSelectionChannelsResponse(RadioResponseInfo info);
+
+ /**
+ * This is identical to getCellInfoListResponse_1_5 but uses an updated version of CellInfo.
+ *
+ * @param info Response info struct containing response type, serial no. and error
+ * @param cellInfo List of current cell information known to radio
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getCellInfoListResponse_1_6(RadioResponseInfo info, vec<CellInfo> cellInfo);
+
+ /**
+ * This is identical to getSignalStrengthResponse_1_4 but uses an updated version of
+ * SignalStrength.
+ *
+ * @param signalStrength Current signal strength
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getSignalStrengthResponse_1_6(RadioResponseInfo info, SignalStrength signalStrength);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param voiceRegResponse Current Voice registration response as defined by RegStateResult
+ * in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getVoiceRegistrationStateResponse_1_6(RadioResponseInfo info,
+ RegStateResult voiceRegResponse);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param dataRegResponse Current Data registration response as defined by RegStateResult in
+ * types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NOT_PROVISIONED
+ */
+ oneway getDataRegistrationStateResponse_1_6(RadioResponseInfo info,
+ RegStateResult dataRegResponse);
};
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index 2cba915..20dc612 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -16,12 +16,35 @@
package android.hardware.radio@1.6;
+import @1.0::CdmaSignalStrength;
+import @1.0::EvdoSignalStrength;
+import @1.0::GsmSignalStrength;
+import @1.0::LteSignalStrength;
import @1.0::RadioError;
import @1.0::RadioResponseType;
+import @1.0::RegState;
+import @1.1::ScanStatus;
+import @1.2::CellInfoCdma;
+import @1.2::CellConnectionStatus;
+import @1.2::TdscdmaSignalStrength;
+import @1.2::WcdmaSignalStrength;
import @1.4::DataCallFailCause;
import @1.4::DataConnActiveStatus;
+import @1.4::NrSignalStrength;
import @1.4::PdpProtocolType;
+import @1.4::RadioTechnology;
+import @1.5::CellIdentity;
+import @1.5::CellIdentityLte;
+import @1.5::CellIdentityNr;
+import @1.5::CellInfoGsm;
+import @1.5::CellInfoWcdma;
+import @1.5::CellInfoTdscdma;
import @1.5::LinkAddress;
+import @1.5::RegStateResult.AccessTechnologySpecificInfo.Cdma2000RegistrationInfo;
+import @1.5::RegStateResult.AccessTechnologySpecificInfo.EutranRegistrationInfo;
+import @1.5::RegistrationFailCause;
+import @1.5::SetupDataCallResult;
+
import android.hidl.safe_union@1.0::Monostate;
struct QosBandwidth {
@@ -416,3 +439,287 @@
*/
HOLD = 3
};
+
+/**
+ * Defines the values for VoPS indicator of NR as per 3gpp spec 24.501 sec 9.10.3.5
+ */
+enum VopsIndicator : uint8_t {
+ /** IMS voice over PS session not supported */
+ VOPS_NOT_SUPPORTED = 0,
+ /** IMS voice over PS session supported over 3GPP access */
+ VOPS_OVER_3GPP = 1,
+ /** IMS voice over PS session supported over non-3GPP access */
+ VOPS_OVER_NON_3GPP = 2,
+};
+
+/**
+ * Defines the values for emergency service indicator of NR
+ * as per 3gpp spec 24.501 sec 9.10.3.5
+ */
+enum EmcIndicator : uint8_t {
+ /** Emergency services not supported */
+ EMC_NOT_SUPPORTED = 0,
+ /** Emergency services supported in NR connected to 5GCN only */
+ EMC_NR_CONNECTED_TO_5GCN = 1,
+ /** Emergency services supported in E-UTRA connected to 5GCN only */
+ EMC_EUTRA_CONNECTED_TO_5GCN = 2,
+ /** Emergency services supported in NR connected to 5GCN and E-UTRA connected to 5GCN */
+ EMC_BOTH_NR_EUTRA_CONNECTED_TO_5GCN = 3
+};
+
+/**
+ * Defines the values for emergency service fallback indicator of NR
+ * as per 3gpp spec 24.501 sec 9.10.3.5
+ */
+enum EmfIndicator : uint8_t {
+ /** Emergency services fallback not supported */
+ EMF_NOT_SUPPORTED = 0,
+ /** Emergency services fallback supported in NR connected to 5GCN only */
+ EMF_NR_CONNECTED_TO_5GCN = 1,
+ /** Emergency services fallback supported in E-UTRA connected to 5GCN only */
+ EMF_EUTRA_CONNECTED_TO_5GCN = 2,
+ /**
+ * Emergency services fallback supported in NR connected to 5GCN and E-UTRA
+ * connected to 5GCN.
+ */
+ EMF_BOTH_NR_EUTRA_CONNECTED_TO_5GCN = 3
+};
+
+/**
+ * Type to define the NR specific network capabilities for voice over PS including
+ * emergency and normal voice calls.
+ */
+struct NrVopsInfo {
+ /**
+ * This indicates if the camped network supports VoNR services, and what kind of services
+ * it supports. This information is received from NR network during NR NAS registration
+ * procedure through NR REGISTRATION ACCEPT.
+ * Refer 3GPP 24.501 EPS 5GS network feature support -> IMS VoPS
+ */
+ VopsIndicator vopsSupported;
+
+ /**
+ * This indicates if the camped network supports VoNR emergency service. This information
+ * is received from NR network through two sources:
+ * a. During NR NAS registration procedure through NR REGISTRATION ACCEPT.
+ * Refer 3GPP 24.501 EPS 5GS network feature support -> EMC
+ * b. In case the device is not registered on the network.
+ * Refer 3GPP 38.331 SIB1 : ims-EmergencySupport
+ * If device is registered on NR, then this field indicates whether the cell
+ * supports IMS emergency bearer services for UEs in limited service mode.
+ */
+ EmcIndicator emcSupported;
+
+ /**
+ * This indicates if the camped network supports VoNR emergency service fallback. This
+ * information is received from NR network during NR NAS registration procedure through
+ * NR REGISTRATION ACCEPT.
+ * Refer 3GPP 24.501 EPS 5GS network feature support -> EMF
+ */
+ EmfIndicator emfSupported;
+};
+
+struct LteSignalStrength {
+ @1.0::LteSignalStrength base;
+
+ /**
+ * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+ * The definition of CQI in each table is different.
+ *
+ * Reference: 3GPP TS 136.213 section 7.2.3.
+ *
+ * Range [1, 6], INT_MAX means invalid/unreported.
+ */
+ uint32_t cqiTableIndex;
+};
+
+struct NrSignalStrength {
+ @1.4::NrSignalStrength base;
+
+ /**
+ * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+ * The definition of CQI in each table is different.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [1, 3], INT_MAX means invalid/unreported.
+ */
+ uint32_t csiCqiTableIndex;
+
+ /**
+ * CSI channel quality indicator (CQI) for all subbands.
+ *
+ * If the CQI report is for the entire wideband, a single CQI index is provided.
+ * If the CQI report is for all subbands, one CQI index is provided for each subband,
+ * in ascending order of subband index.
+ * If CQI is not available, the CQI report is empty.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [0, 15], INT_MAX means invalid/unreported.
+ */
+ vec<uint32_t> csiCqiReport;
+};
+
+/**
+ * Overwritten from @1.4::SignalStrength in order to update LteSignalStrength and NrSignalStrength.
+ */
+struct SignalStrength {
+ /**
+ * If GSM measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ GsmSignalStrength gsm;
+
+ /**
+ * If CDMA measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ CdmaSignalStrength cdma;
+
+ /**
+ * If EvDO measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ EvdoSignalStrength evdo;
+
+ /**
+ * If LTE measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ LteSignalStrength lte;
+
+ /**
+ * If TD-SCDMA measurements are provided, this structure must contain valid measurements;
+ * otherwise all fields should be set to INT_MAX to mark them as invalid.
+ */
+ TdscdmaSignalStrength tdscdma;
+
+ /**
+ * If WCDMA measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ WcdmaSignalStrength wcdma;
+
+ /**
+ * If NR 5G measurements are provided, this structure must contain valid measurements; otherwise
+ * all fields should be set to INT_MAX to mark them as invalid.
+ */
+ NrSignalStrength nr;
+};
+
+/** Overwritten from @1.5::CellInfoLte in order to update LteSignalStrength. */
+struct CellInfoLte {
+ CellIdentityLte cellIdentityLte;
+ LteSignalStrength signalStrengthLte;
+};
+
+/** Overwritten from @1.5::CellInfoNr in order to update NrSignalStrength. */
+struct CellInfoNr {
+ CellIdentityNr cellIdentityNr;
+ NrSignalStrength signalStrengthNr;
+};
+
+/** Overwritten from @1.5::CellInfo in order to update LteSignalStrength and NrSignalStrength. */
+struct CellInfo {
+ /**
+ * True if this cell is registered false if not registered.
+ */
+ bool registered;
+ /**
+ * Connection status for the cell.
+ */
+ CellConnectionStatus connectionStatus;
+
+ safe_union CellInfoRatSpecificInfo {
+ /**
+ * 3gpp CellInfo types.
+ */
+ CellInfoGsm gsm;
+ CellInfoWcdma wcdma;
+ CellInfoTdscdma tdscdma;
+ CellInfoLte lte;
+ CellInfoNr nr;
+
+ /**
+ * 3gpp2 CellInfo types;
+ */
+ CellInfoCdma cdma;
+ } ratSpecificInfo;
+};
+
+/** Overwritten from @1.5::NetworkScanResult in order to update the CellInfo to 1.6 version. */
+struct NetworkScanResult {
+ /**
+ * The status of the scan.
+ */
+ ScanStatus status;
+
+ /**
+ * The error code of the incremental result.
+ */
+ RadioError error;
+
+ /**
+ * List of network information as CellInfo.
+ */
+ vec<CellInfo> networkInfos;
+};
+
+/**
+ * Overwritten from @1.5::RegStateResult to 1.6 to support NrRegistrationInfo
+ * version.
+ */
+struct RegStateResult {
+ /**
+ * Registration state
+ *
+ * If the RAT is indicated as a GERAN, UTRAN, or CDMA2000 technology, this value reports
+ * registration in the Circuit-switched domain.
+ * If the RAT is indicated as an EUTRAN, NGRAN, or another technology that does not support
+ * circuit-switched services, this value reports registration in the Packet-switched domain.
+ */
+ RegState regState;
+
+ /**
+ * Indicates the available voice radio technology, valid values as
+ * defined by RadioTechnology.
+ */
+ RadioTechnology rat;
+
+ /**
+ * Cause code reported by the network in case registration fails. This will be a mobility
+ * management cause code defined for MM, GMM, MME or equivalent as appropriate for the RAT.
+ */
+ RegistrationFailCause reasonForDenial;
+
+ /** CellIdentity */
+ CellIdentity cellIdentity;
+
+ /**
+ * The most-recent PLMN-ID upon which the UE registered (or attempted to register if a failure
+ * is reported in the reasonForDenial field). This PLMN shall be in standard format consisting
+ * of a 3 digit MCC concatenated with a 2 or 3 digit MNC.
+ */
+ string registeredPlmn;
+
+ /**
+ * Access-technology-specific registration information, such as for CDMA2000.
+ */
+ safe_union AccessTechnologySpecificInfo {
+ Monostate noinit;
+
+ Cdma2000RegistrationInfo cdmaInfo;
+
+ EutranRegistrationInfo eutranInfo;
+
+ struct NgranRegistrationInfo {
+ /**
+ * Network capabilities for voice over PS services. This info is valid only on NR
+ * network and must be present when the device is camped on NR. VopsInfo must be
+ * empty when the device is not camped on NR.
+ */
+ NrVopsInfo nrVopsInfo;
+ } ngranInfo;
+ } accessTechnologySpecificInfo;
+};
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index ac84417..75772cd 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -57,7 +57,7 @@
::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
Return<void> res = radio_v1_6->setupDataCall_1_6(serial, accessNetwork, dataProfileInfo,
- roamingAllowed, reason, addresses, dnses);
+ roamingAllowed, reason, addresses, dnses, -1);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -303,7 +303,7 @@
serial = GetRandomSerialNumber();
Return<void> res = radio_v1_6->setDataThrottling(
- serial, DataThrottlingAction::THROTTLE_SECONDARY_CARRIER, 60);
+ serial, DataThrottlingAction::THROTTLE_SECONDARY_CARRIER, 60000);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -318,7 +318,22 @@
serial = GetRandomSerialNumber();
- res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER, 60);
+ res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER,
+ 60000);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+ ::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+
+ serial = GetRandomSerialNumber();
+
+ res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::HOLD, 60000);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -333,9 +348,8 @@
serial = GetRandomSerialNumber();
- res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::HOLD, 60);
+ res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60000);
ASSERT_OK(res);
-
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
@@ -345,19 +359,50 @@
::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
::android::hardware::radio::V1_6::RadioError::NONE,
::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+}
+/*
+ * Test IRadio.setSimCardPower_1_6() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setSimCardPower_1_6) {
+ /* Test setSimCardPower power down */
serial = GetRandomSerialNumber();
-
- res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60);
- ASSERT_OK(res);
-
+ radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_DOWN);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
- {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
- ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
- ::android::hardware::radio::V1_6::RadioError::NONE,
- ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
-}
\ No newline at end of file
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+ // setSimCardPower_1_6 does not return until the request is handled, and should not trigger
+ // CardState::ABSENT when turning off power
+ if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+ /* Wait some time for setting sim power down and then verify it */
+ updateSimCardStatus();
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
+ // applications should be an empty vector of AppStatus
+ EXPECT_EQ(0, cardStatus.applications.size());
+ }
+
+ /* Test setSimCardPower power up */
+ serial = GetRandomSerialNumber();
+ radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_UP);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+ // setSimCardPower_1_6 does not return until the request is handled. Just verify that we still
+ // have CardState::PRESENT after turning the power back on
+ if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+ updateSimCardStatus();
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
+ }
+}
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index 31bb1d7..ab56540 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -784,7 +784,7 @@
Return<void> releasePduSessionIdResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
- Return<void> beginHandoverResponse(
+ Return<void> startHandoverResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
Return<void> cancelHandoverResponse(
@@ -793,8 +793,34 @@
Return<void> setAllowedNetworkTypeBitmapResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+ Return<void> getAllowedNetworkTypeBitmapResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmap);
+
Return<void> setDataThrottlingResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+ Return<void> getSystemSelectionChannelsResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+ Return<void> getSignalStrengthResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_6::SignalStrength& sig_strength);
+
+ Return<void> getCellInfoListResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_6::CellInfo>&
+ cellInfo);
+
+ Return<void> getVoiceRegistrationStateResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_6::RegStateResult& regResponse);
+
+ Return<void> getDataRegistrationStateResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_6::RegStateResult& regResponse);
};
/* Callback class for radio indication */
@@ -814,6 +840,19 @@
Return<void> unthrottleApn(RadioIndicationType type,
const ::android::hardware::hidl_string& apn);
+ Return<void> currentSignalStrength_1_6(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_6::SignalStrength& signalStrength);
+
+ Return<void> networkScanResult_1_6(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_6::NetworkScanResult& result);
+
+ Return<void> cellInfoList_1_6(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_6::CellInfo>&
+ records);
+
/* 1.5 Api */
Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
diff --git a/radio/1.6/vts/functional/radio_indication.cpp b/radio/1.6/vts/functional/radio_indication.cpp
index afde291..bfc54c0 100644
--- a/radio/1.6/vts/functional/radio_indication.cpp
+++ b/radio/1.6/vts/functional/radio_indication.cpp
@@ -386,3 +386,22 @@
const ::android::hardware::hidl_string& /*reason*/) {
return Void();
}
+
+Return<void> RadioIndication_v1_6::currentSignalStrength_1_6(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_6::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_6::networkScanResult_1_6(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_6::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_6::cellInfoList_1_6(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_6::CellInfo>& /*records*/) {
+ return Void();
+}
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index 09a2bac..e37efdd 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -808,12 +808,6 @@
return Void();
}
-Return<void> RadioResponse_v1_6::getSignalStrengthResponse_1_4(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
- const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
- return Void();
-}
-
Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_2(
const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
const ::android::hardware::hidl_vec<
@@ -867,6 +861,12 @@
return Void();
}
+Return<void> RadioResponse_v1_6::getSignalStrengthResponse_1_4(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
+ return Void();
+}
+
Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_4(
const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
const ::android::hardware::hidl_vec<
@@ -1136,7 +1136,7 @@
return Void();
}
-Return<void> RadioResponse_v1_6::beginHandoverResponse(
+Return<void> RadioResponse_v1_6::startHandoverResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
rspInfo = info;
parent_v1_6.notify(info.serial);
@@ -1157,9 +1157,53 @@
return Void();
}
+Return<void> RadioResponse_v1_6::getAllowedNetworkTypeBitmapResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ /*networkTypeBitmap*/) {
+ return Void();
+}
+
Return<void> RadioResponse_v1_6::setDataThrottlingResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
rspInfo = info;
parent_v1_6.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_6::getSignalStrengthResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_6::SignalStrength& /*sig_strength*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_6::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_6::getSystemSelectionChannelsResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_6.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_6::getVoiceRegistrationStateResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_6::RegStateResult& /*regResponse*/) {
+ rspInfo = info;
+ parent_v1_6.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_6::getDataRegistrationStateResponse_1_6(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_6::RegStateResult& /*regResponse*/) {
+ rspInfo = info;
+ parent_v1_6.notify(info.serial);
+ return Void();
+}
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
new file mode 100644
index 0000000..ace0de9
--- /dev/null
+++ b/radio/config/1.3/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.radio.config@1.3",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IRadioConfig.hal",
+ "IRadioConfigResponse.hal",
+ ],
+ interfaces: [
+ "android.hardware.radio.config@1.0",
+ "android.hardware.radio.config@1.1",
+ "android.hardware.radio.config@1.2",
+ "android.hardware.radio@1.0",
+ "android.hardware.radio@1.6",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+ system_ext_specific: true,
+}
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
new file mode 100644
index 0000000..83bcf92
--- /dev/null
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 interface is used by telephony and telecom to talk to cellular radio for the purpose of
+ * radio configuration, and it is not associated with any specific modem or slot.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ */
+
+package android.hardware.radio.config@1.3;
+
+import @1.1::IRadioConfig;
+import IRadioConfigResponse;
+
+interface IRadioConfig extends @1.1::IRadioConfig {
+ /**
+ * Gets the available Radio Hal capabilities on the current device.
+ *
+ * This is called once per device boot up.
+ *
+ * @param serial Serial number of request
+ *
+ * Response callback is
+ * IRadioConfigResponse.getHalDeviceCapabilitiesResponse()
+ */
+ oneway getHalDeviceCapabilities(int32_t serial);
+};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
new file mode 100644
index 0000000..863754f
--- /dev/null
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.hardware.radio.config@1.3;
+
+import android.hardware.radio@1.6::RadioResponseInfo;
+import @1.2::IRadioConfigResponse;
+import HalDeviceCapabilities;
+
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param capabilities Capabilities struct containing the capabilities of the
+ * device related to the Radio HAL
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getHalDeviceCapabilitiesResponse(RadioResponseInfo info,
+ HalDeviceCapabilities capabilities);
+};
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
new file mode 100644
index 0000000..bedb709
--- /dev/null
+++ b/radio/config/1.3/types.hal
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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.hardware.radio.config@1.3;
+
+/**
+ * Contains the device capabilities with respect to the Radio HAL.
+ */
+struct HalDeviceCapabilities {};
diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..abd081f
--- /dev/null
+++ b/radio/config/1.3/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalRadioConfigV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "radio_config_hidl_hal_api.cpp",
+ "radio_config_hidl_hal_test.cpp",
+ "radio_config_response.cpp",
+ "radio_config_indication.cpp",
+ "VtsHalRadioConfigV1_3TargetTest.cpp",
+ ],
+ static_libs: [
+ "RadioVtsTestUtilBase",
+ "android.hardware.radio.config@1.0",
+ "android.hardware.radio.config@1.1",
+ "android.hardware.radio.config@1.2",
+ "android.hardware.radio.config@1.3",
+ ],
+ header_libs: ["radio.util.header@1.0"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
new file mode 100644
index 0000000..5772d08
--- /dev/null
+++ b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioConfigHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, RadioConfigHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IRadioConfig::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
new file mode 100644
index 0000000..8df02dd
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadioConfig.getHalDeviceCapabilities()
+ */
+TEST_P(RadioConfigHidlTest, getHalDeviceCapabilities) {
+ const int serial = GetRandomSerialNumber();
+ Return<void> res = radioConfig->getHalDeviceCapabilities(serial);
+ ASSERT_OK(res);
+ ALOGI("getHalDeviceCapabilities, rspInfo.error = %s\n",
+ toString(radioConfigRsp->rspInfo.error).c_str());
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
new file mode 100644
index 0000000..de8365a
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+void RadioConfigHidlTest::SetUp() {
+ radioConfig = IRadioConfig::getService(GetParam());
+ if (radioConfig == NULL) {
+ sleep(60);
+ radioConfig = IRadioConfig::getService(GetParam());
+ }
+ ASSERT_NE(nullptr, radioConfig.get());
+
+ radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+ ASSERT_NE(nullptr, radioConfigRsp.get());
+
+ count_ = 0;
+
+ radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioConfigHidlTest::notify(int receivedSerial) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ if (serial == receivedSerial) {
+ count_++;
+ cv_.notify_one();
+ }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioConfigHidlTest::wait() {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count_ == 0) {
+ status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ return status;
+ }
+ }
+ count_--;
+ return status;
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
new file mode 100644
index 0000000..439eb70
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.1/types.h>
+#include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.2/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.2/types.h>
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::config::V1_2;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::radio::config::V1_1::ModemsConfig;
+using ::android::hardware::radio::config::V1_1::PhoneCapability;
+using ::android::hardware::radio::config::V1_2::SimSlotStatus;
+using ::android::hardware::radio::config::V1_3::HalDeviceCapabilities;
+using ::android::hardware::radio::config::V1_3::IRadioConfig;
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+
+#define TIMEOUT_PERIOD 75
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioConfigHidlTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public IRadioConfigResponse {
+ protected:
+ RadioConfigHidlTest& parent;
+
+ public:
+ RadioResponseInfo rspInfo;
+ PhoneCapability phoneCap;
+
+ RadioConfigResponse(RadioConfigHidlTest& parent);
+ virtual ~RadioConfigResponse() = default;
+
+ Return<void> getSimSlotsStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+
+ Return<void> getSimSlotsStatusResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
+
+ Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+ Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+ const PhoneCapability& phoneCapability);
+
+ Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+ Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+ const ModemsConfig& mConfig);
+
+ Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> getHalDeviceCapabilitiesResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const HalDeviceCapabilities& halDeviceCapabilities);
+};
+
+/* Callback class for radio config indication */
+class RadioConfigIndication : public IRadioConfigIndication {
+ protected:
+ RadioConfigHidlTest& parent;
+
+ public:
+ RadioConfigIndication(RadioConfigHidlTest& parent);
+ virtual ~RadioConfigIndication() = default;
+
+ Return<void> simSlotsStatusChanged_1_2(
+ ::android::hardware::radio::V1_0::RadioIndicationType type,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+// The main test class for Radio config HIDL.
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
+ protected:
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
+ public:
+ virtual void SetUp() override;
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ void notify(int receivedSerial);
+
+ /* Test code calls this function to wait for response */
+ std::cv_status wait();
+
+ void updateSimCardStatus();
+
+ /* Serial number for radio request */
+ int serial;
+
+ /* radio config service handle */
+ sp<IRadioConfig> radioConfig;
+
+ /* radio config response handle */
+ sp<RadioConfigResponse> radioConfigRsp;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_indication.cpp b/radio/config/1.3/vts/functional/radio_config_indication.cpp
new file mode 100644
index 0000000..6fa443c
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_indication.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+RadioConfigIndication::RadioConfigIndication(RadioConfigHidlTest& parent) : parent(parent) {}
+
+Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
+ ::android::hardware::radio::V1_0::RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& /*slotStatus*/) {
+ return Void();
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..2a8b28b
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+// SimSlotStatus slotStatus;
+
+RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
+
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+ const PhoneCapability& phoneCapability) {
+ rspInfo = info;
+ phoneCap = phoneCapability;
+ parent.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */,
+ const ModemsConfig& /* mConfig */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& /* info */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getHalDeviceCapabilitiesResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& /* info */,
+ const ::android::hardware::radio::config::V1_3::HalDeviceCapabilities& /* capabilities */) {
+ return Void();
+}
\ No newline at end of file
diff --git a/renderscript/1.0/types.hal b/renderscript/1.0/types.hal
index 7c32188..bb39baa 100644
--- a/renderscript/1.0/types.hal
+++ b/renderscript/1.0/types.hal
@@ -170,7 +170,6 @@
};
// Script to Script
-@export(name="RsScriptCall")
struct ScriptCall {
ForEachStrategy strategy;
uint32_t xStart;
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
new file mode 100644
index 0000000..b5adac9
--- /dev/null
+++ b/security/keymint/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+ name: "android.hardware.security.keymint",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/security/keymint/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+}
diff --git a/security/keymint/aidl/OWNERS b/security/keymint/aidl/OWNERS
new file mode 100644
index 0000000..5c79db8
--- /dev/null
+++ b/security/keymint/aidl/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+seleneh@google.com
+swillden@google.com
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Algorithm.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Algorithm.aidl
new file mode 100644
index 0000000..46e0ae0
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Algorithm.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum Algorithm {
+ RSA = 1,
+ EC = 3,
+ AES = 32,
+ TRIPLE_DES = 33,
+ HMAC = 128,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BeginResult.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BeginResult.aidl
new file mode 100644
index 0000000..ed96485
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BeginResult.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable BeginResult {
+ long challenge;
+ android.hardware.security.keymint.KeyParameter[] params;
+ android.hardware.security.keymint.IKeyMintOperation operation;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BlockMode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BlockMode.aidl
new file mode 100644
index 0000000..dddc9d8
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/BlockMode.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum BlockMode {
+ ECB = 1,
+ CBC = 2,
+ CTR = 3,
+ GCM = 32,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ByteArray.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ByteArray.aidl
new file mode 100644
index 0000000..3d18a26
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ByteArray.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable ByteArray {
+ byte[] data;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Certificate.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Certificate.aidl
new file mode 100644
index 0000000..9e0f8dc
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Certificate.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable Certificate {
+ byte[] encodedCertificate;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Digest.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Digest.aidl
new file mode 100644
index 0000000..8fc4d42
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Digest.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum Digest {
+ NONE = 0,
+ MD5 = 1,
+ SHA1 = 2,
+ SHA_2_224 = 3,
+ SHA_2_256 = 4,
+ SHA_2_384 = 5,
+ SHA_2_512 = 6,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl
new file mode 100644
index 0000000..7c3f2f3
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum EcCurve {
+ P_224 = 0,
+ P_256 = 1,
+ P_384 = 2,
+ P_521 = 3,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
new file mode 100644
index 0000000..cdcb08d
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -0,0 +1,100 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum ErrorCode {
+ OK = 0,
+ ROOT_OF_TRUST_ALREADY_SET = -1,
+ UNSUPPORTED_PURPOSE = -2,
+ INCOMPATIBLE_PURPOSE = -3,
+ UNSUPPORTED_ALGORITHM = -4,
+ INCOMPATIBLE_ALGORITHM = -5,
+ UNSUPPORTED_KEY_SIZE = -6,
+ UNSUPPORTED_BLOCK_MODE = -7,
+ INCOMPATIBLE_BLOCK_MODE = -8,
+ UNSUPPORTED_MAC_LENGTH = -9,
+ UNSUPPORTED_PADDING_MODE = -10,
+ INCOMPATIBLE_PADDING_MODE = -11,
+ UNSUPPORTED_DIGEST = -12,
+ INCOMPATIBLE_DIGEST = -13,
+ INVALID_EXPIRATION_TIME = -14,
+ INVALID_USER_ID = -15,
+ INVALID_AUTHORIZATION_TIMEOUT = -16,
+ UNSUPPORTED_KEY_FORMAT = -17,
+ INCOMPATIBLE_KEY_FORMAT = -18,
+ UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19,
+ UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20,
+ INVALID_INPUT_LENGTH = -21,
+ KEY_EXPORT_OPTIONS_INVALID = -22,
+ DELEGATION_NOT_ALLOWED = -23,
+ KEY_NOT_YET_VALID = -24,
+ KEY_EXPIRED = -25,
+ KEY_USER_NOT_AUTHENTICATED = -26,
+ OUTPUT_PARAMETER_NULL = -27,
+ INVALID_OPERATION_HANDLE = -28,
+ INSUFFICIENT_BUFFER_SPACE = -29,
+ VERIFICATION_FAILED = -30,
+ TOO_MANY_OPERATIONS = -31,
+ UNEXPECTED_NULL_POINTER = -32,
+ INVALID_KEY_BLOB = -33,
+ IMPORTED_KEY_NOT_ENCRYPTED = -34,
+ IMPORTED_KEY_DECRYPTION_FAILED = -35,
+ IMPORTED_KEY_NOT_SIGNED = -36,
+ IMPORTED_KEY_VERIFICATION_FAILED = -37,
+ INVALID_ARGUMENT = -38,
+ UNSUPPORTED_TAG = -39,
+ INVALID_TAG = -40,
+ MEMORY_ALLOCATION_FAILED = -41,
+ IMPORT_PARAMETER_MISMATCH = -44,
+ SECURE_HW_ACCESS_DENIED = -45,
+ OPERATION_CANCELLED = -46,
+ CONCURRENT_ACCESS_CONFLICT = -47,
+ SECURE_HW_BUSY = -48,
+ SECURE_HW_COMMUNICATION_FAILED = -49,
+ UNSUPPORTED_EC_FIELD = -50,
+ MISSING_NONCE = -51,
+ INVALID_NONCE = -52,
+ MISSING_MAC_LENGTH = -53,
+ KEY_RATE_LIMIT_EXCEEDED = -54,
+ CALLER_NONCE_PROHIBITED = -55,
+ KEY_MAX_OPS_EXCEEDED = -56,
+ INVALID_MAC_LENGTH = -57,
+ MISSING_MIN_MAC_LENGTH = -58,
+ UNSUPPORTED_MIN_MAC_LENGTH = -59,
+ UNSUPPORTED_KDF = -60,
+ UNSUPPORTED_EC_CURVE = -61,
+ KEY_REQUIRES_UPGRADE = -62,
+ ATTESTATION_CHALLENGE_MISSING = -63,
+ KEYMINT_NOT_CONFIGURED = -64,
+ ATTESTATION_APPLICATION_ID_MISSING = -65,
+ CANNOT_ATTEST_IDS = -66,
+ ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+ HARDWARE_TYPE_UNAVAILABLE = -68,
+ PROOF_OF_PRESENCE_REQUIRED = -69,
+ CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+ NO_USER_CONFIRMATION = -71,
+ DEVICE_LOCKED = -72,
+ EARLY_BOOT_ENDED = -73,
+ ATTESTATION_KEYS_NOT_PROVISIONED = -74,
+ ATTESTATION_IDS_NOT_PROVISIONED = -75,
+ INVALID_OPERATION = -76,
+ STORAGE_KEY_UNSUPPORTED = -77,
+ UNIMPLEMENTED = -100,
+ VERSION_MISMATCH = -101,
+ UNKNOWN_ERROR = -1000,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthToken.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthToken.aidl
new file mode 100644
index 0000000..9ea24f5
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthToken.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable HardwareAuthToken {
+ long challenge;
+ long userId;
+ long authenticatorId;
+ android.hardware.security.keymint.HardwareAuthenticatorType authenticatorType;
+ android.hardware.security.keymint.Timestamp timestamp;
+ byte[] mac;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..aef5ee0
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum HardwareAuthenticatorType {
+ NONE = 0,
+ PASSWORD = 1,
+ FINGERPRINT = 2,
+ ANY = -1,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
new file mode 100644
index 0000000..3d08cfe
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+interface IKeyMintDevice {
+ android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
+ android.hardware.security.keymint.VerificationToken verifyAuthorization(in long challenge, in android.hardware.security.keymint.HardwareAuthToken token);
+ void addRngEntropy(in byte[] data);
+ void generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams, out android.hardware.security.keymint.ByteArray generatedKeyBlob, out android.hardware.security.keymint.KeyCharacteristics generatedKeyCharacteristics, out android.hardware.security.keymint.Certificate[] outCertChain);
+ void importKey(in android.hardware.security.keymint.KeyParameter[] inKeyParams, in android.hardware.security.keymint.KeyFormat inKeyFormat, in byte[] inKeyData, out android.hardware.security.keymint.ByteArray outImportedKeyBlob, out android.hardware.security.keymint.KeyCharacteristics outImportedKeyCharacteristics, out android.hardware.security.keymint.Certificate[] outCertChain);
+ void importWrappedKey(in byte[] inWrappedKeyData, in byte[] inWrappingKeyBlob, in byte[] inMaskingKey, in android.hardware.security.keymint.KeyParameter[] inUnwrappingParams, in long inPasswordSid, in long inBiometricSid, out android.hardware.security.keymint.ByteArray outImportedKeyBlob, out android.hardware.security.keymint.KeyCharacteristics outImportedKeyCharacteristics);
+ byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] inUpgradeParams);
+ void deleteKey(in byte[] inKeyBlob);
+ void deleteAllKeys();
+ void destroyAttestationIds();
+ android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.security.keymint.KeyParameter[] inParams, in android.hardware.security.keymint.HardwareAuthToken inAuthToken);
+ const int AUTH_TOKEN_MAC_LENGTH = 32;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl
new file mode 100644
index 0000000..8e3b0fc
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+interface IKeyMintOperation {
+ int update(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable android.hardware.security.keymint.HardwareAuthToken inAuthToken, in @nullable android.hardware.security.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams, out @nullable android.hardware.security.keymint.ByteArray output);
+ byte[] finish(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable byte[] inSignature, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken, in @nullable android.hardware.security.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams);
+ void abort();
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyCharacteristics.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyCharacteristics.aidl
new file mode 100644
index 0000000..fb4214c
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyCharacteristics.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable KeyCharacteristics {
+ android.hardware.security.keymint.KeyParameter[] softwareEnforced;
+ android.hardware.security.keymint.KeyParameter[] hardwareEnforced;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyDerivationFunction.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyDerivationFunction.aidl
new file mode 100644
index 0000000..83b7e6e
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyDerivationFunction.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum KeyDerivationFunction {
+ NONE = 0,
+ RFC5869_SHA256 = 1,
+ ISO18033_2_KDF1_SHA1 = 2,
+ ISO18033_2_KDF1_SHA256 = 3,
+ ISO18033_2_KDF2_SHA1 = 4,
+ ISO18033_2_KDF2_SHA256 = 5,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyFormat.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyFormat.aidl
new file mode 100644
index 0000000..f701c80
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyFormat.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum KeyFormat {
+ X509 = 0,
+ PKCS8 = 1,
+ RAW = 3,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
new file mode 100644
index 0000000..5e9f7ae
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable KeyMintHardwareInfo {
+ int versionNumber;
+ android.hardware.security.keymint.SecurityLevel securityLevel;
+ @utf8InCpp String keyMintName;
+ @utf8InCpp String keyMintAuthorName;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyOrigin.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyOrigin.aidl
new file mode 100644
index 0000000..9728bf9
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyOrigin.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum KeyOrigin {
+ GENERATED = 0,
+ DERIVED = 1,
+ IMPORTED = 2,
+ RESERVED = 3,
+ SECURELY_IMPORTED = 4,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameter.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameter.aidl
new file mode 100644
index 0000000..91f83e4
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameter.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable KeyParameter {
+ android.hardware.security.keymint.Tag tag;
+ boolean boolValue;
+ int integer;
+ long longInteger;
+ byte[] blob;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameterArray.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameterArray.aidl
new file mode 100644
index 0000000..2c3b768
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyParameterArray.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable KeyParameterArray {
+ android.hardware.security.keymint.KeyParameter[] params;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
new file mode 100644
index 0000000..a6fd8c3
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum KeyPurpose {
+ ENCRYPT = 0,
+ DECRYPT = 1,
+ SIGN = 2,
+ VERIFY = 3,
+ WRAP_KEY = 5,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/PaddingMode.aidl
new file mode 100644
index 0000000..2ecfa1e
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/PaddingMode.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum PaddingMode {
+ NONE = 1,
+ RSA_OAEP = 2,
+ RSA_PSS = 3,
+ RSA_PKCS1_1_5_ENCRYPT = 4,
+ RSA_PKCS1_1_5_SIGN = 5,
+ PKCS7 = 64,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/SecurityLevel.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/SecurityLevel.aidl
new file mode 100644
index 0000000..601693f
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/SecurityLevel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ STRONGBOX = 2,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
new file mode 100644
index 0000000..38eb6e6
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -0,0 +1,80 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum Tag {
+ INVALID = 0,
+ PURPOSE = 536870913,
+ ALGORITHM = 268435458,
+ KEY_SIZE = 805306371,
+ BLOCK_MODE = 536870916,
+ DIGEST = 536870917,
+ PADDING = 536870918,
+ CALLER_NONCE = 1879048199,
+ MIN_MAC_LENGTH = 805306376,
+ EC_CURVE = 268435466,
+ RSA_PUBLIC_EXPONENT = 1342177480,
+ INCLUDE_UNIQUE_ID = 1879048394,
+ BLOB_USAGE_REQUIREMENTS = 268435757,
+ BOOTLOADER_ONLY = 1879048494,
+ ROLLBACK_RESISTANCE = 1879048495,
+ HARDWARE_TYPE = 268435760,
+ EARLY_BOOT_ONLY = 1879048497,
+ ACTIVE_DATETIME = 1610613136,
+ ORIGINATION_EXPIRE_DATETIME = 1610613137,
+ USAGE_EXPIRE_DATETIME = 1610613138,
+ MIN_SECONDS_BETWEEN_OPS = 805306771,
+ MAX_USES_PER_BOOT = 805306772,
+ USER_ID = 805306869,
+ USER_SECURE_ID = -1610612234,
+ NO_AUTH_REQUIRED = 1879048695,
+ USER_AUTH_TYPE = 268435960,
+ AUTH_TIMEOUT = 805306873,
+ ALLOW_WHILE_ON_BODY = 1879048698,
+ TRUSTED_USER_PRESENCE_REQUIRED = 1879048699,
+ TRUSTED_CONFIRMATION_REQUIRED = 1879048700,
+ UNLOCKED_DEVICE_REQUIRED = 1879048701,
+ APPLICATION_ID = -1879047591,
+ APPLICATION_DATA = -1879047492,
+ CREATION_DATETIME = 1610613437,
+ ORIGIN = 268436158,
+ ROOT_OF_TRUST = -1879047488,
+ OS_VERSION = 805307073,
+ OS_PATCHLEVEL = 805307074,
+ UNIQUE_ID = -1879047485,
+ ATTESTATION_CHALLENGE = -1879047484,
+ ATTESTATION_APPLICATION_ID = -1879047483,
+ ATTESTATION_ID_BRAND = -1879047482,
+ ATTESTATION_ID_DEVICE = -1879047481,
+ ATTESTATION_ID_PRODUCT = -1879047480,
+ ATTESTATION_ID_SERIAL = -1879047479,
+ ATTESTATION_ID_IMEI = -1879047478,
+ ATTESTATION_ID_MEID = -1879047477,
+ ATTESTATION_ID_MANUFACTURER = -1879047476,
+ ATTESTATION_ID_MODEL = -1879047475,
+ VENDOR_PATCHLEVEL = 805307086,
+ BOOT_PATCHLEVEL = 805307087,
+ DEVICE_UNIQUE_ATTESTATION = 1879048912,
+ IDENTITY_CREDENTIAL_KEY = 1879048913,
+ STORAGE_KEY = 1879048914,
+ ASSOCIATED_DATA = -1879047192,
+ NONCE = -1879047191,
+ MAC_LENGTH = 805307371,
+ RESET_SINCE_ID_ROTATION = 1879049196,
+ CONFIRMATION_TOKEN = -1879047187,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl
new file mode 100644
index 0000000..bb2766c
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@Backing(type="int") @VintfStability
+enum TagType {
+ INVALID = 0,
+ ENUM = 268435456,
+ ENUM_REP = 536870912,
+ UINT = 805306368,
+ UINT_REP = 1073741824,
+ ULONG = 1342177280,
+ DATE = 1610612736,
+ BOOL = 1879048192,
+ BIGNUM = -2147483648,
+ BYTES = -1879048192,
+ ULONG_REP = -1610612736,
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Timestamp.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Timestamp.aidl
new file mode 100644
index 0000000..4d5b659
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Timestamp.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable Timestamp {
+ long milliSeconds;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/VerificationToken.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/VerificationToken.aidl
new file mode 100644
index 0000000..5c76816
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/VerificationToken.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable VerificationToken {
+ long challenge;
+ android.hardware.security.keymint.Timestamp timestamp;
+ android.hardware.security.keymint.SecurityLevel securityLevel;
+ byte[] mac;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Algorithm.aidl b/security/keymint/aidl/android/hardware/security/keymint/Algorithm.aidl
new file mode 100644
index 0000000..8300b0d
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/Algorithm.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Algorithms provided by IKeyMintDevice implementations.
+ */
+@VintfStability
+@Backing(type="int")
+enum Algorithm {
+ /** Asymmetric algorithms. */
+ RSA = 1,
+ /** 2 removed, do not reuse. */
+ EC = 3,
+
+ /** Block cipher algorithms */
+ AES = 32,
+ TRIPLE_DES = 33,
+
+ /** MAC algorithms */
+ HMAC = 128,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl
new file mode 100644
index 0000000..aaf9f3c
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.IKeyMintOperation;
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * This is all the results returned by the IKeyMintDevice begin() function.
+ */
+@VintfStability
+parcelable BeginResult {
+ /* This is the challenge used in verifyAuthorization. It must be a nonce. */
+ long challenge;
+
+ /**
+ * begin() uses this field to return additional data from the operation
+ * initialization, notably to return the IV or nonce from operations
+ * that generate an IV or nonce.
+ */
+ KeyParameter[] params;
+ IKeyMintOperation operation;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/BlockMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/BlockMode.aidl
new file mode 100644
index 0000000..629c89f
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/BlockMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Symmetric block cipher modes provided by IKeyMintDevice implementations.
+ */
+@VintfStability
+@Backing(type="int")
+enum BlockMode {
+ /*
+ * Unauthenticated modes, usable only for encryption/decryption and not generally recommended
+ * except for compatibility with existing other protocols.
+ */
+ ECB = 1,
+ CBC = 2,
+ CTR = 3,
+
+ /*
+ * Authenticated modes, usable for encryption/decryption and signing/verification. Recommended
+ * over unauthenticated modes for all purposes.
+ */
+ GCM = 32,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ByteArray.aidl b/security/keymint/aidl/android/hardware/security/keymint/ByteArray.aidl
new file mode 100644
index 0000000..c3b402e
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/ByteArray.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * This is used to contain a byte[], to make out parameters of byte arrays
+ * more convenient for callers.
+ */
+@VintfStability
+parcelable ByteArray {
+ byte[] data;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Certificate.aidl b/security/keymint/aidl/android/hardware/security/keymint/Certificate.aidl
new file mode 100644
index 0000000..a953859
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/Certificate.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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.hardware.security.keymint;
+
+/**
+ * This encodes the IKeyMintDevice attestation generated certificate.
+ */
+
+@VintfStability
+parcelable Certificate {
+ /**
+ * EncodedCertificate contains the bytes of a DER-encoded X.509 certificate.
+ */
+ byte[] encodedCertificate;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Digest.aidl b/security/keymint/aidl/android/hardware/security/keymint/Digest.aidl
new file mode 100644
index 0000000..b44da5a
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/Digest.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Digests provided by keyMint implementations.
+ */
+@VintfStability
+@Backing(type="int")
+enum Digest {
+ NONE = 0,
+ MD5 = 1,
+ SHA1 = 2,
+ SHA_2_224 = 3,
+ SHA_2_256 = 4,
+ SHA_2_384 = 5,
+ SHA_2_512 = 6,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl b/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl
new file mode 100644
index 0000000..b9d1646
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Supported EC curves, used in ECDSA
+ */
+@VintfStability
+@Backing(type="int")
+enum EcCurve {
+ P_224 = 0,
+ P_256 = 1,
+ P_384 = 2,
+ P_521 = 3,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
new file mode 100644
index 0000000..fb24ad1
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * KeyMint error codes. Aidl will return these error codes as service specific
+ * errors in EX_SERVICE_SPECIFIC.
+ */
+@VintfStability
+@Backing(type="int")
+enum ErrorCode {
+ OK = 0,
+ ROOT_OF_TRUST_ALREADY_SET = -1,
+ UNSUPPORTED_PURPOSE = -2,
+ INCOMPATIBLE_PURPOSE = -3,
+ UNSUPPORTED_ALGORITHM = -4,
+ INCOMPATIBLE_ALGORITHM = -5,
+ UNSUPPORTED_KEY_SIZE = -6,
+ UNSUPPORTED_BLOCK_MODE = -7,
+ INCOMPATIBLE_BLOCK_MODE = -8,
+ UNSUPPORTED_MAC_LENGTH = -9,
+ UNSUPPORTED_PADDING_MODE = -10,
+ INCOMPATIBLE_PADDING_MODE = -11,
+ UNSUPPORTED_DIGEST = -12,
+ INCOMPATIBLE_DIGEST = -13,
+ INVALID_EXPIRATION_TIME = -14,
+ INVALID_USER_ID = -15,
+ INVALID_AUTHORIZATION_TIMEOUT = -16,
+ UNSUPPORTED_KEY_FORMAT = -17,
+ INCOMPATIBLE_KEY_FORMAT = -18,
+ UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, /** For PKCS8 & PKCS12 */
+ UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /** For PKCS8 & PKCS12 */
+ INVALID_INPUT_LENGTH = -21,
+ KEY_EXPORT_OPTIONS_INVALID = -22,
+ DELEGATION_NOT_ALLOWED = -23,
+ KEY_NOT_YET_VALID = -24,
+ KEY_EXPIRED = -25,
+ KEY_USER_NOT_AUTHENTICATED = -26,
+ OUTPUT_PARAMETER_NULL = -27,
+ INVALID_OPERATION_HANDLE = -28,
+ INSUFFICIENT_BUFFER_SPACE = -29,
+ VERIFICATION_FAILED = -30,
+ TOO_MANY_OPERATIONS = -31,
+ UNEXPECTED_NULL_POINTER = -32,
+ INVALID_KEY_BLOB = -33,
+ IMPORTED_KEY_NOT_ENCRYPTED = -34,
+ IMPORTED_KEY_DECRYPTION_FAILED = -35,
+ IMPORTED_KEY_NOT_SIGNED = -36,
+ IMPORTED_KEY_VERIFICATION_FAILED = -37,
+ INVALID_ARGUMENT = -38,
+ UNSUPPORTED_TAG = -39,
+ INVALID_TAG = -40,
+ MEMORY_ALLOCATION_FAILED = -41,
+ IMPORT_PARAMETER_MISMATCH = -44,
+ SECURE_HW_ACCESS_DENIED = -45,
+ OPERATION_CANCELLED = -46,
+ CONCURRENT_ACCESS_CONFLICT = -47,
+ SECURE_HW_BUSY = -48,
+ SECURE_HW_COMMUNICATION_FAILED = -49,
+ UNSUPPORTED_EC_FIELD = -50,
+ MISSING_NONCE = -51,
+ INVALID_NONCE = -52,
+ MISSING_MAC_LENGTH = -53,
+ KEY_RATE_LIMIT_EXCEEDED = -54,
+ CALLER_NONCE_PROHIBITED = -55,
+ KEY_MAX_OPS_EXCEEDED = -56,
+ INVALID_MAC_LENGTH = -57,
+ MISSING_MIN_MAC_LENGTH = -58,
+ UNSUPPORTED_MIN_MAC_LENGTH = -59,
+ UNSUPPORTED_KDF = -60,
+ UNSUPPORTED_EC_CURVE = -61,
+ KEY_REQUIRES_UPGRADE = -62,
+ ATTESTATION_CHALLENGE_MISSING = -63,
+ KEYMINT_NOT_CONFIGURED = -64,
+ ATTESTATION_APPLICATION_ID_MISSING = -65,
+ CANNOT_ATTEST_IDS = -66,
+ ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+ HARDWARE_TYPE_UNAVAILABLE = -68,
+ PROOF_OF_PRESENCE_REQUIRED = -69,
+ CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+ NO_USER_CONFIRMATION = -71,
+ DEVICE_LOCKED = -72,
+ EARLY_BOOT_ENDED = -73,
+ ATTESTATION_KEYS_NOT_PROVISIONED = -74,
+ ATTESTATION_IDS_NOT_PROVISIONED = -75,
+ INVALID_OPERATION = -76,
+ STORAGE_KEY_UNSUPPORTED = -77,
+
+ UNIMPLEMENTED = -100,
+ VERSION_MISMATCH = -101,
+
+ UNKNOWN_ERROR = -1000,
+
+ // Implementer's namespace for error codes starts at -10000.
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthToken.aidl b/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthToken.aidl
new file mode 100644
index 0000000..12d615f
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthToken.aidl
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.Timestamp;
+import android.hardware.security.keymint.HardwareAuthenticatorType;
+
+/**
+ * HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key.
+ *
+ * HardwareAuthTokens are produced by other secure environment applications, notably GateKeeper and
+ * biometric authenticators, in response to successful user authentication events. These tokens are passed to
+ * begin(), update(), and finish() to prove that authentication occurred. See those methods for
+ * more details. It is up to the caller to determine which of the generated auth tokens is
+ * appropriate for a given key operation.
+ */
+@VintfStability
+parcelable HardwareAuthToken {
+ /**
+ * challenge is a value that's used to enable authentication tokens to authorize specific
+ * events. The primary use case for challenge is to authorize an IKeyMintDevice cryptographic
+ * operation, for keys that require authentication per operation. See begin() for details.
+ */
+ long challenge;
+
+ /**
+ * userId is the a "secure" user ID. It is not related to any Android user ID or UID, but is
+ * created in the Gatekeeper application in the secure environment.
+ */
+ long userId;
+
+ /**
+ * authenticatorId is the a "secure" user ID. It is not related to any Android user ID or UID,
+ * but is created in an authentication application in the secure environment, such as the
+ * Fingerprint application.
+ */
+ long authenticatorId;
+
+ /**
+ * authenticatorType describes the type of authentication that took place, e.g. password or
+ * fingerprint.
+ */
+ HardwareAuthenticatorType authenticatorType;
+
+ /**
+ * timestamp indicates when the user authentication took place, in milliseconds since some
+ * starting point (generally the most recent device boot) which all of the applications within
+ * one secure environment must agree upon. This timestamp is used to determine whether or not
+ * the authentication occurred recently enough to unlock a key (see Tag::AUTH_TIMEOUT).
+ */
+ Timestamp timestamp;
+
+ /**
+ * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
+ * and Fingerprint 1.0, as well as pre-treble HALs.
+ *
+ * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows:
+ *
+ * HMAC_SHA256(
+ * H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+ *
+ * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
+ * are represented as unsigned values, the full width of the type. The challenge, userId and
+ * authenticatorId values are in machine order, but authenticatorType and timestamp are in
+ * network order (big-endian). This odd construction is compatible with the hw_auth_token_t
+ * structure.
+ */
+ byte[] mac;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthenticatorType.aidl b/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..33f71b8
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.hardware.security.keymint;
+
+/**
+ * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
+ * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
+ * authenticating to activate a key.
+ */
+@VintfStability
+@Backing(type="int")
+enum HardwareAuthenticatorType {
+ NONE = 0,
+ PASSWORD = 1 << 0,
+ FINGERPRINT = 1 << 1,
+ // Additional entries must be powers of 2.
+ ANY = 0xFFFFFFFF,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
new file mode 100644
index 0000000..4944acb
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.BeginResult;
+import android.hardware.security.keymint.ByteArray;
+import android.hardware.security.keymint.Certificate;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.keymint.IKeyMintOperation;
+import android.hardware.security.keymint.KeyCharacteristics;
+import android.hardware.security.keymint.KeyFormat;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyMintHardwareInfo;
+import android.hardware.security.keymint.KeyPurpose;
+import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.VerificationToken;
+
+/**
+ * KeyMint device definition.
+ *
+ * == Features ==
+ *
+ * An IKeyMintDevice provides cryptographic services, including the following categories of
+ * operations:
+ *
+ * o Key generation
+ * o Import of asymmetric keys
+ * o Import of raw symmetric keys
+ * o Asymmetric decryption with appropriate padding modes
+ * o Asymmetric signing with digesting and appropriate padding modes
+ * o Symmetric encryption and decryption in appropriate modes, including an AEAD mode
+ * o Generation and verification of symmetric message authentication codes
+ * o Attestation to the presence and configuration of asymmetric keys.
+ *
+ * Protocol elements, such as purpose, mode and padding, as well as access control constraints, must
+ * be specified by the caller when keys are generated or imported and must be permanently bound to
+ * the key, ensuring that the key cannot be used in any other way.
+ *
+ * In addition to the list above, IKeyMintDevice implementations must provide one more service
+ * which is not exposed as an API but used internally: Random number generation. The random number
+ * generator must be high-quality and must be used for generation of keys, initialization vectors,
+ * random padding and other elements of secure protocols that require randomness.
+ *
+ * == Types of IKeyMintDevices ==
+ *
+ * All of the operations and storage of key material must occur in a secure environment. Secure
+ * environments may be either:
+ *
+ * 1. Isolated execution environments, such as a separate virtual machine, hypervisor or
+ * purpose-built trusted execution environment like ARM TrustZone. The isolated environment
+ * must provide complete separation from the Android kernel and user space (collectively called
+ * the "non-secure world", or NSW) so that nothing running in the NSW can observe or manipulate
+ * the results of any computation in the isolated environment. Isolated execution environments
+ * are identified by the SecurityLevel TRUSTED_ENVIRONMENT.
+ *
+ * 2. Completely separate, purpose-built and certified secure CPUs, called "StrongBox" devices.
+ * Examples of StrongBox devices are embedded Secure Elements (eSE) or on-SoC secure processing
+ * units (iSE). StrongBox environments are identified by the SecurityLevel STRONGBOX. To
+ * qualify as a StrongBox, a device must meet the requirements specified in CDD 9.11.2.
+ *
+ * == Necessary Primitives ==
+ *
+ * All IKeyMintDevice implementations must provide support for the following:
+ *
+ * o RSA
+ *
+ * - TRUSTED_ENVIRONMENT IKeyMintDevices must support 2048, 3072 and 4096-bit keys.
+ * STRONGBOX IKeyMintDevices must support 2048-bit keys.
+ * - Public exponent F4 (2^16+1)
+ * - Unpadded, RSASSA-PSS and RSASSA-PKCS1-v1_5 padding modes for RSA signing
+ * - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2
+ * 384 and SHA-2 512 digest modes for RSA signing. STRONGBOX IKeyMintDevices must support
+ * SHA-2 256.
+ * - Unpadded, RSAES-OAEP and RSAES-PKCS1-v1_5 padding modes for RSA encryption.
+ *
+ * o ECDSA
+ *
+ * - TRUSTED_ENVIRONMENT IKeyMintDevices must support NIST curves P-224, P-256, P-384 and
+ * P-521. STRONGBOX IKeyMintDevices must support NIST curve P-256.
+ * - TRUSTED_ENVIRONMENT IKeyMintDevices must support SHA1, SHA-2 224, SHA-2 256, SHA-2
+ * 384 and SHA-2 512 digest modes. STRONGBOX IKeyMintDevices must support SHA-2 256.
+ *
+ * o AES
+ *
+ * - 128 and 256-bit keys
+ * - CBC, CTR, ECB and GCM modes. The GCM mode must not allow the use of tags smaller than 96
+ * bits or nonce lengths other than 96 bits.
+ * - CBC and ECB modes must support unpadded and PKCS7 padding modes. With no padding CBC and
+ * ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a
+ * multiple of the AES block size. With PKCS7 padding, GCM and CTR operations must fail with
+ * ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * o 3DES
+ *
+ * - 168-bit keys.
+ * - CBC and ECB mode.
+
+ * - CBC and ECB modes must support unpadded and PKCS7 padding modes. With no padding CBC and
+ * ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a
+ * multiple of the DES block size.
+ *
+ * o HMAC
+ *
+ * - Any key size that is between 64 and 512 bits (inclusive) and a multiple of 8 must be
+ * supported. STRONGBOX IKeyMintDevices must not support keys larger than 512 bits.
+ * - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD-5, SHA1, SHA-2-224, SHA-2-256,
+ * SHA-2-384 and SHA-2-512. STRONGBOX IKeyMintDevices must support SHA-2-256.
+ *
+ * == Key Access Control ==
+ *
+ * Hardware-based keys that can never be extracted from the device don't provide much security if an
+ * attacker can use them at will (though they're more secure than keys which can be
+ * exfiltrated). Therefore, IKeyMintDevice must enforce access controls.
+ *
+ * Access controls are defined as an "authorization list" of tag/value pairs. Authorization tags
+ * are 32-bit integers from the Tag enum, and the values are a variety of types, defined in the
+ * TagType enum. Some tags may be repeated to specify multiple values. Whether a tag may be
+ * repeated is specified in the documentation for the tag and in the TagType. When a key is
+ * created or imported, the caller specifies an authorization list. The IKeyMintDevice must divide
+ * the caller-provided authorizations into two lists, those it enforces in tee secure zone and
+ * those enforced in the strongBox hardware. These two lists are returned as the "teeEnforced"
+ * and "strongboxEnforced" elements of the KeyCharacteristics struct. Note that software enforced
+ * authorization list entries are not returned because they are not enforced by keymint. The
+ * IKeyMintDevice must also add the following authorizations to the appropriate list:
+ *
+ * o Tag::OS_VERSION
+ * o Tag::OS_PATCHLEVEL
+ * o Tag::VENDOR_PATCHLEVEL
+ * o Tag::BOOT_PATCHLEVEL
+ * o Tag::ORIGIN
+ *
+ * The IKeyMintDevice must ignore unknown tags.
+ *
+ * The caller must always provide the current date time in the keyParameter CREATION_DATETIME
+ * tags.
+ *
+ * All authorization tags and their values, both teeEnforced and strongboxEnforced, including
+ * unknown tags, must be cryptographically bound to the private/secret key material such that any
+ * modification of the portion of the key blob that contains the authorization list makes it
+ * impossible for the secure environment to obtain the private/secret key material. The
+ * recommended approach to meet this requirement is to use the full set of authorization tags
+ * associated with a key as input to a secure key derivation function used to derive a key that
+ * is used to encrypt the private/secret key material.
+ *
+ * IKeyMintDevice implementations ignore any tags they cannot enforce and do not return them
+ * in KeyCharacteristics. For example, Tag::ORIGINATION_EXPIRE_DATETIME provides the date and
+ * time after which a key may not be used to encrypt or sign new messages. Unless the
+ * IKeyMintDevice has access to a secure source of current date/time information, it is not
+ * possible for the IKeyMintDevice to enforce this tag. An IKeyMintDevice implementation will
+ * not rely on the non-secure world's notion of time, because it could be controlled by an
+ * attacker. Similarly, it cannot rely on GPSr time, even if it has exclusive control of the
+ * GPSr, because that might be spoofed by attacker RF signals.
+ *
+ * IKeyMintDevices do not use or enforce any tags they place in the softwareEnforced
+ * list. The IKeyMintDevice caller must enforce them, and it is unnecessary to enforce them
+ * twice.
+ *
+ * Some tags must be enforced by the IKeyMintDevice. See the detailed documentation on each Tag
+ * in Tag.aidl.
+ *
+ * == Root of Trust Binding ==
+ *
+ * IKeyMintDevice keys must be bound to a root of trust, which is a bitstring that must be
+ * provided to the secure environment (by an unspecified, implementation-defined mechanism) during
+ * startup, preferably by the bootloader. This bitstring must be cryptographically bound to every
+ * key managed by the IKeyMintDevice. As above, the recommended mechanism for this cryptographic
+ * binding is to include the Root of Trust data in the input to the key derivation function used to
+ * derive a key that is used to encryp the private/secret key material.
+ *
+ * The root of trust consists of a bitstring that must be derived from the public key used by
+ * Verified Boot to verify the signature on the boot image and from the lock state of the
+ * device. If the public key is changed to allow a different system image to be used or if the
+ * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous
+ * system state must be unusable, unless the previous state is restored. The goal is to increase
+ * the value of the software-enforced key access controls by making it impossible for an attacker-
+ * installed operating system to use IKeyMintDevice keys.
+ *
+ * == Version Binding ==
+ *
+ * All keys must also be bound to the operating system and patch level of the system image and the
+ * patch levels of the vendor image and boot image. This ensures that an attacker who discovers a
+ * weakness in an old version of the software cannot roll a device back to the vulnerable version
+ * and use keys created with the newer version. In addition, when a key with a given version and
+ * patch level is used on a device that has been upgraded to a newer version or patch level, the
+ * key must be upgraded (See IKeyMintDevice::upgradeKey()) before it can be used, and the previous
+ * version of the key must be invalidated. In this way, as the device is upgraded, the keys will
+ * "ratchet" forward along with the device, but any reversion of the device to a previous release
+ * will cause the keys to be unusable.
+ *
+ * This version information must be associated with every key as a set of tag/value pairs in the
+ * hardwareEnforced authorization list. Tag::OS_VERSION, Tag::OS_PATCHLEVEL,
+ * Tag::VENDOR_PATCHLEVEL, and Tag::BOOT_PATCHLEVEL must be cryptographically bound to every
+ * IKeyMintDevice key, as described in the Key Access Control section above.
+ */
+@VintfStability
+interface IKeyMintDevice {
+ const int AUTH_TOKEN_MAC_LENGTH = 32;
+
+ /**
+ * @return info which contains information about the underlying IKeyMintDevice hardware, such
+ * as version number, security level, keyMint name and author name.
+ */
+ KeyMintHardwareInfo getHardwareInfo();
+
+ /**
+ * Verify authorizations for another IKeyMintDevice instance.
+ *
+ * On systems with both a StrongBox and a TEE IKeyMintDevice instance it is sometimes useful
+ * to ask the TEE KeyMintDevice to verify authorizations for a key hosted in StrongBox.
+ *
+ * For every StrongBox operation, Keystore is required to call this method on the TEE KeyMint,
+ * passing in the StrongBox key's hardwareEnforced authorization list and the challenge
+ * returned by StrongBox begin(). Keystore must then pass the VerificationToken to the
+ * subsequent invocations of StrongBox update() and finish().
+ *
+ * StrongBox implementations must return ErrorCode::UNIMPLEMENTED.
+ *
+ * @param the challenge returned by StrongBox's keyMint's begin().
+ *
+ * @param authToken A HardwareAuthToken if needed to authorize key usage.
+ *
+ * @return error ErrorCode::OK on success or ErrorCode::UNIMPLEMENTED if the KeyMintDevice is
+ * a StrongBox. If the IKeyMintDevice cannot verify one or more elements of
+ * parametersToVerify it must not return an error code, but just omit the unverified
+ * parameter from the VerificationToken.
+ *
+ * @return token the verification token. See VerificationToken in VerificationToken.aidl for
+ * details.
+ */
+ VerificationToken verifyAuthorization(in long challenge,
+ in HardwareAuthToken token);
+
+ /**
+ * Adds entropy to the RNG used by KeyMint. Entropy added through this method must not be the
+ * only source of entropy used, and a secure mixing function must be used to mix the entropy
+ * provided by this method with internally-generated entropy. The mixing function must be
+ * secure in the sense that if any one of the mixing function inputs is provided with any data
+ * the attacker cannot predict (or control), then the output of the seeded CRNG is
+ * indistinguishable from random. Thus, if the entropy from any source is good, the output
+ * must be good.
+ *
+ * TODO(seleneh) specify what mixing functions and cprng we allow.
+ *
+ * @param data Bytes to be mixed into the CRNG seed. The caller must not provide more than 2
+ * KiB of data per invocation.
+ *
+ * @return error ErrorCode::OK on success; ErrorCode::INVALID_INPUT_LENGTH if the caller
+ * provides more than 2 KiB of data.
+ */
+ void addRngEntropy(in byte[] data);
+
+ /**
+ * Generates a new cryptographic key, specifying associated parameters, which must be
+ * cryptographically bound to the key. IKeyMintDevice implementations must disallow any use
+ * of a key in any way inconsistent with the authorizations specified at generation time. With
+ * respect to parameters that the secure environment cannot enforce, the secure envionment's
+ * obligation is limited to ensuring that the unenforceable parameters associated with the key
+ * cannot be modified. In addition, the characteristics returned by generateKey places
+ * parameters correctly in the tee-enforced and strongbox-enforced lists.
+ *
+ * In addition to the parameters provided, generateKey must add the following to the returned
+ * characteristics.
+ *
+ * o Tag::ORIGIN with the value KeyOrigin::GENERATED.
+ *
+ * o Tag::BLOB_USAGE_REQUIREMENTS with the appropriate value (see KeyBlobUsageRequirements in
+ * Tag.aidl).
+ *
+ * o Tag::OS_VERSION, Tag::OS_PATCHLEVEL, Tag::VENDOR_PATCHLEVEL and Tag::BOOT_PATCHLEVEL with
+ * appropriate values.
+ *
+ * The parameters provided to generateKey depend on the type of key being generated. This
+ * section summarizes the necessary and optional tags for each type of key. Tag::ALGORITHM is
+ * always necessary, to specify the type.
+ *
+ * == RSA Keys ==
+ *
+ * The following parameters are required to generate an RSA key:
+ *
+ * o Tag::Key_SIZE specifies the size of the public modulus, in bits. If omitted, generateKey
+ * must return ErrorCode::UNSUPPORTED_KEY_SIZE. Required values for TEE IKeyMintDevice
+ * implementations are 1024, 2048, 3072 and 4096. StrongBox IKeyMintDevice implementations
+ * must support 2048.
+ *
+ * o Tag::RSA_PUBLIC_EXPONENT specifies the RSA public exponent value. If omitted, generateKey
+ * must return ErrorCode::INVALID_ARGUMENT. The values 3 and 65537 must be supported. It is
+ * recommended to support all prime values up to 2^64. If provided with a non-prime value,
+ * generateKey must return ErrorCode::INVALID_ARGUMENT.
+ *
+ * The following parameters are not necessary to generate a usable RSA key, but generateKey must
+ * not return an error if they are omitted:
+ *
+ * o Tag::PURPOSE specifies allowed purposes. All KeyPurpose values (see KeyPurpose.aidl)
+ * except AGREE_KEY must be supported for RSA keys.
+ *
+ * o Tag::DIGEST specifies digest algorithms that may be used with the new key. TEE
+ * IKeyMintDevice implementatiosn must support all Digest values (see digest.aidl) for RSA
+ * keys. StrongBox IKeyMintDevice implementations must support SHA_2_256.
+ *
+ * o Tag::PADDING specifies the padding modes that may be used with the new
+ * key. IKeyMintDevice implementations must support PaddingMode::NONE,
+ * PaddingMode::RSA_OAEP, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_ENCRYPT and
+ * PaddingMode::RSA_PKCS1_1_5_SIGN for RSA keys.
+ *
+ * == ECDSA Keys ==
+ *
+ * Either Tag::KEY_SIZE or Tag::EC_CURVE must be provided to generate an ECDSA key. If neither
+ * is provided, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE. If Tag::KEY_SIZE is
+ * provided, the possible values are 224, 256, 384 and 521, and must be mapped to Tag::EC_CURVE
+ * values P_224, P_256, P_384 and P_521, respectively. TEE IKeyMintDevice implementations
+ * must support all curves. StrongBox implementations must support P_256.
+ *
+ * == AES Keys ==
+ *
+ * Only Tag::KEY_SIZE is required to generate an AES key. If omitted, generateKey must return
+ * ErrorCode::UNSUPPORTED_KEY_SIZE. 128 and 256-bit key sizes must be supported.
+ *
+ * If Tag::BLOCK_MODE is specified with value BlockMode::GCM, then the caller must also provide
+ * Tag::MIN_MAC_LENGTH. If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH.
+ *
+ *
+ * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
+ * provided in params. See above for detailed specifications of which tags are required
+ * for which types of keys.
+ *
+ * @return generatedKeyBlob Opaque descriptor of the generated key. The recommended
+ * implementation strategy is to include an encrypted copy of the key material, wrapped
+ * in a key unavailable outside secure hardware.
+ *
+ * @return generatedKeyCharacteristics Description of the generated key, divided into two sets:
+ * hardware-enforced and software-enforced. The description here applies equally
+ * to the key characteristics lists returned by generateKey, importKey and
+ * importWrappedKey. The characteristics returned by this parameter completely
+ * describe the type and usage of the specified key.
+ *
+ * The rule that IKeyMintDevice implementations must use for deciding whether a
+ * given tag belongs in the hardware-enforced or software-enforced list is that if
+ * the meaning of the tag is fully assured by secure hardware, it is hardware
+ * enforced. Otherwise, it's software enforced.
+ *
+ * @return outCertChain If the key is an asymmetric key, and proper keyparameters for
+ * attestation (such as challenge) is provided, then this parameter will return the
+ * attestation certificate. If the signing of the attestation certificate is from a
+ * factory key, additional certificates back to the root attestation certificate will
+ * also be provided. Clients will need to check root certificate against a known-good
+ * value. The certificates must be DER-encoded. Caller needs to provide
+ * CREATION_DATETIME as one of the attestation parameters, otherwise the attestation
+ * certificate will not contain the creation datetime. The first certificate in the
+ * vector is the attestation for the generated key itself, the next certificate is
+ * the key that signs the first certificate, and so forth. The last certificate in
+ * the chain is the root certificate. If the key is a symmetric key, then no
+ * certificate will be returned and this variable will return empty. TODO: change
+ * certificate return to a single certificate and make it nullable b/163604282.
+ */
+ void generateKey(in KeyParameter[] keyParams, out ByteArray generatedKeyBlob,
+ out KeyCharacteristics generatedKeyCharacteristics,
+ out Certificate[] outCertChain);
+
+ /**
+ * Imports key material into an IKeyMintDevice. Key definition parameters and return values
+ * are the same as for generateKey, with the following exceptions:
+ *
+ * o Tag::KEY_SIZE is not necessary in the input parameters. If not provided, the
+ * IKeyMintDevice must deduce the value from the provided key material and add the tag and
+ * value to the key characteristics. If Tag::KEY_SIZE is provided, the IKeyMintDevice must
+ * validate it against the key material. In the event of a mismatch, importKey must return
+ * ErrorCode::IMPORT_PARAMETER_MISMATCH.
+ *
+ * o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters. If
+ * not provided, the IKeyMintDevice must deduce the value from the provided key material and
+ * add the tag and value to the key characteristics. If Tag::RSA_PUBLIC_EXPONENT is provided,
+ * the IKeyMintDevice must validate it against the key material. In the event of a
+ * mismatch, importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH.
+ *
+ * o Tag::ORIGIN (returned in keyCharacteristics) must have the value KeyOrigin::IMPORTED.
+ *
+ * @param inKeyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
+ * provided in params.
+ *
+ * @param inKeyFormat The format of the key material to import. See KeyFormat in
+ * keyformat.aidl.
+ *
+ * @param inKeyData The key material to import, in the format specified in keyFormat.
+ *
+ * @return outImportedKeyBlob descriptor of the imported key. The format of the keyblob will
+ * be the google specified keyblob format.
+ *
+ * @return outImportedKeyCharacteristics Description of the generated key. See the
+ * keyCharacteristics description in generateKey.
+ *
+ * @return outCertChain If the key is an asymmetric key, and proper keyparameters for
+ * attestation (such as challenge) is provided, then this parameter will return the
+ * attestation certificate. If the signing of the attestation certificate is from a
+ * factory key, additional certificates back to the root attestation certificate will
+ * also be provided. Clients will need to check root certificate against a known-good
+ * value. The certificates must be DER-encoded. Caller needs to provide
+ * CREATION_DATETIME as one of the attestation parameters, otherwise the attestation
+ * certificate will not contain the creation datetime. The first certificate in the
+ * vector is the attestation for the generated key itself, the next certificate is
+ * the key that signs the first certificate, and so forth. The last certificate in
+ * the chain is the root certificate. If the key is a symmetric key, then no
+ * certificate will be returned and this variable will return empty.
+ */
+ void importKey(in KeyParameter[] inKeyParams, in KeyFormat inKeyFormat,
+ in byte[] inKeyData, out ByteArray outImportedKeyBlob,
+ out KeyCharacteristics outImportedKeyCharacteristics,
+ out Certificate[] outCertChain);
+
+ /**
+ * Securely imports a key, or key pair, returning a key blob and a description of the imported
+ * key.
+ *
+ * @param inWrappedKeyData The wrapped key material to import.
+ * TODO(seleneh) Decide if we want the wrapped key in DER-encoded ASN.1 format or CBOR
+ * format or both. And specify the standarized format.
+ *
+ * KeyDescription ::= SEQUENCE(
+ * keyFormat INTEGER, # Values from KeyFormat enum.
+ * keyParams AuthorizationList,
+ * )
+ *
+ * SecureKeyWrapper ::= SEQUENCE(
+ * version INTEGER, # Contains value 0
+ * encryptedTransportKey OCTET_STRING,
+ * initializationVector OCTET_STRING,
+ * keyDescription KeyDescription,
+ * encryptedKey OCTET_STRING,
+ * tag OCTET_STRING
+ * )
+ *
+ * Where:
+ *
+ * o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+ * key material.
+ * o keyParams is the characteristics of the key to be imported (as with generateKey or
+ * importKey). If the secure import is successful, these characteristics must be
+ * associated with the key exactly as if the key material had been insecurely imported
+ * with the IKeyMintDevice::importKey. See attestKey() for documentation of the
+ * AuthorizationList schema.
+ * o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+ * with the wrapping key specified by wrappingKeyBlob.
+ * o keyDescription is a KeyDescription, above.
+ * o encryptedKey is the key material of the key to be imported, in format keyFormat, and
+ * encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+ * representation of keyDescription provided as additional authenticated data.
+ * o tag is the tag produced by the AES-GCM encryption of encryptedKey.
+ *
+ * So, importWrappedKey does the following:
+ *
+ * 1. Get the private key material for wrappingKeyBlob, verifying that the wrapping key has
+ * purpose KEY_WRAP, padding mode RSA_OAEP, and digest SHA_2_256, returning the
+ * error INCOMPATIBLE_PURPOSE, INCOMPATIBLE_PADDING_MODE, or INCOMPATIBLE_DIGEST if any
+ * of those requirements fail.
+ * 2. Extract the encryptedTransportKey field from the SecureKeyWrapper, and decrypt
+ * it with the wrapping key.
+ * 3. XOR the result of step 2 with maskingKey.
+ * 4. Use the result of step 3 as an AES-GCM key to decrypt encryptedKey, using the encoded
+ * value of keyDescription as the additional authenticated data. Call the result
+ * "keyData" for the next step.
+ * 5. Perform the equivalent of calling importKey(keyParams, keyFormat, keyData), except
+ * that the origin tag should be set to SECURELY_IMPORTED.
+ *
+ * @param inWrappingKeyBlob The opaque key descriptor returned by generateKey() or importKey().
+ * This key must have been created with Purpose::WRAP_KEY.
+ *
+ * @param inMaskingKey The 32-byte value XOR'd with the transport key in the SecureWrappedKey
+ * structure.
+ *
+ * @param inUnwrappingParams must contain any parameters needed to perform the unwrapping
+ * operation. For example, if the wrapping key is an AES key the block and padding
+ * modes must be specified in this argument.
+ *
+ * @param inPasswordSid specifies the password secure ID (SID) of the user that owns the key
+ * being installed. If the authorization list in wrappedKeyData contains a
+ * Tag::USER_SECURE_IDwith a value that has the HardwareAuthenticatorType::PASSWORD
+ * bit set, the constructed key must be bound to the SID value provided by this
+ * argument. If the wrappedKeyData does not contain such a tag and value, this argument
+ * must be ignored.
+ *
+ * @param inBiometricSid specifies the biometric secure ID (SID) of the user that owns the key
+ * being installed. If the authorization list in wrappedKeyData contains a
+ * Tag::USER_SECURE_ID with a value that has the HardwareAuthenticatorType::FINGERPRINT
+ * bit set, the constructed key must be bound to the SID value provided by this argument.
+ * If the wrappedKeyData does not contain such a tag and value, this argument must be
+ * ignored.
+ *
+ * @return outImportedKeyBlob Opaque descriptor of the imported key. It is recommended that
+ * the keyBlob contain a copy of the key material, wrapped in a key unavailable outside
+ * secure hardware.
+ *
+ * @return outImportedKeyCharacteristics Description of the generated key. See the description
+ * of keyCharacteristics parameter in generateKey.
+ */
+ void importWrappedKey(in byte[] inWrappedKeyData,
+ in byte[] inWrappingKeyBlob,
+ in byte[] inMaskingKey,
+ in KeyParameter[] inUnwrappingParams,
+ in long inPasswordSid,
+ in long inBiometricSid,
+ out ByteArray outImportedKeyBlob,
+ out KeyCharacteristics outImportedKeyCharacteristics);
+
+ /**
+ * Upgrades an old key blob. Keys can become "old" in two ways: IKeyMintDevice can be
+ * upgraded to a new version with an incompatible key blob format, or the system can be updated
+ * to invalidate the OS version (OS_VERSION tag), system patch level (OS_PATCHLEVEL tag),
+ * vendor patch level (VENDOR_PATCH_LEVEL tag), boot patch level (BOOT_PATCH_LEVEL tag) or
+ * other, implementation-defined patch level (keyMint implementers are encouraged to extend
+ * this HAL with a minor version extension to define validatable patch levels for other
+ * images; tags must be defined in the implementer's namespace, starting at 10000). In either
+ * case, attempts to use an old key blob with begin() must result in IKeyMintDevice returning
+ * ErrorCode::KEY_REQUIRES_UPGRADE. The caller must use this method to upgrade the key blob.
+ *
+ * The upgradeKey method must examine each version or patch level associated with the key. If
+ * any one of them is higher than the corresponding current device value upgradeKey() must
+ * return ErrorCode::INVALID_ARGUMENT. There is one exception: it is always permissible to
+ * "downgrade" from any OS_VERSION number to OS_VERSION 0. For example, if the key has
+ * OS_VERSION 080001, it is permisible to upgrade the key if the current system version is
+ * 080100, because the new version is larger, or if the current system version is 0, because
+ * upgrades to 0 are always allowed. If the system version were 080000, however, keyMint must
+ * return ErrorCode::INVALID_ARGUMENT because that value is smaller than 080001. Values other
+ * than OS_VERSION must never be downgraded.
+ *
+ * Note that Keymaster versions 2 and 3 required that the system and boot images have the same
+ * patch level and OS version. This requirement is relaxed for 4.0::IKeymasterDevice and
+ * IKeyMintDevice, and the OS version in the boot image footer is no longer used.
+ *
+ * @param inKeyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @param inUpgradeParams A parameter list containing any parameters needed to complete the
+ * upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
+ *
+ * @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
+ * format, or has the new version data.
+ */
+ byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
+
+ /**
+ * Deletes the key, or key pair, associated with the key blob. Calling this function on
+ * a key with Tag::ROLLBACK_RESISTANCE in its hardware-enforced authorization list must
+ * render the key permanently unusable. Keys without Tag::ROLLBACK_RESISTANCE may or
+ * may not be rendered unusable.
+ *
+ * @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
+ */
+ void deleteKey(in byte[] inKeyBlob);
+
+ /**
+ * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
+ * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
+ * authorization lists must be rendered permanently unusable. Keys without
+ * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ void deleteAllKeys();
+
+ /**
+ * Destroys knowledge of the device's ids. This prevents all device id attestation in the
+ * future. The destruction must be permanent so that not even a factory reset will restore the
+ * device ids.
+ *
+ * Device id attestation may be provided only if this method is fully implemented, allowing the
+ * user to permanently disable device id attestation. If this cannot be guaranteed, the device
+ * must never attest any device ids.
+ *
+ * This is a NOP if device id attestation is not supported.
+ */
+ void destroyAttestationIds();
+
+ /**
+ * Begins a cryptographic operation using the specified key. If all is well, begin() must
+ * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls
+ * to update(), finish() or abort().
+ *
+ * It is critical that each call to begin() be paired with a subsequent call to finish() or
+ * abort(), to allow the IKeyMintDevice implementation to clean up any internal operation
+ * state. The caller's failure to do this may leak internal state space or other internal
+ * resources and may eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it
+ * runs out of space for operations. Any result other than ErrorCode::OK from begin(), update()
+ * or finish() implicitly aborts the operation, in which case abort() need not be called (and
+ * must return ErrorCode::INVALID_OPERATION_HANDLE if called). IKeyMintDevice implementations
+ * must support 32 concurrent operations.
+ *
+ * If Tag::APPLICATION_ID or Tag::APPLICATION_DATA were specified during key generation or
+ * import, calls to begin must include those tags with the originally-specified values in the
+ * inParams argument to this method. If not, begin() must return ErrorCode::INVALID_KEY_BLOB.
+ *
+ * == Authorization Enforcement ==
+ *
+ * The following key authorization parameters must be enforced by the IKeyMintDevice secure
+ * environment if the tags were returned in the "hardwareEnforced" list in the
+ * KeyCharacteristics. Public key operations, meaning KeyPurpose::ENCRYPT and
+ * KeyPurpose::VERIFY must be allowed to succeed even if authorization requirements are not met.
+ *
+ * -- All Key Types --
+ *
+ * The tags in this section apply to all key types. See below for additional key type-specific
+ * tags.
+ *
+ * o Tag::PURPOSE: The purpose specified in the begin() call must match one of the purposes in
+ * the key authorizations. If the specified purpose does not match, begin() must return
+ * ErrorCode::UNSUPPORTED_PURPOSE.
+ *
+ * o Tag::ACTIVE_DATETIME can only be enforced if a trusted UTC time source is available. If
+ * the current date and time is prior to the tag value, begin() must return
+ * ErrorCode::KEY_NOT_YET_VALID.
+ *
+ * o Tag::ORIGINATION_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is
+ * available. If the current date and time is later than the tag value and the purpose is
+ * KeyPurpose::ENCRYPT or KeyPurpose::SIGN, begin() must return ErrorCode::KEY_EXPIRED.
+ *
+ * o Tag::USAGE_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is
+ * available. If the current date and time is later than the tag value and the purpose is
+ * KeyPurpose::DECRYPT or KeyPurpose::VERIFY, begin() must return ErrorCode::KEY_EXPIRED.
+ *
+ * o Tag::MAX_USES_PER_BOOT must be compared against a secure counter that tracks the uses of
+ * the key since boot time. If the count of previous uses exceeds the tag value, begin() must
+ * return ErrorCode::KEY_MAX_OPS_EXCEEDED.
+ *
+ * o Tag::USER_SECURE_ID must be enforced by this method if and only if the key also has
+ * Tag::AUTH_TIMEOUT (if it does not have Tag::AUTH_TIMEOUT, the Tag::USER_SECURE_ID
+ * requirement must be enforced by update() and finish()). If the key has both, then this
+ * method must receive a non-empty HardwareAuthToken in the authToken argument. For the auth
+ * token to be valid, all of the following have to be true:
+ *
+ * o The HMAC field must validate correctly.
+ *
+ * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+ * the secure ID values in the token.
+ *
+ * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+ *
+ * o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than
+ * the current secure timestamp (which is a monotonic timer counting milliseconds since
+ * boot.)
+ *
+ * If any of these conditions are not met, begin() must return
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * o Tag::CALLER_NONCE allows the caller to specify a nonce or initialization vector (IV). If
+ * the key doesn't have this tag, but the caller provided Tag::NONCE to this method,
+ * ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+ *
+ * o Tag::BOOTLOADER_ONLY specifies that only the bootloader may use the key. If this method is
+ * called with a bootloader-only key after the bootloader has finished executing, it must
+ * return ErrorCode::INVALID_KEY_BLOB. The mechanism for notifying the IKeyMintDevice that
+ * the bootloader has finished executing is implementation-defined.
+ *
+ * -- RSA Keys --
+ *
+ * All RSA key operations must specify exactly one padding mode in inParams. If unspecified or
+ * specified more than once, the begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
+ *
+ * RSA signing and verification operations need a digest, as do RSA encryption and decryption
+ * operations with OAEP padding mode. For those cases, the caller must specify exactly one
+ * digest in inParams. If unspecified or specified more than once, begin() must return
+ * ErrorCode::UNSUPPORTED_DIGEST.
+ *
+ * Private key operations (KeyPurpose::DECRYPT and KeyPurpose::SIGN) need authorization of
+ * digest and padding, which means that the key authorizations need to contain the specified
+ * values. If not, begin() must return ErrorCode::INCOMPATIBLE_DIGEST or
+ * ErrorCode::INCOMPATIBLE_PADDING, as appropriate. Public key operations (KeyPurpose::ENCRYPT
+ * and KeyPurpose::VERIFY) are permitted with unauthorized digest or padding modes.
+ *
+ * With the exception of PaddingMode::NONE, all RSA padding modes are applicable only to certain
+ * purposes. Specifically, PaddingMode::RSA_PKCS1_1_5_SIGN and PaddingMode::RSA_PSS only
+ * support signing and verification, while PaddingMode::RSA_PKCS1_1_5_ENCRYPT and
+ * PaddingMode::RSA_OAEP only support encryption and decryption. begin() must return
+ * ErrorCode::UNSUPPORTED_PADDING_MODE if the specified mode does not support the specified
+ * purpose.
+ *
+ * There are some important interactions between padding modes and digests:
+ *
+ * o PaddingMode::NONE indicates that a "raw" RSA operation is performed. If signing or
+ * verifying, Digest::NONE is specified for the digest. No digest is necessary for unpadded
+ * encryption or decryption.
+ *
+ * o PaddingMode::RSA_PKCS1_1_5_SIGN padding requires a digest. The digest may be Digest::NONE,
+ * in which case the KeyMint implementation cannot build a proper PKCS#1 v1.5 signature
+ * structure, because it cannot add the DigestInfo structure. Instead, the IKeyMintDevice
+ * must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
+ * random padding string at least eight bytes in length. The size of the RSA key has to be at
+ * least 11 bytes larger than the message, otherwise begin() must return
+ * ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
+ *
+ * o PaddingMode::RSA_PSS padding requires a digest, which may not be Digest::NONE. If
+ * Digest::NONE is specified, the begin() must return ErrorCode::INCOMPATIBLE_DIGEST. In
+ * addition, the size of the RSA key must be at least 2 + D bytes larger than the output size
+ * of the digest, where D is the size of the digest, in bytes. Otherwise begin() must
+ * return ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D.
+ *
+ * o PaddingMode::RSA_OAEP padding requires a digest, which may not be Digest::NONE. If
+ * Digest::NONE is specified, begin() must return ErrorCode::INCOMPATIBLE_DIGEST. The OAEP
+ * mask generation function must be MGF1 and the MGF1 digest must be SHA1, regardless of the
+ * OAEP digest specified.
+ *
+ * -- EC Keys --
+ *
+ * EC key operations must specify exactly one padding mode in inParams. If unspecified or
+ * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
+ *
+ * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
+ * means that the key authorizations must contain the specified values. If not, begin() must
+ * return ErrorCode::INCOMPATIBLE_DIGEST. Public key operations (KeyPurpose::VERIFY) are
+ * permitted with unauthorized digest or padding.
+ *
+ * -- AES Keys --
+ *
+ * AES key operations must specify exactly one block mode (Tag::BLOCK_MODE) and one padding mode
+ * (Tag::PADDING) in inParams. If either value is unspecified or specified more than once,
+ * begin() must return ErrorCode::UNSUPPORTED_BLOCK_MODE or
+ * ErrorCode::UNSUPPORTED_PADDING_MODE. The specified modes must be authorized by the key,
+ * otherwise begin() must return ErrorCode::INCOMPATIBLE_BLOCK_MODE or
+ * ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * If the block mode is BlockMode::GCM, inParams must specify Tag::MAC_LENGTH, and the specified
+ * value must be a multiple of 8 that is not greater than 128 or less than the value of
+ * Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than 128 or
+ * non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For values less
+ * than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH.
+ *
+ * If the block mode is BlockMode::GCM or BlockMode::CTR, the specified padding mode must be
+ * PaddingMode::NONE. For BlockMode::ECB or BlockMode::CBC, the mode may be PaddingMode::NONE
+ * or PaddingMode::PKCS7. If the padding mode doesn't meet these conditions, begin() must
+ * return ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * If the block mode is BlockMode::CBC, BlockMode::CTR, or BlockMode::GCM, an initialization
+ * vector or nonce is required. In most cases, callers shouldn't provide an IV or nonce and the
+ * IKeyMintDevice implementation must generate a random IV or nonce and return it via
+ * Tag::NONCE in outParams. CBC and CTR IVs are 16 bytes. GCM nonces are 12 bytes. If the key
+ * authorizations contain Tag::CALLER_NONCE, then the caller may provide an IV/nonce with
+ * Tag::NONCE in inParams. If a nonce is provided when Tag::CALLER_NONCE is not authorized,
+ * begin() must return ErrorCode::CALLER_NONCE_PROHIBITED. If a nonce is not provided when
+ * Tag::CALLER_NONCE is authorized, IKeyMintDevice msut generate a random IV/nonce.
+ *
+ * -- HMAC keys --
+ *
+ * HMAC key operations must specify Tag::MAC_LENGTH in inParams. The specified value must be a
+ * multiple of 8 that is not greater than the digest length or less than the value of
+ * Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than the digest
+ * length or non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For
+ * values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH.
+ *
+ * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT,
+ * KeyPurpose::DECRYPT, KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD
+ * modes, encryption and decryption imply signing and verification, respectively, but
+ * must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+ *
+ * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey(). The key
+ * must have a purpose compatible with purpose and all of its usage requirements must be
+ * satisfied, or begin() must return an appropriate error code (see above).
+ *
+ * @param inParams Additional parameters for the operation. If Tag::APPLICATION_ID or
+ * Tag::APPLICATION_DATA were provided during generation, they must be provided here, or
+ * the operation must fail with ErrorCode::INVALID_KEY_BLOB. For operations that require
+ * a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may
+ * contain a tag Tag::NONCE. If Tag::NONCE is provided for a key without
+ * Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+ *
+ * @param inAuthToken Authentication token. Callers that provide no token must set all numeric
+ * fields to zero and the MAC must be an empty vector. TODO: make this field nullable.
+ * b/173483024.
+ *
+ * @return BeginResult as output, which contains the challenge, KeyParameters which haves
+ * additional data from the operation initialization, notably to return the IV or nonce
+ * from operations that generate an IV or nonce, and IKeyMintOperation object pointer
+ * which is used to perform update(), finish() or abort() operations.
+ */
+ BeginResult begin(in KeyPurpose inPurpose,
+ in byte[] inKeyBlob,
+ in KeyParameter[] inParams,
+ in HardwareAuthToken inAuthToken);
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
new file mode 100644
index 0000000..24960cc
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.ByteArray;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameterArray;
+import android.hardware.security.keymint.VerificationToken;
+
+@VintfStability
+interface IKeyMintOperation {
+ /**
+ * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
+ * with begin().
+ *
+ * If operation is in an invalid state (was aborted or had an error) update() must return
+ * ErrorCode::INVALID_OPERATION_HANDLE.
+ *
+ * To provide more flexibility for buffer handling, implementations of this method have the
+ * option of consuming less data than was provided. The caller is responsible for looping to
+ * feed the rest of the data in subsequent calls. The amount of input consumed must be returned
+ * in the inputConsumed parameter. Implementations must always consume at least one byte,
+ * unless the operation cannot accept any more; if more than zero bytes are provided and zero
+ * bytes are consumed, callers must consider this an error and abort the operation.
+ * TODO(seleneh) update the code to always consume alll the input data. b/168665179.
+ *
+ * Implementations may also choose how much data to return, as a result of the update. This is
+ * only relevant for encryption and decryption operations, because signing and verification
+ * return no data until finish. It is recommended to return data as early as possible, rather
+ * than buffer it.
+ *
+ * If this method returns an error code other than ErrorCode::OK, the operation is aborted and
+ * the operation handle must be invalidated. Any future use of the handle, with this method,
+ * finish, or abort, must return ErrorCode::INVALID_OPERATION_HANDLE.
+ *
+ * == Authorization Enforcement ==
+ *
+ * Key authorization enforcement is performed primarily in begin(). The one exception is the
+ * case where the key has:
+ *
+ * o One or more Tag::USER_SECURE_IDs, and
+ *
+ * o Does not have a Tag::AUTH_TIMEOUT
+ *
+ * In this case, the key requires an authorization per operation, and the update method must
+ * receive a non-empty and valid HardwareAuthToken. For the auth token to be valid, all of the
+ * following has to be true:
+ *
+ * o The HMAC field must validate correctly.
+ *
+ * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+ * the secure ID values in the token.
+ *
+ * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+ *
+ * o The challenge field in the auth token must contain the operationHandle
+ *
+ * If any of these conditions are not met, update() must return
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * The caller must provide the auth token on every call to update() and finish().
+ *
+ * -- RSA keys --
+ *
+ * For signing and verification operations with Digest::NONE, this method must accept the entire
+ * block to be signed or verified in a single update. It may not consume only a portion of the
+ * block in these cases. However, the caller may choose to provide the data in multiple
+ * updates, and update() must accept the data this way as well. If the caller provides more
+ * data to sign than can be used (length of data exceeds RSA key size), update() must return
+ * ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * -- ECDSA keys --
+ *
+ * For signing and verification operations with Digest::NONE, this method must accept the entire
+ * block to be signed or verified in a single update. This method may not consume only a
+ * portion of the block. However, the caller may choose to provide the data in multiple updates
+ * and update() must accept the data this way as well. If the caller provides more data to sign
+ * than can be used, the data is silently truncated. (This differs from the handling of excess
+ * data provided in similar RSA operations. The reason for this is compatibility with legacy
+ * clients.)
+ *
+ * -- AES keys --
+ *
+ * AES GCM mode supports "associated authentication data," provided via the Tag::ASSOCIATED_DATA
+ * tag in the inParams argument. The associated data may be provided in repeated calls
+ * (important if the data is too large to send in a single block) but must always precede data
+ * to be encrypted or decrypted. An update call may receive both associated data and data to
+ * encrypt/decrypt, but subsequent updates must not include associated data. If the caller
+ * provides associated data to an update call after a call that includes data to
+ * encrypt/decrypt, update() must return ErrorCode::INVALID_TAG.
+ *
+ * For GCM encryption, the AEAD tag must be appended to the ciphertext by finish(). During
+ * decryption, the last Tag::MAC_LENGTH bytes of the data provided to the last update call must
+ * be the AEAD tag. Since a given invocation of update cannot know if it's the last invocation,
+ * it must process all but the tag length and buffer the possible tag data for processing during
+ * finish().
+ *
+ * TODO: update() needs to be refactored b/168665179.
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA. Note that additional data may be provided in multiple
+ * calls to update(), but only until input data has been provided.
+ *
+ * @param input Data to be processed. Note that update() may or may not consume all of the data
+ * provided. See return value.
+ *
+ * @param verificationToken Verification token, used to prove that another IKeymasterDevice HAL
+ * has verified some parameters, and to deliver the other HAL's current timestamp, if
+ * needed. If not provided, all fields must be initialized to zero and vectors must be
+ * empty.
+ *
+ * @return error Returns ErrorCode encountered in keymint as service specific errors. See the
+ * ErrorCode enum in ErrorCode.aidl.
+ *
+ * @return int Amount of data that was consumed by update(). If this is less than the
+ * amount provided, the caller may provide the remainder in a subsequent call to
+ * update() or finish(). Every call to update must consume at least one byte, unless
+ * the input is empty, and implementations should consume as much data as reasonably
+ * possible for each call.
+ *
+ * @return outParams returns the updated key parameters from the blob, if needed.
+ * operation.
+ *
+ * @return out variable output The output data, if any.
+ */
+ int update(in @nullable KeyParameterArray inParams,
+ in @nullable byte[] input,
+ in @nullable HardwareAuthToken inAuthToken,
+ in @nullable VerificationToken inVerificationToken,
+ out @nullable KeyParameterArray outParams,
+ out @nullable ByteArray output);
+
+ /**
+ * Finalizes a cryptographic operation begun with begin() and invalidates operation.
+ *
+ * This method is the last one called in an operation, so all processed data must be returned.
+ *
+ * Whether it completes successfully or returns an error, this method finalizes the operation.
+ * Any future use of the operation, with finish(), update(), or abort(), must return
+ * ErrorCode::INVALID_OPERATION_HANDLE.
+ *
+ * Signing operations return the signature as the output. Verification operations accept the
+ * signature in the signature parameter, and return no output.
+ *
+ * == Authorization enforcement ==
+ *
+ * Key authorization enforcement is performed primarily in begin(). The exceptions are
+ * authorization per operation keys and confirmation-required keys.
+ *
+ * Authorization per operation keys are the case where the key has one or more
+ * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT. In this case, the key requires
+ * an authorization per operation, and the finish method must receive a non-empty and valid
+ * authToken. For the auth token to be valid, all of the following has to be true:
+ *
+ * o The HMAC field must validate correctly.
+ *
+ * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+ * the secure ID values in the token.
+ *
+ * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+ *
+ * o The challenge field in the auth token must contain the operation challenge.
+ *
+ * If any of these conditions are not met, update() must return
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * The caller must provide the auth token on every call to update() and finish().
+ *
+ * Confirmation-required keys are keys that were generated with
+ * Tag::TRUSTED_CONFIRMATION_REQUIRED. For these keys, when doing a signing operation the
+ * caller must pass a KeyParameter Tag::CONFIRMATION_TOKEN to finish(). Implementations must
+ * check the confirmation token by computing the 32-byte HMAC-SHA256 over all of the
+ * to-be-signed data, prefixed with the 18-byte UTF-8 encoded string "confirmation token". If
+ * the computed value does not match the Tag::CONFIRMATION_TOKEN parameter, finish() must not
+ * produce a signature and must return ErrorCode::NO_USER_CONFIRMATION.
+ *
+ * -- RSA keys --
+ *
+ * Some additional requirements, depending on the padding mode:
+ *
+ * o PaddingMode::NONE. For unpadded signing and encryption operations, if the provided data is
+ * shorter than the key, the data must be zero-padded on the left before
+ * signing/encryption. If the data is the same length as the key, but numerically larger,
+ * finish() must return ErrorCode::INVALID_ARGUMENT. For verification and decryption
+ * operations, the data must be exactly as long as the key. Otherwise, return
+ * ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * o PaddingMode::RSA_PSS. For PSS-padded signature operations, the PSS salt length must match
+ * the size of the PSS digest selected. The digest specified with Tag::DIGEST in inputParams
+ * on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask
+ * generation function and SHA1 must be used as the MGF1 digest algorithm.
+ *
+ * o PaddingMode::RSA_OAEP. The digest specified with Tag::DIGEST in inputParams on begin is
+ * used as the OAEP digest algorithm, MGF1 must be used as the mask generation function and
+ * and SHA1 must be used as the MGF1 digest algorithm.
+ *
+ * -- ECDSA keys --
+ *
+ * If the data provided for unpadded signing or verification is too long, truncate it.
+ *
+ * -- AES keys --
+ *
+ * Some additional conditions, depending on block mode:
+ *
+ * o BlockMode::ECB or BlockMode::CBC. If padding is PaddingMode::NONE and the data length is
+ * not a multiple of the AES block size, finish() must return
+ * ErrorCode::INVALID_INPUT_LENGTH. If padding is PaddingMode::PKCS7, pad the data per the
+ * PKCS#7 specification, including adding an additional padding block if the data is a multiple
+ * of the block length.
+ *
+ * o BlockMode::GCM. During encryption, after processing all plaintext, compute the tag
+ * (Tag::MAC_LENGTH bytes) and append it to the returned ciphertext. During decryption,
+ * process the last Tag::MAC_LENGTH bytes as the tag. If tag verification fails, finish()
+ * must return ErrorCode::VERIFICATION_FAILED.
+ *
+ * TODO: update() will need to be refactored into 2 function. b/168665179.
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update().
+ *
+ * @param input Data to be processed, per the parameters established in the call to begin().
+ * finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * @param signature The signature to be verified if the purpose specified in the begin() call
+ * was KeyPurpose::VERIFY.
+ *
+ * @param authToken Authentication token. Can be nullable if not provided.
+ *
+ * @param verificationToken Verification token, used to prove that another IKeyMintDevice HAL
+ * has verified some parameters, and to deliver the other HAL's current timestamp, if
+ * needed. Can be nullable if not needed.
+ *
+ * @return outParams Any output parameters generated by finish().
+ *
+ * @return The output data, if any.
+ */
+ byte[] finish(in @nullable KeyParameterArray inParams, in @nullable byte[] input,
+ in @nullable byte[] inSignature,
+ in @nullable HardwareAuthToken authToken,
+ in @nullable VerificationToken inVerificationToken,
+ out @nullable KeyParameterArray outParams);
+
+ /**
+ * Aborts a cryptographic operation begun with begin(), freeing all internal resources. If an
+ * operation was finalized, calling update, finish, or abort yields
+ * ErrorCode::INVALID_OPERATION_HANDLE. An operation is finalized if finish or abort was
+ * called on it, or if update returned an ErrorCode.
+ *
+ * @param operationHandle The operation handle returned by begin(). This handle must be
+ * invalid when abort() returns.
+ *
+ * @return error See the ErrorCode enum in ErrorCode.aidl.
+ */
+ void abort();
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
new file mode 100644
index 0000000..0801868
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * KeyCharacteristics defines the attributes of a key, including cryptographic parameters, and usage
+ * restrictions. It consits of two vectors of KeyParameters, one for "softwareEnforced" attributes
+ * and one for "hardwareEnforced" attributes.
+ *
+ * KeyCharacteristics objects are returned by generateKey, importKey, importWrappedKey and
+ * getKeyCharacteristics. The IKeyMintDevice secure environment is responsible for allocating the
+ * parameters, all of which are Tags with associated values, to the correct vector. The
+ * hardwareEnforced vector must contain only those attributes which are enforced by secure hardware.
+ * All others should be in the softwareEnforced vector. See the definitions of individual Tag enums
+ * for specification of which must be hardware-enforced, which may be software-enforced and which
+ * must never appear in KeyCharacteristics.
+ */
+@VintfStability
+parcelable KeyCharacteristics {
+ /* TODO(seleneh) get rid of the software enforced in keymint. replace hardware enforced with
+ * tee enforced and strongbox enforced.
+ */
+ KeyParameter[] softwareEnforced;
+ KeyParameter[] hardwareEnforced;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyDerivationFunction.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyDerivationFunction.aidl
new file mode 100644
index 0000000..e166ab6
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyDerivationFunction.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Key derivation functions, mostly used in ECIES.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyDerivationFunction {
+ /** Do not apply a key derivation function; use the raw agreed key */
+ NONE = 0,
+ /** HKDF defined in RFC 5869 with SHA256 */
+ RFC5869_SHA256 = 1,
+ /** KDF1 defined in ISO 18033-2 with SHA1 */
+ ISO18033_2_KDF1_SHA1 = 2,
+ /** KDF1 defined in ISO 18033-2 with SHA256 */
+ ISO18033_2_KDF1_SHA256 = 3,
+ /** KDF2 defined in ISO 18033-2 with SHA1 */
+ ISO18033_2_KDF2_SHA1 = 4,
+ /** KDF2 defined in ISO 18033-2 with SHA256 */
+ ISO18033_2_KDF2_SHA256 = 5,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl
new file mode 100644
index 0000000..6ad8e3d
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Formats for key import and export.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyFormat {
+ /** X.509 certificate format, for public key export. */
+ X509 = 0,
+ /** PCKS#8 format, asymmetric key pair import. */
+ PKCS8 = 1,
+ /** Raw bytes, for symmetric key import. */
+ RAW = 3,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
new file mode 100644
index 0000000..d3d7368
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.SecurityLevel;
+
+/**
+ * KeyMintHardwareInfo is the hardware information returned by calling KeyMint getHardwareInfo()
+ */
+@VintfStability
+parcelable KeyMintHardwareInfo {
+ /**
+ * Implementation version of the keymint hardware. The version number is implementation
+ * defined, and not necessarily globally meaningful. The version is used to distinguish
+ * between different versions of a given implementation.
+ * TODO(seleneh) add the version related info to the code.
+ */
+ int versionNumber;
+
+ /* securityLevel is the security level of the IKeyMintDevice implementation accessed
+ * through this aidl package. */
+ SecurityLevel securityLevel;
+
+ /* keyMintName is the name of the IKeyMintDevice implementation. */
+ @utf8InCpp String keyMintName;
+
+ /* keyMintAuthorName is the name of the author of the IKeyMintDevice implementation
+ * (organization name, not individual). This name is implementation defined,
+ * so it can be used to distinguish between different implementations from the
+ * same author.
+ */
+ @utf8InCpp String keyMintAuthorName;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl
new file mode 100644
index 0000000..0cd53c2
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * The origin of a key (or pair), i.e. where it was generated. Note that ORIGIN can be found in
+ * either the hardware-enforced or software-enforced list for a key, indicating whether the key is
+ * hardware or software-based. Specifically, a key with GENERATED in the hardware-enforced list
+ * must be guaranteed never to have existed outide the secure hardware.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyOrigin {
+ /** Generated in keyMint. Should not exist outside the TEE. */
+ GENERATED = 0,
+
+ /** Derived inside keyMint. Likely exists off-device. */
+ DERIVED = 1,
+
+ /** Imported into keyMint. Existed as cleartext in Android. */
+ IMPORTED = 2,
+
+ /** Previously used for another purpose that is now obsolete. */
+ RESERVED = 3,
+
+ /**
+ * Securely imported into KeyMint. Was created elsewhere, and passed securely through Android
+ * to secure hardware.
+ */
+ SECURELY_IMPORTED = 4,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyParameter.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyParameter.aidl
new file mode 100644
index 0000000..938064c
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyParameter.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.Algorithm;
+import android.hardware.security.keymint.BlockMode;
+import android.hardware.security.keymint.Digest;
+import android.hardware.security.keymint.EcCurve;
+import android.hardware.security.keymint.HardwareAuthenticatorType;
+import android.hardware.security.keymint.KeyDerivationFunction;
+import android.hardware.security.keymint.KeyOrigin;
+import android.hardware.security.keymint.KeyPurpose;
+import android.hardware.security.keymint.PaddingMode;
+import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Tag;
+
+
+/**
+ * Identifies the key authorization parameters to be used with keyMint. This is usually
+ * provided as an array of KeyParameters to IKeyMintDevice or Operation.
+ *
+ * TODO(seleneh): Union was not supported in aidl when this cl is first drafted. So we just had
+ * the Tags, and bool, int, long, int[], and we will cast to the appropate types base on the
+ * Tag value. We need to update this defination to distingish Algorithm, BlockMode,
+ * PaddingMode, KeyOrigin...etc later, as union support is recently added to aidl.
+ * b/173253030
+ */
+@VintfStability
+parcelable KeyParameter {
+ /**
+ * Identify what type of key parameter this parcelable actually holds, and based on the type
+ * of tag is int, long, bool, or byte[], one of the fields below will be referenced.
+ */
+ Tag tag;
+
+ boolean boolValue;
+ int integer;
+ long longInteger;
+ // TODO: change this to nullable.
+ byte[] blob;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyParameterArray.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyParameterArray.aidl
new file mode 100644
index 0000000..acab435
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyParameterArray.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * Identifies the key authorization parameters to be used with keyMint. This is usually
+ * provided as an array of KeyParameters to IKeyMintDevice or Operation.
+ */
+@VintfStability
+parcelable KeyParameterArray {
+ /**
+ * Identify list of key parameters corresponding to a particular key blob.
+ */
+ KeyParameter[] params;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
new file mode 100644
index 0000000..cb4682e
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+@VintfStability
+@Backing(type = "int")
+enum KeyPurpose {
+ /* Usable with RSA, EC and AES keys. */
+ ENCRYPT = 0,
+
+ /* Usable with RSA, EC and AES keys. */
+ DECRYPT = 1,
+
+ /* Usable with RSA, EC and HMAC keys. */
+ SIGN = 2,
+
+ /* Usable with RSA, EC and HMAC keys. */
+ VERIFY = 3,
+
+ /* 4 is reserved */
+ /* Usable with wrapping keys. */
+ WRAP_KEY = 5,
+
+ /* TODO(seleneh) add AGREE_KEY and ATTEST_KEY and their corresponding codes and tests later*/
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
new file mode 100644
index 0000000..80b73bd
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * TODO(seleneh) update the description.
+ *
+ * Padding modes that may be applied to plaintext for encryption operations. This list includes
+ * padding modes for both symmetric and asymmetric algorithms. Note that implementations should not
+ * provide all possible combinations of algorithm and padding, only the
+ * cryptographically-appropriate pairs.
+ */
+@VintfStability
+@Backing(type="int")
+enum PaddingMode {
+ NONE = 1, /* deprecated */
+ RSA_OAEP = 2,
+ RSA_PSS = 3,
+ RSA_PKCS1_1_5_ENCRYPT = 4,
+ RSA_PKCS1_1_5_SIGN = 5,
+ PKCS7 = 64,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/SecurityLevel.aidl b/security/keymint/aidl/android/hardware/security/keymint/SecurityLevel.aidl
new file mode 100644
index 0000000..10363e9
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/SecurityLevel.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * Device security levels.
+ */
+@VintfStability
+@Backing(type="int")
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ /**
+ * STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD
+ * 9.11.2.
+ */
+ STRONGBOX = 2,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
new file mode 100644
index 0000000..532bc5d
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -0,0 +1,892 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.TagType;
+
+// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as
+// ROOT_OF_TRUST = TagType:BYTES | 704. So we are forced to write definations as
+// ROOT_OF_TRUST = (9 << 28) for now. Will need to flip this back later when aidl support is added.
+
+/**
+ * Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of
+ * data are stored in KeyParameter.
+ */
+@VintfStability
+@Backing(type = "int")
+enum Tag {
+ /**
+ * Tag::INVALID should never be set. It means you hit an error.
+ */
+ INVALID = (0 << 28) | 0,
+
+ /**
+ * Tag::PURPOSE specifies the set of purposes for which the key may be used. Possible values
+ * are defined in the KeyPurpose enumeration.
+ *
+ * This tag is repeatable; keys may be generated with multiple values, although an operation has
+ * a single purpose. When begin() is called to start an operation, the purpose of the operation
+ * is specified. If the purpose specified for the operation is not authorized by the key (the
+ * key didn't have a corresponding Tag::PURPOSE provided during generation/import), the
+ * operation must fail with ErrorCode::INCOMPATIBLE_PURPOSE.
+ *
+ * Must be hardware-enforced.
+ */
+ PURPOSE = (2 << 28) | 1, /* TagType:ENUM_REP */
+
+ /**
+ * Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used. This tag
+ * must be provided to generateKey and importKey, and must be specified in the wrapped key
+ * provided to importWrappedKey.
+ *
+ * Must be hardware-enforced.
+ */
+ ALGORITHM = (1 << 28) | 2, /* TagType:ENUM */
+
+ /**
+ * Tag::KEY_SIZE pecifies the size, in bits, of the key, measuring in the normal way for the
+ * key's algorithm. For example, for RSA keys, Tag::KEY_SIZE specifies the size of the public
+ * modulus. For AES keys it specifies the length of the secret key material. For 3DES keys it
+ * specifies the length of the key material, not counting parity bits (though parity bits must
+ * be provided for import, etc.). Since only three-key 3DES keys are supported, 3DES
+ * Tag::KEY_SIZE must be 168.
+ *
+ * Must be hardware-enforced.
+ */
+ KEY_SIZE = (3 << 28) | 3, /* TagType:UINT */
+
+ /**
+ * Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used. This tag
+ * is only relevant to AES and 3DES keys. Possible values are defined by the BlockMode enum.
+ *
+ * This tag is repeatable for key generation/import. For AES and 3DES operations the caller
+ * must specify a Tag::BLOCK_MODE in the additionalParams argument of begin(). If the mode is
+ * missing or the specified mode is not in the modes specified for the key during
+ * generation/import, the operation must fail with ErrorCode::INCOMPATIBLE_BLOCK_MODE.
+ *
+ * Must be hardware-enforced.
+ */
+ BLOCK_MODE = (2 << 28) | 4,
+ /* BlockMode. */ /* TagType:ENUM_REP */
+
+ /**
+ * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
+ * and verification operations. This tag is relevant to RSA, ECDSA and HMAC keys. Possible
+ * values are defined by the Digest enum.
+ *
+ * This tag is repeatable for key generation/import. For signing and verification operations,
+ * the caller must specify a digest in the additionalParams argument of begin(). If the digest
+ * is missing or the specified digest is not in the digests associated with the key, the
+ * operation must fail with ErrorCode::INCOMPATIBLE_DIGEST.
+ *
+ * Must be hardware-enforced.
+ */
+ DIGEST = (2 << 28) | 5, /* TagType:ENUM_REP */
+
+ /**
+ * Tag::PADDING specifies the padding modes that may be used with the key. This tag is relevant
+ * to RSA, AES and 3DES keys. Possible values are defined by the PaddingMode enum.
+ *
+ * PaddingMode::RSA_OAEP and PaddingMode::RSA_PKCS1_1_5_ENCRYPT are used only for RSA
+ * encryption/decryption keys and specify RSA OAEP padding and RSA PKCS#1 v1.5 randomized
+ * padding, respectively. PaddingMode::RSA_PSS and PaddingMode::RSA_PKCS1_1_5_SIGN are used
+ * only for RSA signing/verification keys and specify RSA PSS padding and RSA PKCS#1 v1.5
+ * deterministic padding, respectively.
+ *
+ * PaddingMode::NONE may be used with either RSA, AES or 3DES keys. For AES or 3DES keys, if
+ * PaddingMode::NONE is used with block mode ECB or CBC and the data to be encrypted or
+ * decrypted is not a multiple of the AES block size in length, the call to finish() must fail
+ * with ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * PaddingMode::PKCS7 may only be used with AES and 3DES keys, and only with ECB and CBC modes.
+ *
+ * In any case, if the caller specifies a padding mode that is not usable with the key's
+ * algorithm, the generation or import method must return ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * This tag is repeatable. A padding mode must be specified in the call to begin(). If the
+ * specified mode is not authorized for the key, the operation must fail with
+ * ErrorCode::INCOMPATIBLE_BLOCK_MODE.
+ *
+ * Must be hardware-enforced.
+ */
+ PADDING = (2 << 28) | 6, /* TagType:ENUM_REP */
+
+ /**
+ * Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring
+ * operations. This tag is boolean, so the possible values are true (if the tag is present) and
+ * false (if the tag is not present).
+ *
+ * This tag is used only for AES and 3DES keys, and is only relevant for CBC, CTR and GCM block
+ * modes. If the tag is not present in a key's authorization list, implementations must reject
+ * any operation that provides Tag::NONCE to begin() with ErrorCode::CALLER_NONCE_PROHIBITED.
+ *
+ * Must be hardware-enforced.
+ */
+ CALLER_NONCE = (7 << 28) | 7, /* TagType:BOOL */
+
+ /**
+ * Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified
+ * with this key for HMAC keys and AES keys that support GCM mode.
+ *
+ * This value is the minimum MAC length, in bits. It must be a multiple of 8 bits. For HMAC
+ * keys, the value must be least 64 and no more than 512. For GCM keys, the value must be at
+ * least 96 and no more than 128. If the provided value violates these requirements,
+ * generateKey() or importKey() must return ErrorCode::UNSUPPORTED_KEY_SIZE.
+ *
+ * Must be hardware-enforced.
+ */
+ MIN_MAC_LENGTH = (3 << 28) | 8, /* TagType:UINT */
+
+ // Tag 9 reserved
+
+ /**
+ * Tag::EC_CURVE specifies the elliptic curve. EC key generation requests may have
+ * Tag:EC_CURVE, Tag::KEY_SIZE, or both. If both are provided and the size and curve do not
+ * match, IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ *
+ * Must be hardware-enforced.
+ */
+ EC_CURVE = (1 << 28) | 10, /* TagType:ENUM */
+
+ /**
+ * Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair.
+ * This tag is relevant only to RSA keys, and is required for all RSA keys.
+ *
+ * The value is a 64-bit unsigned integer that satisfies the requirements of an RSA public
+ * exponent. This value must be a prime number. IKeyMintDevice implementations must support
+ * the value 2^16+1 and may support other reasonable values. If no exponent is specified or if
+ * the specified exponent is not supported, key generation must fail with
+ * ErrorCode::INVALID_ARGUMENT.
+ *
+ * Must be hardware-enforced.
+ */
+ RSA_PUBLIC_EXPONENT = (5 << 28) | 200, /* TagType:ULONG */
+
+ // Tag 201 reserved
+
+ /**
+ * Tag::INCLUDE_UNIQUE_ID is specified during key generation to indicate that an attestation
+ * certificate for the generated key should contain an application-scoped and time-bounded
+ * device-unique ID. See Tag::UNIQUE_ID.
+ *
+ * Must be hardware-enforced.
+ */
+ INCLUDE_UNIQUE_ID = (7 << 28) | 202, /* TagType:BOOL */
+
+ /**
+ * TODO(seleneh) this tag needs to be deleted from all codes.
+ *
+ * Tag::BLOB_USAGE_REQUIREMENTS specifies the necessary system environment conditions for the
+ * generated key to be used. Possible values are defined by the KeyBlobUsageRequirements enum.
+ *
+ * This tag is specified by the caller during key generation or import to require that the key
+ * is usable in the specified condition. If the caller specifies Tag::BLOB_USAGE_REQUIREMENTS
+ * with value KeyBlobUsageRequirements::STANDALONE the IKeyMintDevice must return a key blob
+ * that can be used without file system support. This is critical for devices with encrypted
+ * disks, where the file system may not be available until after a KeyMint key is used to
+ * decrypt the disk.
+ *
+ * Must be hardware-enforced.
+ */
+ BLOB_USAGE_REQUIREMENTS = (1 << 28) | 301, /* TagType:ENUM */
+
+ /**
+ * Tag::BOOTLOADER_ONLY specifies only the bootloader can use the key.
+ *
+ * Any attempt to use a key with Tag::BOOTLOADER_ONLY from the Android system must fail with
+ * ErrorCode::INVALID_KEY_BLOB.
+ *
+ * Must be hardware-enforced.
+ */
+ BOOTLOADER_ONLY = (7 << 28) | 302, /* TagType:BOOL */
+
+ /**
+ * Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when
+ * deleted with deleteKey() or deleteAllKeys(), the key is guaranteed to be permanently deleted
+ * and unusable. It's possible that keys without this tag could be deleted and then restored
+ * from backup.
+ *
+ * This tag is specified by the caller during key generation or import to require. If the
+ * IKeyMintDevice cannot guarantee rollback resistance for the specified key, it must return
+ * ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE. IKeyMintDevice implementations are not
+ * required to support rollback resistance.
+ *
+ * Must be hardwared-enforced.
+ */
+ ROLLBACK_RESISTANCE = (7 << 28) | 303, /* TagType:BOOL */
+
+ // Reserved for future use.
+ HARDWARE_TYPE = (1 << 28) | 304, /* TagType:ENUM */
+
+ /**
+ * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until
+ * IKeyMintDevice::earlyBootEnded() is called.
+ */
+ EARLY_BOOT_ONLY = (7 << 28) | 305, /* TagType:BOOL */
+
+ /**
+ * Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in
+ * milliseconds since Jan 1, 1970. If a key with this tag is used prior to the specified date
+ * and time, IKeyMintDevice::begin() must return ErrorCode::KEY_NOT_YET_VALID;
+ *
+ * Need not be hardware-enforced.
+ */
+ ACTIVE_DATETIME = (6 << 28) | 400,
+ /* Start of validity. */ /* TagType:DATE */
+
+ /**
+ * Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for
+ * signing and encryption purposes. After this time, any attempt to use a key with
+ * KeyPurpose::SIGN or KeyPurpose::ENCRYPT provided to begin() must fail with
+ * ErrorCode::KEY_EXPIRED.
+ *
+ * The value is a 64-bit integer representing milliseconds since January 1, 1970.
+ *
+ * Need not be hardware-enforced.
+ */
+ ORIGINATION_EXPIRE_DATETIME = (6 << 28) | 401, /* TagType:DATE */
+
+ /**
+ * Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for
+ * verification and decryption purposes. After this time, any attempt to use a key with
+ * KeyPurpose::VERIFY or KeyPurpose::DECRYPT provided to begin() must fail with
+ * ErrorCode::KEY_EXPIRED.
+ *
+ * The value is a 64-bit integer representing milliseconds since January 1, 1970.
+ *
+ * Need not be hardware-enforced.
+ */
+ USAGE_EXPIRE_DATETIME = (6 << 28) | 402, /* TagType:DATE */
+
+ /**
+ * TODO(seleneh) this tag need to be deleted.
+ *
+ * TODO(seleneh) this tag need to be deleted.
+ *
+ * Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between
+ * allowed operations using a key. This can be used to rate-limit uses of keys in contexts
+ * where unlimited use may enable brute force attacks.
+ *
+ * The value is a 32-bit integer representing seconds between allowed operations.
+ *
+ * When a key with this tag is used in an operation, the IKeyMintDevice must start a timer
+ * during the finish() or abort() call. Any call to begin() that is received before the timer
+ * indicates that the interval specified by Tag::MIN_SECONDS_BETWEEN_OPS has elapsed must fail
+ * with ErrorCode::KEY_RATE_LIMIT_EXCEEDED. This implies that the IKeyMintDevice must keep a
+ * table of use counters for keys with this tag. Because memory is often limited, this table
+ * may have a fixed maximum size and KeyMint may fail operations that attempt to use keys with
+ * this tag when the table is full. The table must acommodate at least 8 in-use keys and
+ * aggressively reuse table slots when key minimum-usage intervals expire. If an operation
+ * fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
+ *
+ * Must be hardware-enforced.
+ */
+ MIN_SECONDS_BETWEEN_OPS = (3 << 28) | 403, /* TagType:UINT */
+
+ /**
+ * Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between
+ * system reboots. This is another mechanism to rate-limit key use.
+ *
+ * The value is a 32-bit integer representing uses per boot.
+ *
+ * When a key with this tag is used in an operation, a key-associated counter must be
+ * incremented during the begin() call. After the key counter has exceeded this value, all
+ * subsequent attempts to use the key must fail with ErrorCode::MAX_OPS_EXCEEDED, until the
+ * device is restarted. This implies that the IKeyMintDevice must keep a table of use
+ * counters for keys with this tag. Because KeyMint memory is often limited, this table can
+ * have a fixed maximum size and KeyMint can fail operations that attempt to use keys with
+ * this tag when the table is full. The table needs to acommodate at least 8 keys. If an
+ * operation fails because the table is full, IKeyMintDevice must
+ * ErrorCode::TOO_MANY_OPERATIONS.
+ *
+ * Must be hardware-enforced.
+ */
+ MAX_USES_PER_BOOT = (3 << 28) | 404, /* TagType:UINT */
+
+ /**
+ * Tag::USER_ID specifies the ID of the Android user that is permitted to use the key.
+ *
+ * Must not be hardware-enforced.
+ */
+ USER_ID = (3 << 28) | 501, /* TagType:UINT */
+
+ /**
+ * Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user
+ * authentication state. This tag is mutually exclusive with Tag::NO_AUTH_REQUIRED.
+ *
+ * The value is a 64-bit integer specifying the authentication policy state value which must be
+ * present in the userId or authenticatorId field of a HardwareAuthToken provided to begin(),
+ * update(), or finish(). If a key with Tag::USER_SECURE_ID is used without a HardwareAuthToken
+ * with the matching userId or authenticatorId, the IKeyMintDevice must return
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * Tag::USER_SECURE_ID interacts with Tag::AUTH_TIMEOUT in a very important way. If
+ * Tag::AUTH_TIMEOUT is present in the key's characteristics then the key is a "timeout-based"
+ * key, and may only be used if the difference between the current time when begin() is called
+ * and the timestamp in the HardwareAuthToken is less than the value in Tag::AUTH_TIMEOUT * 1000
+ * (the multiplier is because Tag::AUTH_TIMEOUT is in seconds, but the HardwareAuthToken
+ * timestamp is in milliseconds). Otherwise the IKeyMintDevice must returrn
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * If Tag::AUTH_TIMEOUT is not present, then the key is an "auth-per-operation" key. In this
+ * case, begin() must not require a HardwareAuthToken with appropriate contents. Instead,
+ * update() and finish() must receive a HardwareAuthToken with Tag::USER_SECURE_ID value in
+ * userId or authenticatorId fields, and the current operation's operation handle in the
+ * challenge field. Otherwise the IKeyMintDevice must returrn
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * This tag is repeatable. If repeated, and any one of the values matches the HardwareAuthToken
+ * as described above, the key is authorized for use. Otherwise the operation must fail with
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
+ * Must be hardware-enforced.
+ */
+ USER_SECURE_ID = (10 << 28) | 502, /* TagType:ULONG_REP */
+
+ /**
+ * Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key. This tag
+ * is mutually exclusive with Tag::USER_SECURE_ID.
+ *
+ * Must be hardware-enforced.
+ */
+ NO_AUTH_REQUIRED = (7 << 28) | 503, /* TagType:BOOL */
+
+ /**
+ * Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize
+ * this key.
+ *
+ * The value is one or more values from HardwareAuthenticatorType, ORed together.
+ *
+ * When IKeyMintDevice is requested to perform an operation with a key with this tag, it must
+ * receive a HardwareAuthToken and one or more bits must be set in both the HardwareAuthToken's
+ * authenticatorType field and the Tag::USER_AUTH_TYPE value. That is, it must be true that
+ *
+ * (token.authenticatorType & tag_user_auth_type) != 0
+ *
+ * where token.authenticatorType is the authenticatorType field of the HardwareAuthToken and
+ * tag_user_auth_type is the value of Tag:USER_AUTH_TYPE.
+ *
+ * Must be hardware-enforced.
+ */
+ USER_AUTH_TYPE = (1 << 28) | 504, /* TagType:ENUM */
+
+ /**
+ * Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
+ * after user authentication. If
+ * Tag::USER_SECURE_ID is present and this tag is not, then the key requies authentication for
+ * every usage (see begin() for the details of the authentication-per-operation flow).
+ *
+ * The value is a 32-bit integer specifying the time in seconds after a successful
+ * authentication of the user specified by Tag::USER_SECURE_ID with the authentication method
+ * specified by Tag::USER_AUTH_TYPE that the key can be used.
+ *
+ * Must be hardware-enforced.
+ */
+ AUTH_TIMEOUT = (3 << 28) | 505, /* TagType:UINT */
+
+ /**
+ * Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if
+ * device is still on-body (requires on-body sensor).
+ *
+ * Cannot be hardware-enforced.
+ */
+ ALLOW_WHILE_ON_BODY = (7 << 28) | 506, /* TagType:BOOL */
+
+ /**
+ * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
+ * unusable except when the user has provided proof of physical presence. Proof of physical
+ * presence must be a signal that cannot be triggered by an attacker who doesn't have one of:
+ *
+ * a) Physical control of the device or
+ *
+ * b) Control of the secure environment that holds the key.
+ *
+ * For instance, proof of user identity may be considered proof of presence if it meets the
+ * requirements. However, proof of identity established in one security domain (e.g. TEE) does
+ * not constitute proof of presence in another security domain (e.g. StrongBox), and no
+ * mechanism analogous to the authentication token is defined for communicating proof of
+ * presence across security domains.
+ *
+ * Some examples:
+ *
+ * A hardware button hardwired to a pin on a StrongBox device in such a way that nothing
+ * other than a button press can trigger the signal constitutes proof of physical presence
+ * for StrongBox keys.
+ *
+ * Fingerprint authentication provides proof of presence (and identity) for TEE keys if the
+ * TEE has exclusive control of the fingerprint scanner and performs fingerprint matching.
+ *
+ * Password authentication does not provide proof of presence to either TEE or StrongBox,
+ * even if TEE or StrongBox does the password matching, because password input is handled by
+ * the non-secure world, which means an attacker who has compromised Android can spoof
+ * password authentication.
+ *
+ * Note that no mechanism is defined for delivering proof of presence to an IKeyMintDevice,
+ * except perhaps as implied by an auth token. This means that KeyMint must be able to check
+ * proof of presence some other way. Further, the proof of presence must be performed between
+ * begin() and the first call to update() or finish(). If the first update() or the finish()
+ * call is made without proof of presence, the keyMint method must return
+ * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation. The caller must delay the
+ * update() or finish() call until proof of presence has been provided, which means the caller
+ * must also have some mechanism for verifying that the proof has been provided.
+ *
+ * Only one operation requiring TUP may be in flight at a time. If begin() has already been
+ * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
+ * key or another with TRUSTED_USER_PRESENCE_REQUIRED, KeyMint must return
+ * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+ *
+ * Must be hardware-enforced.
+ */
+ TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) | 507, /* TagType:BOOL */
+
+ /** Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
+ * specifies that this key must not be usable unless the user provides confirmation of the data
+ * to be signed. Confirmation is proven to keyMint via an approval token. See
+ * CONFIRMATION_TOKEN, as well as the ConfirmatinUI HAL.
+ *
+ * If an attempt to use a key with this tag does not have a cryptographically valid
+ * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
+ * match the data described in the token, keyMint must return NO_USER_CONFIRMATION.
+ *
+ * Must be hardware-enforced.
+ */
+ TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) | 508, /* TagType:BOOL */
+
+ /**
+ * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
+ * unlocked.
+ *
+ * Must be software-enforced.
+ */
+ UNLOCKED_DEVICE_REQUIRED = (7 << 28) | 509, /* TagType:BOOL */
+
+ /**
+ * Tag::APPLICATION_ID. When provided to generateKey or importKey, this tag specifies data
+ * that is necessary during all uses of the key. In particular, calls to exportKey() and
+ * getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to
+ * begin must provide this tag and the same associated data as part of the inParams set. If
+ * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ *
+ * The content of this tag must be bound to the key cryptographically, meaning it must not be
+ * possible for an adversary who has access to all of the secure world secrets but does not have
+ * access to the tag content to decrypt the key without brute-forcing the tag content, which
+ * applications can prevent by specifying sufficiently high-entropy content.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ APPLICATION_ID = (9 << 28) | 601, /* TagType:BYTES */
+
+ /*
+ * Semantically unenforceable tags, either because they have no specific meaning or because
+ * they're informational only.
+ */
+
+ /**
+ * Tag::APPLICATION_DATA. When provided to generateKey or importKey, this tag specifies data
+ * that is necessary during all uses of the key. In particular, calls to exportKey() and
+ * getKeyCharacteristics() must provide the same value to the appData parameter, and calls to
+ * begin must provide this tag and the same associated data as part of the inParams set. If
+ * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ *
+ * The content of this tag msut be bound to the key cryptographically, meaning it must not be
+ * possible for an adversary who has access to all of the secure world secrets but does not have
+ * access to the tag content to decrypt the key without brute-forcing the tag content, which
+ * applications can prevent by specifying sufficiently high-entropy content.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ APPLICATION_DATA = (9 << 28) | 700, /* TagType:BYTES */
+
+ /**
+ * Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
+ * January 1, 1970. This tag is optional and informational only.
+ *
+ * Tag::CREATED is informational only, and not enforced by anything. Must be in the
+ * software-enforced list, if provided.
+ */
+ CREATION_DATETIME = (6 << 28) | 701, /* TagType:DATE */
+
+ /**
+ * Tag::ORIGIN specifies where the key was created, if known. This tag must not be specified
+ * during key generation or import, and must be added to the key characteristics by the
+ * IKeyMintDevice. The possible values are defined in the KeyOrigin enum.
+ *
+ * Must be hardware-enforced.
+ */
+ ORIGIN = (1 << 28) | 702, /* TagType:ENUM */
+
+ // 703 is unused.
+
+ /**
+ * Tag::ROOT_OF_TRUST specifies the root of trust associated with the key used by verified boot
+ * to validate the system. It describes the boot key, verified boot state, boot hash, and
+ * whether device is locked. This tag is never provided to or returned from KeyMint in the
+ * key characteristics. It exists only to define the tag for use in the attestation record.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ROOT_OF_TRUST = (9 << 28) | 704, /* TagType:BYTES */
+
+ /**
+ * Tag::OS_VERSION specifies the system OS version with which the key may be used. This tag is
+ * never sent to the IKeyMintDevice, but is added to the hardware-enforced authorization list
+ * by the TA. Any attempt to use a key with a Tag::OS_VERSION value different from the
+ * currently-running OS version must cause begin(), getKeyCharacteristics() or exportKey() to
+ * return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
+ *
+ * The value of the tag is an integer of the form MMmmss, where MM is the major version number,
+ * mm is the minor version number, and ss is the sub-minor version number. For example, for a
+ * key generated on Android version 4.0.3, the value would be 040003.
+ *
+ * The IKeyMintDevice HAL must read the current OS version from the system property
+ * ro.build.version.release and deliver it to the secure environment when the HAL is first
+ * loaded (mechanism is implementation-defined). The secure environment must not accept another
+ * version until after the next boot. If the content of ro.build.version.release has additional
+ * version information after the sub-minor version number, it must not be included in
+ * Tag::OS_VERSION. If the content is non-numeric, the secure environment must use 0 as the
+ * system version.
+ *
+ * Must be hardware-enforced.
+ */
+ OS_VERSION = (3 << 28) | 705, /* TagType:UINT */
+
+ /**
+ * Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
+ * This tag is never sent to the keyMint TA, but is added to the hardware-enforced
+ * authorization list by the TA. Any attempt to use a key with a Tag::OS_PATCHLEVEL value
+ * different from the currently-running system patchlevel must cause begin(),
+ * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See
+ * upgradeKey() for details.
+ *
+ * The value of the tag is an integer of the form YYYYMM, where YYYY is the four-digit year of
+ * the last update and MM is the two-digit month of the last update. For example, for a key
+ * generated on an Android device last updated in December 2015, the value would be 201512.
+ *
+ * The IKeyMintDevice HAL must read the current system patchlevel from the system property
+ * ro.build.version.security_patch and deliver it to the secure environment when the HAL is
+ * first loaded (mechanism is implementation-defined). The secure environment must not accept
+ * another patchlevel until after the next boot.
+ *
+ * Must be hardware-enforced.
+ */
+ OS_PATCHLEVEL = (3 << 28) | 706, /* TagType:UINT */
+
+ /**
+ * Tag::UNIQUE_ID specifies a unique, time-based identifier. This tag is never provided to or
+ * returned from KeyMint in the key characteristics. It exists only to define the tag for use
+ * in the attestation record.
+ *
+ * When a key with Tag::INCLUDE_UNIQUE_ID is attested, the unique ID is added to the attestation
+ * record. The value is a 128-bit hash that is unique per device and per calling application,
+ * and changes monthly and on most password resets. It is computed with:
+ *
+ * HMAC_SHA256(T || C || R, HBK)
+ *
+ * Where:
+ *
+ * T is the "temporal counter value", computed by dividing the value of
+ * Tag::CREATION_DATETIME by 2592000000, dropping any remainder. T changes every 30 days
+ * (2592000000 = 30 * 24 * 60 * 60 * 1000).
+ *
+ * C is the value of Tag::ATTESTATION_APPLICATION_ID that is provided to attestKey().
+ *
+ * R is 1 if Tag::RESET_SINCE_ID_ROTATION was provided to attestKey or 0 if the tag was not
+ * provided.
+ *
+ * HBK is a unique hardware-bound secret known to the secure environment and never revealed
+ * by it. The secret must contain at least 128 bits of entropy and be unique to the
+ * individual device (probabilistic uniqueness is acceptable).
+ *
+ * HMAC_SHA256 is the HMAC function, with SHA-2-256 as the hash.
+ *
+ * The output of the HMAC function must be truncated to 128 bits.
+ *
+ * Must be hardware-enforced.
+ */
+ UNIQUE_ID = (9 << 28) | 707, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attestKey() method,
+ * which must place the value in the KeyDescription SEQUENCE of the attestation extension. See
+ * attestKey().
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_CHALLENGE = (9 << 28) | 708, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
+ * only with attestKey().
+ *
+ * The content of Tag::ATTESTATION_APPLICATION_ID is a DER-encoded ASN.1 structure, with the
+ * following schema:
+ *
+ * AttestationApplicationId ::= SEQUENCE {
+ * packageInfoRecords SET OF PackageInfoRecord,
+ * signatureDigests SET OF OCTET_STRING,
+ * }
+ *
+ * PackageInfoRecord ::= SEQUENCE {
+ * packageName OCTET_STRING,
+ * version INTEGER,
+ * }
+ *
+ * See system/security/keystore/keystore_attestation_id.cpp for details of construction.
+ * IKeyMintDevice implementers do not need to create or parse the ASN.1 structure, but only
+ * copy the tag value into the attestation record. The DER-encoded string must not exceed 1 KiB
+ * in length.
+ *
+ * Cannot be hardware-enforced.
+ */
+ ATTESTATION_APPLICATION_ID = (9 << 28) | 709, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
+ * Android, to attestKey(). This field must be set only when requesting attestation of the
+ * device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_BRAND = (9 << 28) | 710, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
+ * Android, to attestKey(). This field must be set only when requesting attestation of the
+ * device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_DEVICE = (9 << 28) | 711, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
+ * in Android, to attestKey(). This field must be set only when requesting attestation of the
+ * device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_PRODUCT = (9 << 28) | 712, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_SERIAL the device's serial number. This field must be set only when
+ * requesting attestation of the device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_SERIAL = (9 << 28) | 713, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attestKey().
+ * This field must be set only when requesting attestation of the device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_IMEI = (9 << 28) | 714, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attestKey().
+ * This field must be set only when requesting attestation of the device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_MEID = (9 << 28) | 715, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
+ * Build.MANUFACTURER in Android, to attstKey(). This field must be set only when requesting
+ * attestation of the device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_MANUFACTURER = (9 << 28) | 716, /* TagType:BYTES */
+
+ /**
+ * Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
+ * Android, to attestKey(). This field must be set only when requesting attestation of the
+ * device's identifiers.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_MODEL = (9 << 28) | 717, /* TagType:BYTES */
+
+ /**
+ * Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
+ * be used. This tag is never sent to the keyMint TA, but is added to the hardware-enforced
+ * authorization list by the TA. Any attempt to use a key with a Tag::VENDOR_PATCHLEVEL value
+ * different from the currently-running system patchlevel must cause begin(),
+ * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See
+ * upgradeKey() for details.
+ *
+ * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
+ * the last update, MM is the two-digit month and DD is the two-digit day of the last
+ * update. For example, for a key generated on an Android device last updated on June 5, 2018,
+ * the value would be 20180605.
+ *
+ * The IKeyMintDevice HAL must read the current vendor patchlevel from the system property
+ * ro.vendor.build.security_patch and deliver it to the secure environment when the HAL is first
+ * loaded (mechanism is implementation-defined). The secure environment must not accept another
+ * patchlevel until after the next boot.
+ *
+ * Must be hardware-enforced.
+ */
+ VENDOR_PATCHLEVEL = (3 << 28) | 718, /* TagType:UINT */
+
+ /**
+ * Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the
+ * key may be used. This tag is never sent to the keyMint TA, but is added to the
+ * hardware-enforced authorization list by the TA. Any attempt to use a key with a
+ * Tag::BOOT_PATCHLEVEL value different from the currently-running system patchlevel must
+ * cause begin(), getKeyCharacteristics() or exportKey() to return
+ * ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
+ *
+ * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
+ * the last update, MM is the two-digit month and DD is the two-digit day of the last
+ * update. For example, for a key generated on an Android device last updated on June 5, 2018,
+ * the value would be 20180605. If the day is not known, 00 may be substituted.
+ *
+ * During each boot, the bootloader must provide the patch level of the boot image to the secure
+ * envirionment (mechanism is implementation-defined).
+ *
+ * Must be hardware-enforced.
+ */
+ BOOT_PATCHLEVEL = (3 << 28) | 719, /* TagType:UINT */
+
+ /**
+ * DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attestKey(). It indicates that
+ * attestation using a device-unique key is requested, rather than a batch key. When a
+ * device-unique key is used, only the attestation certificate is returned; no additional
+ * chained certificates are provided. It's up to the caller to recognize the device-unique
+ * signing key. Only SecurityLevel::STRONGBOX IKeyMintDevices may support device-unique
+ * attestations. SecurityLevel::TRUSTED_ENVIRONMENT IKeyMintDevices must return
+ * ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION.
+ * SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and
+ * return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
+ *
+ * IKeyMintDevice implementations that support device-unique attestation MUST add the
+ * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
+ */
+ DEVICE_UNIQUE_ATTESTATION = (7 << 28) | 720, /* TagType:BOOL */
+
+ /**
+ * IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key
+ * generation or any operation, is never returned by any method and is never used in a key
+ * attestation. It is used in attestations produced by the IIdentityCredential HAL when that
+ * HAL attests to Credential Keys. IIdentityCredential produces KeyMint-style attestations.
+ */
+ IDENTITY_CREDENTIAL_KEY = (7 << 28) | 721, /* TagType:BOOL */
+
+ /**
+ * To prevent keys from being compromised if an attacker acquires read access to system / kernel
+ * memory, some inline encryption hardware supports protecting storage encryption keys in
+ * hardware without software having access to or the ability to set the plaintext keys.
+ * Instead, software only sees wrapped version of these keys.
+ *
+ * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
+ * encryption. Keys of this type can either be generated or imported or secure imported using
+ * keyMint. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key
+ * wrapped key once the key characteristics are enforced.
+ *
+ * Keys with this tag cannot be used for any operation within keyMint.
+ * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
+ * begin().
+ */
+ STORAGE_KEY = (7 << 28) | 722, /* TagType:BOOL */
+
+ /**
+ * Tag::ASSOCIATED_DATA Provides "associated data" for AES-GCM encryption or decryption. This
+ * tag is provided to update and specifies data that is not encrypted/decrypted, but is used in
+ * computing the GCM tag.
+ *
+ * Must never appear KeyCharacteristics.
+ */
+ ASSOCIATED_DATA = (9 << 28) | 1000, /* TagType:BYTES */
+
+ /**
+ * Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
+ * AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption. This tag is provided to begin during
+ * encryption and decryption operations. It is only provided to begin if the key has
+ * Tag::CALLER_NONCE. If not provided, an appropriate nonce or IV must be randomly generated by
+ * KeyMint and returned from begin.
+ *
+ * The value is a blob, an arbitrary-length array of bytes. Allowed lengths depend on the mode:
+ * GCM nonces are 12 bytes in length; AES-CBC and AES-CTR IVs are 16 bytes in length, 3DES-CBC
+ * IVs are 8 bytes in length.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ NONCE = (9 << 28) | 1001, /* TagType:BYTES */
+
+ /**
+ * Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits.
+ *
+ * The value is the MAC length in bits. It must be a multiple of 8 and at least as large as the
+ * value of Tag::MIN_MAC_LENGTH associated with the key. Otherwise, begin() must return
+ * ErrorCode::INVALID_MAC_LENGTH.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ MAC_LENGTH = (3 << 28) | 1003, /* TagType:UINT */
+
+ /**
+ * Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the
+ * last unique ID rotation. Used for key attestation.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ RESET_SINCE_ID_ROTATION = (7 << 28) | 1004, /* TagType:BOOL */
+
+ /**
+ * Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user
+ * confirmed a signing request. The content is a full-length HMAC-SHA256 value. See the
+ * ConfirmationUI HAL for details of token computation.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ CONFIRMATION_TOKEN = (9 << 28) | 1005, /* TagType:BYTES */
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/TagType.aidl b/security/keymint/aidl/android/hardware/security/keymint/TagType.aidl
new file mode 100644
index 0000000..a273af3
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/TagType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+/**
+ * TagType classifies Tags in Tag.aidl into various groups of data.
+ */
+@VintfStability
+@Backing(type="int")
+enum TagType {
+ /** Invalid type, used to designate a tag as uninitialized. */
+ INVALID = 0 << 28,
+ /** Enumeration value. */
+ ENUM = 1 << 28,
+ /** Repeatable enumeration value. */
+ ENUM_REP = 2 << 28,
+ /** 32-bit unsigned integer. */
+ UINT = 3 << 28,
+ /** Repeatable 32-bit unsigned integer. */
+ UINT_REP = 4 << 28,
+ /** 64-bit unsigned integer. */
+ ULONG = 5 << 28,
+ /** 64-bit unsigned integer representing a date and time, in milliseconds since 1 Jan 1970. */
+ DATE = 6 << 28,
+ /** Boolean. If a tag with this type is present, the value is "true". If absent, "false". */
+ BOOL = 7 << 28,
+ /** Byte string containing an arbitrary-length integer, big-endian ordering. */
+ BIGNUM = 8 << 28,
+ /** Byte string */
+ BYTES = 9 << 28,
+ /** Repeatable 64-bit unsigned integer */
+ ULONG_REP = 10 << 28,
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Timestamp.aidl b/security/keymint/aidl/android/hardware/security/keymint/Timestamp.aidl
new file mode 100644
index 0000000..ebb3684
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/Timestamp.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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.hardware.security.keymint;
+
+/**
+ * Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+@VintfStability
+parcelable Timestamp {
+ long milliSeconds;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/VerificationToken.aidl b/security/keymint/aidl/android/hardware/security/keymint/VerificationToken.aidl
new file mode 100644
index 0000000..f76e6a8
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/VerificationToken.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 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.hardware.security.keymint;
+
+import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Timestamp;
+
+/**
+ * VerificationToken instances are used for secure environments to authenticate one another.
+ *
+ * This version of the parcelable currently don't use the parametersVerified field since it's not
+ * needed for time-based verification. This can be added in a later version, if needed.
+ */
+@VintfStability
+parcelable VerificationToken {
+ /**
+ * The operation handle, used to ensure freshness.
+ */
+ long challenge;
+
+ /**
+ * The current time of the secure environment that generates the VerificationToken. This can be
+ * checked against auth tokens generated by the same secure environment, which avoids needing to
+ * synchronize clocks.
+ */
+ Timestamp timestamp;
+
+ /**
+ * SecurityLevel of the secure environment that generated the token.
+ */
+ SecurityLevel securityLevel;
+
+ /**
+ * 32-byte HMAC-SHA256 of the above values, computed as:
+ *
+ * HMAC(H,
+ * "Auth Verification" || challenge || timestamp || securityLevel)
+ *
+ * where:
+ *
+ * ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeyMint).
+ *
+ * ``||'' represents concatenation
+ *
+ * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
+ * order. securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+ */
+ byte[] mac;
+}
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
new file mode 100644
index 0000000..491a2c1
--- /dev/null
+++ b/security/keymint/aidl/default/Android.bp
@@ -0,0 +1,26 @@
+cc_binary {
+ name: "android.hardware.security.keymint-service",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.security.keymint-service.rc"],
+ vintf_fragments: ["android.hardware.security.keymint-service.xml"],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "android.hardware.security.keymint-ndk_platform",
+ "libbase",
+ "libbinder_ndk",
+ "libcppbor",
+ "libcrypto",
+ "libkeymaster_portable",
+ "libkeymint",
+ "liblog",
+ "libpuresoftkeymasterdevice",
+ "libutils",
+ ],
+ srcs: [
+ "service.cpp",
+ ],
+}
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.rc b/security/keymint/aidl/default/android.hardware.security.keymint-service.rc
new file mode 100644
index 0000000..0c3a6e1
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.rc
@@ -0,0 +1,3 @@
+service vendor.keymint-default /vendor/bin/hw/android.hardware.security.keymint-service
+ class early_hal
+ user nobody
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
new file mode 100644
index 0000000..73d15a8
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IKeyMintDevice/default</fqname>
+ </hal>
+</manifest>
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
new file mode 100644
index 0000000..a710535
--- /dev/null
+++ b/security/keymint/aidl/default/service.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-service"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <AndroidKeyMintDevice.h>
+#include <keymaster/soft_keymaster_logger.h>
+
+using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
+using aidl::android::hardware::security::keymint::SecurityLevel;
+
+int main() {
+ // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
+ // the pool size to 1.
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<AndroidKeyMintDevice> keyMint =
+ ndk::SharedRefBase::make<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
+
+ keymaster::SoftKeymasterLogger logger;
+ const auto instanceName = std::string(AndroidKeyMintDevice::descriptor) + "/default";
+ LOG(INFO) << "instance: " << instanceName;
+ binder_status_t status =
+ AServiceManager_addService(keyMint->asBinder().get(), instanceName.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..ef7adb1
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -0,0 +1,66 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_test {
+ name: "VtsAidlKeyMintTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "KeyMintTest.cpp",
+ "VerificationTokenTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libkeymint",
+ "libkeymint_support",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-cpp",
+ "libcppbor_external",
+ "libkeymint_vts_test_utils",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
+cc_test_library {
+ name: "libkeymint_vts_test_utils",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "KeyMintAidlTestBase.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libkeymint",
+ "libkeymint_support",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-cpp",
+ "libcppbor",
+ ],
+}
diff --git a/security/keymint/aidl/vts/functional/AndroidTest.xml b/security/keymint/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..43e7a8a
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs VtsAidlKeyMintV1_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsAidlKeyMintV1_0TargetTest->/data/local/tmp/VtsAidlKeyMintV1_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsAidlKeyMintV1_0TargetTest" />
+ <option name="native-test-timeout" value="900000"/>
+ </test>
+</configuration>
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
new file mode 100644
index 0000000..ea3a329
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -0,0 +1,753 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "KeyMintAidlTestBase.h"
+
+#include <chrono>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/keymint_utils.h>
+
+namespace android::hardware::security::keymint {
+
+using namespace std::literals::chrono_literals;
+using std::endl;
+using std::optional;
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+ if (set.size() == 0)
+ os << "(Empty)" << ::std::endl;
+ else {
+ os << "\n";
+ for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
+ }
+ return os;
+}
+
+namespace test {
+
+ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(Status result) {
+ if (result.isOk()) return ErrorCode::OK;
+
+ if (result.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
+ return static_cast<ErrorCode>(result.serviceSpecificErrorCode());
+ }
+
+ return ErrorCode::UNKNOWN_ERROR;
+}
+
+void KeyMintAidlTestBase::InitializeKeyMint(sp<IKeyMintDevice> keyMint) {
+ ASSERT_NE(keyMint, nullptr);
+ keymint_ = keyMint;
+
+ KeyMintHardwareInfo info;
+ ASSERT_TRUE(keymint_->getHardwareInfo(&info).isOk());
+
+ securityLevel_ = info.securityLevel;
+ name_.assign(info.keyMintName.begin(), info.keyMintName.end());
+ author_.assign(info.keyMintAuthorName.begin(), info.keyMintAuthorName.end());
+
+ os_version_ = getOsVersion();
+ os_patch_level_ = getOsPatchlevel();
+}
+
+void KeyMintAidlTestBase::SetUp() {
+ InitializeKeyMint(
+ android::waitForDeclaredService<IKeyMintDevice>(String16(GetParam().c_str())));
+}
+
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+ vector<uint8_t>* keyBlob, KeyCharacteristics* keyChar) {
+ EXPECT_NE(keyBlob, nullptr) << "Key blob pointer must not be null. Test bug";
+ EXPECT_NE(keyChar, nullptr)
+ << "Previous characteristics not deleted before generating key. Test bug.";
+
+ // Aidl does not clear these output parameters if the function returns
+ // error. This is different from hal where output parameter is always
+ // cleared due to hal returning void. So now we need to do our own clearing
+ // of the output variables prior to calling keyMint aidl libraries.
+ keyBlob->clear();
+ keyChar->softwareEnforced.clear();
+ keyChar->hardwareEnforced.clear();
+ certChain_.clear();
+
+ Status result;
+ ByteArray blob;
+
+ result = keymint_->generateKey(key_desc.vector_data(), &blob, keyChar, &certChain_);
+
+ // On result, blob & characteristics should be empty.
+ if (result.isOk()) {
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(keyChar->hardwareEnforced.size(), 0);
+ }
+ EXPECT_GT(keyChar->softwareEnforced.size(), 0);
+ // TODO(seleneh) in a later version where we return @nullable
+ // single Certificate, check non-null single certificate is always
+ // non-empty.
+ *keyBlob = blob.data;
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
+ return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material, vector<uint8_t>* key_blob,
+ KeyCharacteristics* key_characteristics) {
+ Status result;
+
+ certChain_.clear();
+ key_characteristics->softwareEnforced.clear();
+ key_characteristics->hardwareEnforced.clear();
+ key_blob->clear();
+
+ ByteArray blob;
+ result = keymint_->importKey(key_desc.vector_data(), format,
+ vector<uint8_t>(key_material.begin(), key_material.end()), &blob,
+ key_characteristics, &certChain_);
+
+ if (result.isOk()) {
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ }
+ EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
+ *key_blob = blob.data;
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material) {
+ return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapping_key,
+ const AuthorizationSet& wrapping_key_desc,
+ string masking_key,
+ const AuthorizationSet& unwrapping_params) {
+ Status result;
+ EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
+
+ ByteArray outBlob;
+ key_characteristics_.softwareEnforced.clear();
+ key_characteristics_.hardwareEnforced.clear();
+
+ result = keymint_->importWrappedKey(vector<uint8_t>(wrapped_key.begin(), wrapped_key.end()),
+ key_blob_,
+ vector<uint8_t>(masking_key.begin(), masking_key.end()),
+ unwrapping_params.vector_data(), 0 /* passwordSid */,
+ 0 /* biometricSid */, &outBlob, &key_characteristics_);
+
+ if (result.isOk()) {
+ key_blob_ = outBlob.data;
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(key_characteristics_.hardwareEnforced.size(), 0);
+ }
+ EXPECT_GT(key_characteristics_.softwareEnforced.size(), 0);
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
+ Status result = keymint_->deleteKey(*key_blob);
+ if (!keep_key_blob) {
+ *key_blob = vector<uint8_t>();
+ }
+
+ EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl;
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteKey(bool keep_key_blob) {
+ return DeleteKey(&key_blob_, keep_key_blob);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteAllKeys() {
+ Status result = keymint_->deleteAllKeys();
+ EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl;
+ return GetReturnErrorCode(result);
+}
+
+void KeyMintAidlTestBase::CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
+ ErrorCode result = DeleteKey(key_blob, keep_key_blob);
+ EXPECT_TRUE(result == ErrorCode::OK || result == ErrorCode::UNIMPLEMENTED) << result << endl;
+}
+
+void KeyMintAidlTestBase::CheckedDeleteKey() {
+ CheckedDeleteKey(&key_blob_);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+ const AuthorizationSet& in_params,
+ AuthorizationSet* out_params, sp<IKeyMintOperation>& op) {
+ SCOPED_TRACE("Begin");
+ Status result;
+ BeginResult out;
+ result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+
+ if (result.isOk()) {
+ *out_params = out.params;
+ challenge_ = out.challenge;
+ op = out.operation;
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+ const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("Begin");
+ Status result;
+ BeginResult out;
+
+ result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+
+ if (result.isOk()) {
+ *out_params = out.params;
+ challenge_ = out.challenge;
+ op_ = out.operation;
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("Begin");
+ EXPECT_EQ(nullptr, op_);
+ return Begin(purpose, key_blob_, in_params, out_params);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+ SCOPED_TRACE("Begin");
+ AuthorizationSet out_params;
+ ErrorCode result = Begin(purpose, in_params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Update(const AuthorizationSet& in_params, const string& input,
+ AuthorizationSet* out_params, string* output,
+ int32_t* input_consumed) {
+ SCOPED_TRACE("Update");
+
+ Status result;
+ EXPECT_NE(op_, nullptr);
+ if (!op_) {
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+
+ KeyParameterArray key_params;
+ key_params.params = in_params.vector_data();
+
+ KeyParameterArray in_keyParams;
+ in_keyParams.params = in_params.vector_data();
+
+ optional<KeyParameterArray> out_keyParams;
+ optional<ByteArray> o_put;
+ result = op_->update(in_keyParams, vector<uint8_t>(input.begin(), input.end()), {}, {},
+ &out_keyParams, &o_put, input_consumed);
+
+ if (result.isOk()) {
+ if (o_put) {
+ output->append(o_put->data.begin(), o_put->data.end());
+ }
+
+ if (out_keyParams) {
+ out_params->push_back(AuthorizationSet(out_keyParams->params));
+ }
+ }
+
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Update(const string& input, string* out, int32_t* input_consumed) {
+ SCOPED_TRACE("Update");
+ AuthorizationSet out_params;
+ ErrorCode result =
+ Update(AuthorizationSet() /* in_params */, input, &out_params, out, input_consumed);
+ EXPECT_TRUE(out_params.empty());
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const AuthorizationSet& in_params, const string& input,
+ const string& signature, AuthorizationSet* out_params,
+ string* output) {
+ SCOPED_TRACE("Finish");
+ Status result;
+
+ EXPECT_NE(op_, nullptr);
+ if (!op_) {
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+
+ KeyParameterArray key_params;
+ key_params.params = in_params.vector_data();
+
+ KeyParameterArray in_keyParams;
+ in_keyParams.params = in_params.vector_data();
+
+ optional<KeyParameterArray> out_keyParams;
+ optional<vector<uint8_t>> o_put;
+
+ vector<uint8_t> oPut;
+ result = op_->finish(in_keyParams, vector<uint8_t>(input.begin(), input.end()),
+ vector<uint8_t>(signature.begin(), signature.end()), {}, {},
+ &out_keyParams, &oPut);
+
+ if (result.isOk()) {
+ if (out_keyParams) {
+ out_params->push_back(AuthorizationSet(out_keyParams->params));
+ }
+
+ output->append(oPut.begin(), oPut.end());
+ }
+
+ op_.clear(); // So dtor doesn't Abort().
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const string& message, string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ string finish_output;
+ ErrorCode result = Finish(AuthorizationSet() /* in_params */, message, "" /* signature */,
+ &out_params, output);
+ if (result != ErrorCode::OK) {
+ return result;
+ }
+ EXPECT_EQ(0U, out_params.size());
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const string& message, const string& signature,
+ string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ ErrorCode result =
+ Finish(AuthorizationSet() /* in_params */, message, signature, &out_params, output);
+
+ if (result != ErrorCode::OK) {
+ return result;
+ }
+
+ EXPECT_EQ(0U, out_params.size());
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Abort(const sp<IKeyMintOperation>& op) {
+ SCOPED_TRACE("Abort");
+
+ EXPECT_NE(op, nullptr);
+ if (!op) {
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+
+ Status retval = op->abort();
+ EXPECT_TRUE(retval.isOk());
+ return static_cast<ErrorCode>(retval.serviceSpecificErrorCode());
+}
+
+ErrorCode KeyMintAidlTestBase::Abort() {
+ SCOPED_TRACE("Abort");
+
+ EXPECT_NE(op_, nullptr);
+ if (!op_) {
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+
+ Status retval = op_->abort();
+ return static_cast<ErrorCode>(retval.serviceSpecificErrorCode());
+}
+
+void KeyMintAidlTestBase::AbortIfNeeded() {
+ SCOPED_TRACE("AbortIfNeeded");
+ if (op_) {
+ EXPECT_EQ(ErrorCode::OK, Abort());
+ op_.clear();
+ }
+}
+
+string KeyMintAidlTestBase::ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("ProcessMessage");
+ AuthorizationSet begin_out_params;
+ ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params);
+ EXPECT_EQ(ErrorCode::OK, result);
+ if (result != ErrorCode::OK) {
+ return "";
+ }
+
+ string output;
+ int32_t consumed = 0;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ result = Update(update_params, message, &update_out_params, &output, &consumed);
+ EXPECT_EQ(ErrorCode::OK, result);
+ if (result != ErrorCode::OK) {
+ return "";
+ }
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(finish_params, message.substr(consumed), unused, &finish_out_params, &output));
+
+ out_params->push_back(begin_out_params);
+ out_params->push_back(finish_out_params);
+ return output;
+}
+
+string KeyMintAidlTestBase::SignMessage(const vector<uint8_t>& key_blob, const string& message,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet out_params;
+ string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return signature;
+}
+
+string KeyMintAidlTestBase::SignMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ return SignMessage(key_blob_, message, params);
+}
+
+string KeyMintAidlTestBase::MacMessage(const string& message, Digest digest, size_t mac_length) {
+ SCOPED_TRACE("MacMessage");
+ return SignMessage(
+ key_blob_, message,
+ AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+}
+
+void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
+ Digest digest, const string& expected_mac) {
+ SCOPED_TRACE("CheckHmacTestVector");
+ ASSERT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(key.size() * 8)
+ .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+ .Digest(digest),
+ KeyFormat::RAW, key));
+ string signature = MacMessage(message, digest, expected_mac.size() * 8);
+ EXPECT_EQ(expected_mac, signature)
+ << "Test vector didn't match for key of size " << key.size() << " message of size "
+ << message.size() << " and digest " << digest;
+ CheckedDeleteKey();
+}
+
+void KeyMintAidlTestBase::CheckAesCtrTestVector(const string& key, const string& nonce,
+ const string& message,
+ const string& expected_ciphertext) {
+ SCOPED_TRACE("CheckAesCtrTestVector");
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .BlockMode(BlockMode::CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::RAW, key));
+
+ auto params = AuthorizationSetBuilder()
+ .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+ EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+void KeyMintAidlTestBase::CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+ PaddingMode padding_mode, const string& key,
+ const string& iv, const string& input,
+ const string& expected_output) {
+ auto authset = AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(key.size() * 7)
+ .BlockMode(block_mode)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(padding_mode);
+ if (iv.size()) authset.Authorization(TAG_CALLER_NONCE);
+ ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key));
+ ASSERT_GT(key_blob_.size(), 0U);
+
+ auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+ if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size());
+ AuthorizationSet output_params;
+ string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params);
+ EXPECT_EQ(expected_output, output);
+}
+
+void KeyMintAidlTestBase::VerifyMessage(const vector<uint8_t>& key_blob, const string& message,
+ const string& signature, const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params));
+
+ string output;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ int32_t consumed;
+ ASSERT_EQ(ErrorCode::OK,
+ Update(update_params, message, &update_out_params, &output, &consumed));
+ EXPECT_TRUE(output.empty());
+ EXPECT_GT(consumed, 0U);
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(finish_params, message.substr(consumed), signature,
+ &finish_out_params, &output));
+ op_.clear();
+ EXPECT_TRUE(output.empty());
+}
+
+void KeyMintAidlTestBase::VerifyMessage(const string& message, const string& signature,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ VerifyMessage(key_blob_, message, signature, params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
+ const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return EncryptMessage(key_blob_, message, params, out_params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("EncryptMessage");
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+ return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+ return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding, vector<uint8_t>* iv_out) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(1U, out_params.size());
+ auto ivVal = out_params.GetTagValue(TAG_NONCE);
+ EXPECT_TRUE(ivVal.isOk());
+ if (ivVal.isOk()) *iv_out = ivVal.value();
+ return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding, const vector<uint8_t>& iv_in) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(padding)
+ .Authorization(TAG_NONCE, iv_in);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding, uint8_t mac_length_bits,
+ const vector<uint8_t>& iv_in) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(padding)
+ .Authorization(TAG_MAC_LENGTH, mac_length_bits)
+ .Authorization(TAG_NONCE, iv_in);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ return ciphertext;
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const vector<uint8_t>& key_blob,
+ const string& ciphertext,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet out_params;
+ string plaintext =
+ ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return plaintext;
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext, BlockMode block_mode,
+ PaddingMode padding_mode, const vector<uint8_t>& iv) {
+ SCOPED_TRACE("DecryptMessage");
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(padding_mode)
+ .Authorization(TAG_NONCE, iv);
+ return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+std::pair<ErrorCode, vector<uint8_t>> KeyMintAidlTestBase::UpgradeKey(
+ const vector<uint8_t>& key_blob) {
+ std::pair<ErrorCode, vector<uint8_t>> retval;
+ vector<uint8_t> outKeyBlob;
+ Status result = keymint_->upgradeKey(key_blob, vector<KeyParameter>(), &outKeyBlob);
+ ErrorCode errorcode = GetReturnErrorCode(result);
+ retval = std::tie(errorcode, outKeyBlob);
+
+ return retval;
+}
+vector<uint32_t> KeyMintAidlTestBase::ValidKeySizes(Algorithm algorithm) {
+ switch (algorithm) {
+ case Algorithm::RSA:
+ switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
+ case SecurityLevel::TRUSTED_ENVIRONMENT:
+ return {2048, 3072, 4096};
+ case SecurityLevel::STRONGBOX:
+ return {2048};
+ default:
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+ break;
+ }
+ break;
+ case Algorithm::EC:
+ switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
+ case SecurityLevel::TRUSTED_ENVIRONMENT:
+ return {224, 256, 384, 521};
+ case SecurityLevel::STRONGBOX:
+ return {256};
+ default:
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+ break;
+ }
+ break;
+ case Algorithm::AES:
+ return {128, 256};
+ case Algorithm::TRIPLE_DES:
+ return {168};
+ case Algorithm::HMAC: {
+ vector<uint32_t> retval((512 - 64) / 8 + 1);
+ uint32_t size = 64 - 8;
+ std::generate(retval.begin(), retval.end(), [&]() { return (size += 8); });
+ return retval;
+ }
+ default:
+ ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
+ return {};
+ }
+ ADD_FAILURE() << "Should be impossible to get here";
+ return {};
+}
+
+vector<uint32_t> KeyMintAidlTestBase::InvalidKeySizes(Algorithm algorithm) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ switch (algorithm) {
+ case Algorithm::RSA:
+ return {3072, 4096};
+ case Algorithm::EC:
+ return {224, 384, 521};
+ case Algorithm::AES:
+ return {192};
+ default:
+ return {};
+ }
+ }
+ return {};
+}
+
+vector<EcCurve> KeyMintAidlTestBase::ValidCurves() {
+ if (securityLevel_ == SecurityLevel::STRONGBOX) {
+ return {EcCurve::P_256};
+ } else {
+ return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+ }
+}
+
+vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() {
+ if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
+ CHECK(SecLevel() == SecurityLevel::STRONGBOX);
+ return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+}
+
+vector<Digest> KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) {
+ switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
+ case SecurityLevel::TRUSTED_ENVIRONMENT:
+ if (withNone) {
+ if (withMD5)
+ return {Digest::NONE, Digest::MD5, Digest::SHA1,
+ Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+ Digest::SHA_2_512};
+ else
+ return {Digest::NONE, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+ } else {
+ if (withMD5)
+ return {Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+ else
+ return {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+ Digest::SHA_2_512};
+ }
+ break;
+ case SecurityLevel::STRONGBOX:
+ if (withNone)
+ return {Digest::NONE, Digest::SHA_2_256};
+ else
+ return {Digest::SHA_2_256};
+ break;
+ default:
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+ break;
+ }
+ ADD_FAILURE() << "Should be impossible to get here";
+ return {};
+}
+
+} // namespace test
+
+} // namespace android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
new file mode 100644
index 0000000..76effcf
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef VTS_KEYMINT_AIDL_TEST_UTILS_H
+#define VTS_KEYMINT_AIDL_TEST_UTILS_H
+
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android/hardware/security/keymint/ErrorCode.h>
+#include <android/hardware/security/keymint/IKeyMintDevice.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+#include <keymint_support/authorization_set.h>
+
+namespace android::hardware::security::keymint::test {
+
+using ::android::sp;
+using binder::Status;
+using ::std::shared_ptr;
+using ::std::string;
+using ::std::vector;
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+
+class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
+ public:
+ void SetUp() override;
+ void TearDown() override {
+ if (key_blob_.size()) {
+ CheckedDeleteKey();
+ }
+ AbortIfNeeded();
+ }
+
+ void InitializeKeyMint(sp<IKeyMintDevice> keyMint);
+ IKeyMintDevice& keyMint() { return *keymint_; }
+ uint32_t os_version() { return os_version_; }
+ uint32_t os_patch_level() { return os_patch_level_; }
+
+ ErrorCode GetReturnErrorCode(Status result);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
+ KeyCharacteristics* key_characteristics);
+
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material, vector<uint8_t>* key_blob,
+ KeyCharacteristics* key_characteristics);
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material);
+
+ ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
+ const AuthorizationSet& wrapping_key_desc, string masking_key,
+ const AuthorizationSet& unwrapping_params);
+
+ ErrorCode DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
+ ErrorCode DeleteKey(bool keep_key_blob = false);
+
+ ErrorCode DeleteAllKeys();
+
+ void CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
+ void CheckedDeleteKey();
+
+ ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params,
+ sp<IKeyMintOperation>& op);
+ ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params);
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params);
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params);
+
+ ErrorCode Update(const AuthorizationSet& in_params, const string& input,
+ AuthorizationSet* out_params, string* output, int32_t* input_consumed);
+ ErrorCode Update(const string& input, string* out, int32_t* input_consumed);
+
+ ErrorCode Finish(const AuthorizationSet& in_params, const string& input,
+ const string& signature, AuthorizationSet* out_params, string* output);
+ ErrorCode Finish(const string& message, string* output);
+ ErrorCode Finish(const string& message, const string& signature, string* output);
+ ErrorCode Finish(string* output) { return Finish(string(), output); }
+
+ ErrorCode Abort();
+ ErrorCode Abort(const sp<IKeyMintOperation>& op);
+ void AbortIfNeeded();
+
+ string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params);
+
+ string SignMessage(const vector<uint8_t>& key_blob, const string& message,
+ const AuthorizationSet& params);
+ string SignMessage(const string& message, const AuthorizationSet& params);
+
+ string MacMessage(const string& message, Digest digest, size_t mac_length);
+
+ void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+ const string& expected_mac);
+
+ void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+ const string& expected_ciphertext);
+
+ void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+ PaddingMode padding_mode, const string& key, const string& iv,
+ const string& input, const string& expected_output);
+
+ void VerifyMessage(const vector<uint8_t>& key_blob, const string& message,
+ const string& signature, const AuthorizationSet& params);
+ void VerifyMessage(const string& message, const string& signature,
+ const AuthorizationSet& params);
+
+ string EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params);
+ string EncryptMessage(const string& message, const AuthorizationSet& params,
+ AuthorizationSet* out_params);
+ string EncryptMessage(const string& message, const AuthorizationSet& params);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+ vector<uint8_t>* iv_out);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+ const vector<uint8_t>& iv_in);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+ uint8_t mac_length_bits, const vector<uint8_t>& iv_in);
+
+ string DecryptMessage(const vector<uint8_t>& key_blob, const string& ciphertext,
+ const AuthorizationSet& params);
+ string DecryptMessage(const string& ciphertext, const AuthorizationSet& params);
+ string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
+ const vector<uint8_t>& iv);
+
+ std::pair<ErrorCode, vector<uint8_t>> UpgradeKey(const vector<uint8_t>& key_blob);
+
+ bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+ SecurityLevel SecLevel() { return securityLevel_; }
+
+ vector<uint32_t> ValidKeySizes(Algorithm algorithm);
+ vector<uint32_t> InvalidKeySizes(Algorithm algorithm);
+
+ vector<EcCurve> ValidCurves();
+ vector<EcCurve> InvalidCurves();
+
+ vector<Digest> ValidDigests(bool withNone, bool withMD5);
+
+ static vector<string> build_params() {
+ auto params = android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+ return params;
+ }
+
+ sp<IKeyMintOperation> op_;
+ vector<Certificate> certChain_;
+ vector<uint8_t> key_blob_;
+ KeyCharacteristics key_characteristics_;
+
+ private:
+ sp<IKeyMintDevice> keymint_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
+
+ SecurityLevel securityLevel_;
+ string name_;
+ string author_;
+ long challenge_;
+};
+
+#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
+ android::PrintInstanceNameToString)
+
+} // namespace android::hardware::security::keymint::test
+
+#endif // VTS_KEYMINT_AIDL_TEST_UTILS_H
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
new file mode 100644
index 0000000..f9423a2
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -0,0 +1,4058 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "keymint_5_test"
+#include <cutils/log.h>
+
+#include <signal.h>
+#include <iostream>
+
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+#include <cutils/properties.h>
+
+#include <android/hardware/security/keymint/KeyFormat.h>
+
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+static bool arm_deleteAllKeys = false;
+static bool dump_Attestations = false;
+
+using android::hardware::security::keymint::AuthorizationSet;
+using android::hardware::security::keymint::KeyCharacteristics;
+using android::hardware::security::keymint::KeyFormat;
+
+namespace android::hardware::security::keymint {
+
+bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
+} // namespace android::hardware::security::keymint
+
+namespace std {
+
+using namespace android::hardware::security::keymint;
+
+template <>
+struct std::equal_to<KeyCharacteristics> {
+ bool operator()(const KeyCharacteristics& a, const KeyCharacteristics& b) const {
+ // This isn't very efficient. Oh, well.
+ AuthorizationSet a_sw(a.softwareEnforced);
+ AuthorizationSet b_sw(b.softwareEnforced);
+ AuthorizationSet a_tee(b.hardwareEnforced);
+ AuthorizationSet b_tee(b.hardwareEnforced);
+
+ a_sw.Sort();
+ b_sw.Sort();
+ a_tee.Sort();
+ b_tee.Sort();
+
+ return ((a_sw == b_sw) && (a_tee == b_tee));
+ }
+};
+
+} // namespace std
+
+namespace android::hardware::security::keymint::test {
+
+namespace {
+
+template <TagType tag_type, Tag tag, typename ValueT>
+bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+ auto it = std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+ return param.tag == tag && accessTagValue(ttag, param) == expected_value;
+ });
+ return (it != set.end());
+}
+
+template <TagType tag_type, Tag tag>
+bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag>) {
+ auto it = std::find_if(set.begin(), set.end(),
+ [&](const KeyParameter& param) { return param.tag == tag; });
+ return (it != set.end());
+}
+
+constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+ string b;
+ size_t num = a.size() / 2;
+ b.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+ }
+ return b;
+}
+
+string rsa_key =
+ hex2str("30820275020100300d06092a864886f70d01010105000482025f3082025b"
+ "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901"
+ "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9"
+ "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e"
+ "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d"
+ "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37"
+ "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297"
+ "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657"
+ "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac"
+ "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80"
+ "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af"
+ "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285"
+ "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a"
+ "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324"
+ "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411"
+ "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea"
+ "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d"
+ "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945"
+ "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077"
+ "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324"
+ "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
+ "3492d6");
+
+string ec_256_key =
+ hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+ "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
+ "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a"
+ "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4"
+ "1c6eb00083cf3376d11fd44949e0b2183bfe");
+
+string ec_521_key =
+ hex2str("3081EE020100301006072A8648CE3D020106052B810400230481D63081D3"
+ "02010104420011458C586DB5DAA92AFAB03F4FE46AA9D9C3CE9A9B7A006A"
+ "8384BEC4C78E8E9D18D7D08B5BCFA0E53C75B064AD51C449BAE0258D54B9"
+ "4B1E885DED08ED4FB25CE9A1818903818600040149EC11C6DF0FA122C6A9"
+ "AFD9754A4FA9513A627CA329E349535A5629875A8ADFBE27DCB932C05198"
+ "6377108D054C28C6F39B6F2C9AF81802F9F326B842FF2E5F3C00AB7635CF"
+ "B36157FC0882D574A10D839C1A0C049DC5E0D775E2EE50671A208431BB45"
+ "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
+ "D9");
+
+string ec_256_key_rfc5915 =
+ hex2str("308193020100301306072a8648ce3d020106082a8648ce3d030107047930"
+ "770201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+ "8e8d21c9fa750c1da00a06082a8648ce3d030107a14403420004e2cc561e"
+ "e701da0ad0ef0d176bb0c919d42e79c393fdc1bd6c4010d85cf2cf8e68c9"
+ "05464666f98dad4f01573ba81078b3428570a439ba3229fbc026c550682f");
+
+string ec_256_key_sec1 =
+ hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+ "6b0201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+ "8e8d21c9fa750c1da14403420004e2cc561ee701da0ad0ef0d176bb0c919"
+ "d42e79c393fdc1bd6c4010d85cf2cf8e68c905464666f98dad4f01573ba8"
+ "1078b3428570a439ba3229fbc026c550682f");
+
+struct RSA_Delete {
+ void operator()(RSA* p) { RSA_free(p); }
+};
+
+/* TODO(seleneh) add attestation verification codes like verify_chain() and
+ * attestation tests after we decided on the keymint 1 attestation changes.
+ */
+
+std::string make_string(const uint8_t* data, size_t length) {
+ return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N>
+std::string make_string(const uint8_t (&a)[N]) {
+ return make_string(a, N);
+}
+
+class AidlBuf : public vector<uint8_t> {
+ typedef vector<uint8_t> super;
+
+ public:
+ AidlBuf() {}
+ AidlBuf(const super& other) : super(other) {}
+ AidlBuf(super&& other) : super(std::move(other)) {}
+ explicit AidlBuf(const std::string& other) : AidlBuf() { *this = other; }
+
+ AidlBuf& operator=(const super& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ AidlBuf& operator=(super&& other) {
+ super::operator=(std::move(other));
+ return *this;
+ }
+
+ AidlBuf& operator=(const string& other) {
+ resize(other.size());
+ for (size_t i = 0; i < other.size(); ++i) {
+ (*this)[i] = static_cast<uint8_t>(other[i]);
+ }
+ return *this;
+ }
+
+ string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+} // namespace
+
+class NewKeyGenerationTest : public KeyMintAidlTestBase {
+ protected:
+ void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+ // TODO(swillden): Distinguish which params should be in which auth list.
+
+ AuthorizationSet auths(keyCharacteristics.hardwareEnforced);
+ auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
+
+ EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+ EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+ EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+
+ // Verify that App ID, App data and ROT are NOT included.
+ EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+ EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID));
+ EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+ // Check that some unexpected tags/values are NOT present.
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+ EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));
+
+ // Now check that unspecified, defaulted tags are correct.
+ EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME));
+
+ EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
+ << "OS version is " << os_version() << " key reported "
+ << auths.GetTagValue(TAG_OS_VERSION);
+ EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
+ << "OS patch level is " << os_patch_level() << " key reported "
+ << auths.GetTagValue(TAG_OS_PATCHLEVEL);
+ }
+};
+
+/*
+ * NewKeyGenerationTest.Rsa
+ *
+ * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys
+ * have correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Rsa) {
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ vector<uint8_t> key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params;
+ if (IsSecure()) {
+ crypto_params = key_characteristics.hardwareEnforced;
+ } else {
+ crypto_params = key_characteristics.softwareEnforced;
+ }
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.NoInvalidRsaSizes
+ *
+ * Verifies that keymint cannot generate any RSA key sizes that are designated as invalid.
+ */
+TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) {
+ for (auto key_size : InvalidKeySizes(Algorithm::RSA)) {
+ vector<uint8_t> key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ &key_blob, &key_characteristics));
+ }
+}
+
+/*
+ * NewKeyGenerationTest.RsaNoDefaultSize
+ *
+ * Verifies that failing to specify a key size for RSA key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3U)
+ .SigningKey()));
+}
+
+/*
+ * NewKeyGenerationTest.Ecdsa
+ *
+ * Verifies that keymint can generate all required EC key sizes, and that the resulting keys
+ * have correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Ecdsa) {
+ for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ vector<uint8_t> key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(
+ AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+ &key_blob, &key_characteristics));
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params;
+ if (IsSecure()) {
+ crypto_params = key_characteristics.hardwareEnforced;
+ } else {
+ crypto_params = key_characteristics.softwareEnforced;
+ }
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaDefaultSize
+ *
+ * Verifies that failing to specify a key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .SigningKey()
+ .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidSize
+ *
+ * Verifies that specifying an invalid key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
+ for (auto key_size : InvalidKeySizes(Algorithm::EC)) {
+ vector<uint8_t> key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(
+ AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+ &key_blob, &key_characteristics));
+ }
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaMismatchKeySize
+ *
+ * Verifies that specifying mismatched key size and curve for EC key generation returns
+ * INVALID_ARGUMENT.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidSizes
+ *
+ * Verifies that keymint supports all required EC key sizes.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
+ auto valid_sizes = ValidKeySizes(Algorithm::EC);
+ for (size_t size : valid_sizes) {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE)))
+ << "Failed to generate size: " << size;
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidCurves
+ *
+ * Verifies that keymint does not support any curve designated as unsupported.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
+ Digest digest;
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ digest = Digest::SHA_2_256;
+ } else {
+ digest = Digest::SHA_2_512;
+ }
+ for (auto curve : ValidCurves()) {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(digest)))
+ << "Failed to generate key on curve: " << curve;
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * NewKeyGenerationTest.Hmac
+ *
+ * Verifies that keymint supports all required digests, and that the resulting keys have correct
+ * characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Hmac) {
+ for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+ vector<uint8_t> key_blob;
+ KeyCharacteristics key_characteristics;
+ constexpr size_t key_size = 128;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(
+ AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization(
+ TAG_MIN_MAC_LENGTH, 128),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet hardwareEnforced = key_characteristics.hardwareEnforced;
+ AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced;
+ if (IsSecure()) {
+ EXPECT_TRUE(hardwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+ EXPECT_TRUE(hardwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ } else {
+ EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+ EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ }
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckKeySizes
+ *
+ * Verifies that keymint supports all key sizes, and rejects all invalid key sizes.
+ */
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
+ for (size_t key_size = 0; key_size <= 512; ++key_size) {
+ if (key_size < 64 || key_size % 8 != 0) {
+ // To keep this test from being very slow, we only test a random fraction of
+ // non-byte key sizes. We test only ~10% of such cases. Since there are 392 of
+ // them, we expect to run ~40 of them in each run.
+ if (key_size % 8 == 0 || random() % 10 == 0) {
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(key_size)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+ << "HMAC key size " << key_size << " invalid";
+ }
+ } else {
+ EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(key_size)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+ << "Failed to generate HMAC key of size " << key_size;
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckMinMacLengths
+ *
+ * Verifies that keymint supports all required MAC lengths and rejects all invalid lengths. This
+ * test is probabilistic in order to keep the runtime down, but any failure prints out the
+ * specific MAC length that failed, so reproducing a failed run will be easy.
+ */
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+ for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+ if (min_mac_length < 64 || min_mac_length % 8 != 0) {
+ // To keep this test from being very long, we only test a random fraction of
+ // non-byte lengths. We test only ~10% of such cases. Since there are 172 of them,
+ // we expect to run ~17 of them in each run.
+ if (min_mac_length % 8 == 0 || random() % 10 == 0) {
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+ << "HMAC min mac length " << min_mac_length << " invalid.";
+ }
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+ << "Failed to generate HMAC key with min MAC length " << min_mac_length;
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacMultipleDigests
+ *
+ * Verifies that keymint rejects HMAC key generation with multiple specified digest algorithms.
+ */
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA1)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+/*
+ * NewKeyGenerationTest.HmacDigestNone
+ *
+ * Verifies that keymint rejects HMAC key generation with no digest or Digest::NONE
+ */
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH,
+ 128)));
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(NewKeyGenerationTest);
+
+typedef KeyMintAidlTestBase SigningOperationsTest;
+
+/*
+ * SigningOperationsTest.RsaSuccess
+ *
+ * Verifies that raw RSA signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+ string message = "12345678901234567890123456789012";
+ string signature = SignMessage(
+ message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaUseRequiresCorrectAppIdAppData
+ *
+ * Verifies that using an RSA key requires the correct app ID/data.
+ */
+TEST_P(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_APPLICATION_ID, "clientid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata")));
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_APPLICATION_ID, "clientid")));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_APPLICATION_DATA, "appdata")));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_APPLICATION_DATA, "appdata")
+ .Authorization(TAG_APPLICATION_ID, "clientid")));
+ AbortIfNeeded();
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha256Success
+ *
+ * Verifies that RSA-PSS signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PSS)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature = SignMessage(
+ message,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS));
+}
+
+/*
+ * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther
+ *
+ * Verifies that keymint rejects signature operations that specify a padding mode when the key
+ * supports only unpadded operations.
+ */
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+}
+
+/*
+ * SigningOperationsTest.NoUserConfirmation
+ *
+ * Verifies that keymint rejects signing operations for keys with
+ * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
+ * presented.
+ */
+TEST_P(SigningOperationsTest, NoUserConfirmation) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)));
+
+ const string message = "12345678901234567890123456789012";
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+ string signature;
+ EXPECT_EQ(ErrorCode::NO_USER_CONFIRMATION, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1Sha256Success
+ *
+ * Verifies that digested RSA-PKCS1 signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(1024, 'a');
+ string signature = SignMessage(message, AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestSuccess
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(53, 'a');
+ string signature = SignMessage(message, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestTooLarge
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(257, 'a');
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string signature;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha512TooSmallKey
+ *
+ * Verifies that undigested RSA-PSS signature operations fail with the correct error code when
+ * used with a key that is too small for the message.
+ *
+ * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the
+ * keymint specification requires that salt_size == digest_size, so the message will be
+ * digest_size * 2 +
+ * 16. Such a message can only be signed by a given key if the key is at least that size. This
+ * test uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large
+ * for a 1024-bit key.
+ */
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 65537)
+ .Digest(Digest::SHA_2_512)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PSS)));
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_512)
+ .Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ // One byte too long
+ string message(2048 / 8 + 1, 'a');
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string result;
+ ErrorCode finish_error_code = Finish(message, &result);
+ EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+ finish_error_code == ErrorCode::INVALID_ARGUMENT);
+
+ // Very large message that should exceed the transfer buffer size of any reasonable TEE.
+ message = string(128 * 1024, 'a');
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ finish_error_code = Finish(message, &result);
+ EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+ finish_error_code == ErrorCode::INVALID_ARGUMENT);
+}
+
+/*
+ * SigningOperationsTest.RsaAbort
+ *
+ * Verifies that operations can be aborted correctly. Uses an RSA signing operation for the
+ * test, but the behavior should be algorithm and purpose-independent.
+ */
+TEST_P(SigningOperationsTest, RsaAbort) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+ EXPECT_EQ(ErrorCode::OK, Abort());
+
+ // Another abort should fail
+ EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort());
+
+ // Set to sentinel, so TearDown() doesn't try to abort again.
+ op_.clear();
+}
+
+/*
+ * SigningOperationsTest.RsaUnsupportedPadding
+ *
+ * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used
+ * with a padding mode inappropriate for RSA.
+ */
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::SHA_2_256 /* supported digest */)
+ .Padding(PaddingMode::PKCS7)));
+ ASSERT_EQ(
+ ErrorCode::UNSUPPORTED_PADDING_MODE,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA PSS operations fail when no digest is used. PSS requires a digest.
+ */
+TEST_P(SigningOperationsTest, RsaNoDigest) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PSS)));
+ ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS)));
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA operations fail when no padding mode is specified. PaddingMode::NONE is
+ * supported in some cases (as validated in other tests), but a mode must be specified.
+ */
+TEST_P(SigningOperationsTest, RsaNoPadding) {
+ // Padding must be specified
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SigningKey()
+ .Digest(Digest::NONE)));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaShortMessage
+ *
+ * Verifies that raw RSA signatures succeed with a message shorter than the key size.
+ */
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+
+ // Barely shorter
+ string message(2048 / 8 - 1, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+
+ // Much shorter
+ message = "a";
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaSignWithEncryptionKey
+ *
+ * Verifies that RSA encryption keys cannot be used to sign.
+ */
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaSignTooLargeMessage
+ *
+ * Verifies that attempting a raw signature of a message which is the same length as the key,
+ * but numerically larger than the public modulus, fails with the correct error.
+ */
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+
+ // Largest possible message will always be larger than the public modulus.
+ string message(2048 / 8, static_cast<char>(0xff));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ string signature;
+ ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllSizesAndHashes
+ *
+ * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
+ */
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+ for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(key_size)
+ .Digest(digest));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
+ << " and digest " << digest;
+ if (error != ErrorCode::OK) continue;
+
+ string message(1024, 'a');
+ if (digest == Digest::NONE) message.resize(key_size / 8);
+ SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllCurves
+ *
+ * Verifies that ECDSA operations succeed with all possible curves.
+ */
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
+ for (auto curve : ValidCurves()) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::SHA_2_256));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+ if (error != ErrorCode::OK) continue;
+
+ string message(1024, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * SigningOperationsTest.EcdsaNoDigestHugeData
+ *
+ * Verifies that ECDSA operations support very large messages, even without digesting. This
+ * should work because ECDSA actually only signs the leftmost L_n bits of the message, however
+ * large it may be. Not using digesting is a bad idea, but in some cases digesting is done by
+ * the framework.
+ */
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::NONE)));
+ string message(1 * 1024, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+}
+
+/*
+ * SigningOperationsTest.EcUseRequiresCorrectAppIdAppData
+ *
+ * Verifies that using an EC key requires the correct app ID/data.
+ */
+TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_APPLICATION_ID, "clientid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata")));
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Authorization(TAG_APPLICATION_ID, "clientid")));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Authorization(TAG_APPLICATION_DATA, "appdata")));
+ AbortIfNeeded();
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Authorization(TAG_APPLICATION_DATA, "appdata")
+ .Authorization(TAG_APPLICATION_ID, "clientid")));
+ AbortIfNeeded();
+}
+
+/*
+ * SigningOperationsTest.AesEcbSign
+ *
+ * Verifies that attempts to use AES keys to sign fail in the correct way.
+ */
+TEST_P(SigningOperationsTest, AesEcbSign) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SigningKey()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)));
+
+ AuthorizationSet out_params;
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+ Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params));
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+ Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params));
+}
+
+/*
+ * SigningOperationsTest.HmacAllDigests
+ *
+ * Verifies that HMAC works with all digests.
+ */
+TEST_P(SigningOperationsTest, HmacAllDigests) {
+ for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(digest)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160)))
+ << "Failed to create HMAC key with digest " << digest;
+ string message = "12345678901234567890123456789012";
+ string signature = MacMessage(message, digest, 160);
+ EXPECT_EQ(160U / 8U, signature.size())
+ << "Failed to sign with HMAC key with digest " << digest;
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooLargeMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the
+ * digest size.
+ */
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MAC_LENGTH, 264),
+ &output_params));
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooSmallMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
+ * specified minimum MAC length.
+ */
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MAC_LENGTH, 120),
+ &output_params));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase3
+ *
+ * Validates against the test vectors from RFC 4231 test case 3.
+ */
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
+ string key(20, 0xaa);
+ string message(50, 0xdd);
+ uint8_t sha_224_expected[] = {
+ 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+ 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+ 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+ 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+ 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+ 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+ 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+ 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+ 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+ 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ if (SecLevel() != SecurityLevel::STRONGBOX) {
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+ }
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase5
+ *
+ * Validates against the test vectors from RFC 4231 test case 5.
+ */
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
+ string key(20, 0x0c);
+ string message = "Test With Truncation";
+
+ uint8_t sha_224_expected[] = {
+ 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+ 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+ };
+ uint8_t sha_256_expected[] = {
+ 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+ 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+ 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+ 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ if (SecLevel() != SecurityLevel::STRONGBOX) {
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(SigningOperationsTest);
+
+typedef KeyMintAidlTestBase VerificationOperationsTest;
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies that a simple RSA signature/verification sequence succeeds.
+ */
+TEST_P(VerificationOperationsTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature = SignMessage(
+ message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ VerifyMessage(message, signature,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies RSA signature/verification for all padding modes and digests.
+ */
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+ auto authorizations = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(ValidDigests(true /* withNone */, true /* withMD5 */))
+ .Padding(PaddingMode::NONE)
+ .Padding(PaddingMode::RSA_PSS)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN);
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(authorizations));
+
+ string message(128, 'a');
+ string corrupt_message(message);
+ ++corrupt_message[corrupt_message.size() / 2];
+
+ for (auto padding :
+ {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
+ for (auto digest : ValidDigests(true /* withNone */, true /* withMD5 */)) {
+ if (padding == PaddingMode::NONE && digest != Digest::NONE) {
+ // Digesting only makes sense with padding.
+ continue;
+ }
+
+ if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) {
+ // PSS requires digesting.
+ continue;
+ }
+
+ string signature =
+ SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding));
+ VerifyMessage(message, signature,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding));
+
+ /* TODO(seleneh) add exportkey tests back later when we have decided on
+ * the new api.
+ if (digest != Digest::NONE) {
+ // Verify with OpenSSL.
+ vector<uint8_t> pubkey;
+ ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey));
+
+ const uint8_t* p = pubkey.data();
+ EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ const EVP_MD* md = openssl_digest(digest);
+ ASSERT_NE(md, nullptr);
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md,
+ nullptr, pkey.get()));
+
+ switch (padding) {
+ case PaddingMode::RSA_PSS:
+ EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx,
+ RSA_PKCS1_PSS_PADDING), 0); EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx,
+ EVP_MD_size(md)), 0); break; case PaddingMode::RSA_PKCS1_1_5_SIGN:
+ // PKCS1 is the default; don't need to set anything.
+ break;
+ default:
+ FAIL();
+ break;
+ }
+
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(),
+ message.size())); EXPECT_EQ(1, EVP_DigestVerifyFinal(&digest_ctx,
+ reinterpret_cast<const
+ uint8_t*>(signature.data()), signature.size())); EVP_MD_CTX_cleanup(&digest_ctx);
+ }
+ */
+
+ // Corrupt signature shouldn't verify.
+ string corrupt_signature(signature);
+ ++corrupt_signature[corrupt_signature.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+ string result;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result));
+
+ // Corrupt message shouldn't verify
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result));
+ }
+ }
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies ECDSA signature/verification for all digests and curves.
+ */
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+ auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
+
+ string message = "1234567890";
+ string corrupt_message = "2234567890";
+ for (auto curve : ValidCurves()) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(digests));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve;
+ if (error != ErrorCode::OK) {
+ continue;
+ }
+
+ for (auto digest : digests) {
+ string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+ VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest));
+
+ /* TODO(seleneh) add exportkey tests back later when we have decided on
+ * the new api.
+
+ // Verify with OpenSSL
+ if (digest != Digest::NONE) {
+ vector<uint8_t> pubkey;
+ ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey))
+ << curve << ' ' << digest;
+
+ const uint8_t* p = pubkey.data();
+ EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ const EVP_MD* md = openssl_digest(digest);
+
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md,
+ nullptr, pkey.get()))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(),
+ message.size()))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(1,
+ EVP_DigestVerifyFinal(&digest_ctx,
+ reinterpret_cast<const
+ uint8_t*>(signature.data()), signature.size()))
+ << curve << ' ' << digest;
+
+ EVP_MD_CTX_cleanup(&digest_ctx);
+ }
+ */
+ // Corrupt signature shouldn't verify.
+ string corrupt_signature(signature);
+ ++corrupt_signature[corrupt_signature.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+ << curve << ' ' << digest;
+
+ string result;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result))
+ << curve << ' ' << digest;
+
+ // Corrupt message shouldn't verify
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result))
+ << curve << ' ' << digest;
+ }
+
+ auto rc = DeleteKey();
+ ASSERT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+ }
+}
+
+/*
+ * VerificationOperationsTest.HmacSigningKeyCannotVerify
+ *
+ * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
+ */
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+ string key_material = "HelloThisIsAKey";
+
+ vector<uint8_t> signing_key, verification_key;
+ KeyCharacteristics signing_key_chars, verification_key_chars;
+ EXPECT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+ .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160),
+ KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+ EXPECT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+ .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160),
+ KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+ string message = "This is a message.";
+ string signature = SignMessage(
+ signing_key, message,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 160));
+
+ // Signing key should not work.
+ AuthorizationSet out_params;
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+ Begin(KeyPurpose::VERIFY, signing_key,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256), &out_params));
+
+ // Verification key should work.
+ VerifyMessage(verification_key, message, signature,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+
+ CheckedDeleteKey(&signing_key);
+ CheckedDeleteKey(&verification_key);
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VerificationOperationsTest);
+
+typedef KeyMintAidlTestBase ExportKeyTest;
+
+/*
+ * ExportKeyTest.RsaUnsupportedKeyFormat
+ *
+ * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
+ */
+// TODO(seleneh) add ExportKey to GenerateKey
+// check result
+
+class ImportKeyTest : public KeyMintAidlTestBase {
+ public:
+ template <TagType tag_type, Tag tag, typename ValueT>
+ void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+ SCOPED_TRACE("CheckCryptoParam");
+ if (IsSecure()) {
+ EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, ttag, expected))
+ << "Tag " << tag << " with value " << expected << " not found";
+ EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag))
+ << "Tag " << tag << " found";
+ } else {
+ EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected))
+ << "Tag " << tag << " with value " << expected << " not found";
+ EXPECT_FALSE(contains(key_characteristics_.hardwareEnforced, ttag))
+ << "Tag " << tag << " found";
+ }
+ }
+
+ void CheckOrigin() {
+ SCOPED_TRACE("CheckOrigin");
+ if (IsSecure()) {
+ EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, TAG_ORIGIN,
+ KeyOrigin::IMPORTED));
+ } else {
+ EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, TAG_ORIGIN,
+ KeyOrigin::IMPORTED));
+ }
+ }
+};
+
+/*
+ * ImportKeyTest.RsaSuccess
+ *
+ * Verifies that importing and using an RSA key pair works correctly.
+ */
+TEST_P(ImportKeyTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PSS),
+ KeyFormat::PKCS8, rsa_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+ CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+ CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
+ CheckOrigin();
+
+ string message(1024 / 8, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.RsaKeySizeMismatch
+ *
+ * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048 /* Doesn't match key */, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.RsaPublicExponentMismatch
+ *
+ * Verifies that importing an RSA key pair with a public exponent that doesn't match the key
+ * fails in the correct way.
+ */
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3 /* Doesn't match key */)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaSuccess
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_256_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 256U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256RFC5915Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works
+ * correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_256_key_rfc5915));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 256U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256SEC1Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaP256SEC1Success) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_256_key_sec1));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 256U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ecdsa521Success
+ *
+ * Verifies that importing and using an ECDSA P-521 key pair works correctly.
+ */
+TEST_P(ImportKeyTest, Ecdsa521Success) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(521)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_521_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 521U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521);
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaSizeMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224 /* Doesn't match key */)
+ .Digest(Digest::NONE),
+ KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaCurveMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+ .Digest(Digest::NONE),
+ KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an AES key works.
+ */
+TEST_P(ImportKeyTest, AesSuccess) {
+ string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .EcbMode()
+ .Padding(PaddingMode::PKCS7),
+ KeyFormat::RAW, key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::AES);
+ CheckCryptoParam(TAG_KEY_SIZE, 128U);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::PKCS7);
+ CheckCryptoParam(TAG_BLOCK_MODE, BlockMode::ECB);
+ CheckOrigin();
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, params);
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an HMAC key works.
+ */
+TEST_P(ImportKeyTest, HmacKeySuccess) {
+ string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(key.size() * 8)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256),
+ KeyFormat::RAW, key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::HMAC);
+ CheckCryptoParam(TAG_KEY_SIZE, 128U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckOrigin();
+
+ string message = "Hello World!";
+ string signature = MacMessage(message, Digest::SHA_2_256, 256);
+ VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
+
+auto wrapped_key = hex2str(
+ "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac8"
+ "4b59b30b455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e0"
+ "97474febc981195b1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001c"
+ "a5d1ec1e27f5c30f4cec2642074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b5"
+ "0cda07a8ecb7cd8e3dd7009c9636534f6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34"
+ "ed9c3ff999b801597d5220e307eaa5bee507fb94d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0dde"
+ "deae8c70e0233cd098040cd796b02c370f1fa4cc0124f1302e0201033029a1083106020100020101a20302"
+ "0120a30402020100a4053103020101a6053103020140bf83770205000420ccd540855f833a5e1480bfd2d3"
+ "6faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6999e0eb6e5");
+
+auto wrapped_key_masked = hex2str(
+ "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33"
+ "c88732452f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21"
+ "946821553207f8f9931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5"
+ "a96c284b4b8d7e4948f331e5b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4be"
+ "e3759453e69ad1d68a809ce06b949f7694a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f"
+ "1e35da77586775f423e519c2ea394caf48a28d0c8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb9590"
+ "33c1af5c125fd94168040c6d9721d08589581ab49204a3302e0201033029a1083106020100020101a20302"
+ "0120a30402020100a4053103020101a6053103020140bf83770205000420a61c6e247e25b3e6e69aa78eb0"
+ "3c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b98b512a670");
+
+auto wrapping_key = hex2str(
+ "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d"
+ "8900ce56b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86"
+ "acbddc41bb759c2854eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe"
+ "7c0d23be312d7bd5921ffaea1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c137"
+ "4c3886427411c449796792e0bef75dec858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3"
+ "a7ee4991d0d48b0172a95f9536f02ba13cecccb92b727db5c27e5b2f5cec09600b286af5cf14c42024c61d"
+ "dfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed3f4833cca2bd8fa62821dd5502030100010282"
+ "0100431447b6251908112b1ee76f99f3711a52b6630960046c2de70de188d833f8b8b91e4d785caeeeaf4f"
+ "0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b5d2c43080e52bee71e9eae"
+ "b6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2579ba02aae0a00"
+ "900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4a957bb"
+ "ddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f8"
+ "51e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f86181"
+ "02818100de392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a16"
+ "4c5970007047b8c517db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788"
+ "e1f1a97223b524b5357fdf72e2f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d7"
+ "1c743502818100c95387c0f9d35f137b57d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3"
+ "863ca645fcce49582a9aa17349db6c4a95affdae0dae612e1afac99ed39a2d934c880440aed8832f984316"
+ "3a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f58309366a7de25f7c3c9b880677c068e1be936e812"
+ "88815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0b8b36cd6c136e52e4085f4ea5a06"
+ "3212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece1af76ad0b030f27af6f0"
+ "ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719d6e2b9439823"
+ "719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b6556ca"
+ "31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8"
+ "a43e34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277c"
+ "ff1e6aaa5d57aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6"
+ "864236d0c4736a0008a145af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2"
+ "bfdfe27ae778983f959356210723287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9b"
+ "f27ba61be6ad02dfddda8f4e6822");
+
+string zero_masking_key =
+ hex2str("0000000000000000000000000000000000000000000000000000000000000000");
+string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC");
+
+class ImportWrappedKeyTest : public KeyMintAidlTestBase {};
+
+TEST_P(ImportWrappedKeyTest, Success) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(ErrorCode::OK,
+ ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)));
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, params);
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+TEST_P(ImportWrappedKeyTest, SuccessMasked) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(ErrorCode::OK,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_P(ImportWrappedKeyTest, WrongMask) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(
+ ErrorCode::VERIFICATION_FAILED,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_P(ImportWrappedKeyTest, WrongPurpose) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP);
+
+ ASSERT_EQ(
+ ErrorCode::INCOMPATIBLE_PURPOSE,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+ AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ImportWrappedKeyTest);
+
+typedef KeyMintAidlTestBase EncryptionOperationsTest;
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingSuccess
+ *
+ * Verifies that raw RSA encryption works.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::NONE)));
+
+ string message = string(2048 / 8, 'a');
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext2.size());
+
+ // Unpadded RSA is deterministic
+ EXPECT_EQ(ciphertext1, ciphertext2);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingShortMessage
+ *
+ * Verifies that raw RSA encryption of short messages works.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "1";
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext.size());
+
+ string expected_plaintext = string(2048U / 8 - 1, 0) + message;
+ string plaintext = DecryptMessage(ciphertext, params);
+
+ EXPECT_EQ(expected_plaintext, plaintext);
+
+ // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
+ message = static_cast<char>(1);
+ ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext.size());
+ EXPECT_EQ(ciphertext, string(2048U / 8 - 1, 0) + message);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-long messages fails in the expected way.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::NONE)));
+
+ string message(2048 / 8 + 1, 'a');
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+ string result;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLarge
+ *
+ * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected
+ * way.
+ */
+// TODO(seleneh) add RsaNoPaddingTooLarge test back after decided and implemented new
+// version of ExportKey inside generateKey
+
+/*
+ * EncryptionOperationsTest.RsaOaepSuccess
+ *
+ * Verifies that RSA-OAEP encryption operations work, with all digests.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
+ auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+
+ size_t key_size = 2048; // Need largish key for SHA-512 test.
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(digests)));
+
+ string message = "Hello";
+
+ for (auto digest : digests) {
+ auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
+ string ciphertext1 = EncryptMessage(message, params);
+ if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+ EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+ // OAEP randomizes padding so every result should be different (with astronomically high
+ // probability).
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext1 = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+ string plaintext2 = DecryptMessage(ciphertext2, params);
+ EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = random() % ciphertext1.size();
+ char corrupt_byte;
+ do {
+ corrupt_byte = static_cast<char>(random() % 256);
+ } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+ ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_EQ(0U, result.size());
+ }
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * without a digest.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::NONE)));
+ string message = "Hello World!";
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt
+ * with a different digest than was used to encrypt.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_224, Digest::SHA_2_256)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(
+ message,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepTooLarge
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
+ * too-large message.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)));
+ constexpr size_t digest_size = 256 /* SHA_2_256 */ / 8;
+ constexpr size_t oaep_overhead = 2 * digest_size + 2;
+ string message(2048 / 8 - oaep_overhead + 1, 'a');
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)));
+ string result;
+ ErrorCode error = Finish(message, &result);
+ EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1Success
+ *
+ * Verifies that RSA PKCS encryption/decrypts works.
+ */
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(2048U / 8, ciphertext2.size());
+
+ // PKCS1 v1.5 randomizes padding so every result should be different.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = random() % ciphertext1.size();
+ char corrupt_byte;
+ do {
+ corrupt_byte = static_cast<char>(random() % 256);
+ } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+ ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1TooLarge
+ *
+ * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
+ */
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+ string message(2048 / 8 - 10, 'a');
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ string result;
+ ErrorCode error = Finish(message, &result);
+ EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.EcdsaEncrypt
+ *
+ * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::NONE)));
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.HmacEncrypt
+ *
+ * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ auto params = AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES ECB mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+
+ ASSERT_GT(key_blob_.size(), 0U);
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), params);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // ECB is deterministic.
+ EXPECT_EQ(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ ASSERT_GT(key_blob_.size(), 0U);
+
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ EXPECT_EQ(
+ ErrorCode::INCOMPATIBLE_BLOCK_MODE,
+ Begin(KeyPurpose::ENCRYPT,
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * EncryptionOperationsTest.AesWrongPurpose
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized purpose is
+ * specified.
+ */
+TEST_P(EncryptionOperationsTest, AesWrongPurpose) {
+ auto err = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesKey(128)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Padding(PaddingMode::NONE));
+ ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
+ ASSERT_GT(key_blob_.size(), 0U);
+
+ err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+
+ CheckedDeleteKey();
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesKey(128)
+ .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Padding(PaddingMode::NONE)));
+
+ err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
+ *
+ * Verifies that AES encryption fails in the correct way when provided an input that is not a
+ * multiple of the block size and no padding is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+ // Message is slightly shorter than two blocks.
+ string message(16 * 2 - 1, 'a');
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext));
+ EXPECT_EQ(0U, ciphertext.size());
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7Padding
+ *
+ * Verifies that AES PKCS7 padding works for any message length.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbWrongPadding
+ *
+ * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
+ * specified.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ // Try various message lengths; all should fail
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(16U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+}
+
+vector<uint8_t> CopyIv(const AuthorizationSet& set) {
+ auto iv = set.GetTagValue(TAG_NONCE);
+ EXPECT_TRUE(iv.isOk());
+ return iv.value();
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrRoundTripSuccess
+ *
+ * Verifies that AES CTR mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+
+ string message = "123";
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv1 = CopyIv(out_params);
+ EXPECT_EQ(16U, iv1.size());
+
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ out_params.Clear();
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv2 = CopyIv(out_params);
+ EXPECT_EQ(16U, iv2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ auto params_iv1 =
+ AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1);
+ auto params_iv2 =
+ AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2);
+
+ string plaintext = DecryptMessage(ciphertext1, params_iv1);
+ EXPECT_EQ(message, plaintext);
+ plaintext = DecryptMessage(ciphertext2, params_iv2);
+ EXPECT_EQ(message, plaintext);
+
+ // Using the wrong IV will result in a "valid" decryption, but the data will be garbage.
+ plaintext = DecryptMessage(ciphertext1, params_iv2);
+ EXPECT_NE(message, plaintext);
+ plaintext = DecryptMessage(ciphertext2, params_iv1);
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesIncremental
+ *
+ * Verifies that AES works, all modes, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesIncremental) {
+ auto block_modes = {
+ BlockMode::ECB,
+ BlockMode::CBC,
+ BlockMode::CTR,
+ BlockMode::GCM,
+ };
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(block_modes)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ for (int increment = 1; increment <= 240; ++increment) {
+ for (auto block_mode : block_modes) {
+ string message(240, 'a');
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+ string ciphertext;
+ int32_t input_consumed;
+ string to_send;
+ for (size_t i = 0; i < message.size(); i += increment) {
+ to_send.append(message.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+ EXPECT_EQ(to_send.length(), input_consumed);
+ to_send = to_send.substr(input_consumed);
+ EXPECT_EQ(0U, to_send.length());
+
+ switch (block_mode) {
+ case BlockMode::ECB:
+ case BlockMode::CBC:
+ // Implementations must take as many blocks as possible, leaving less
+ // than a block.
+ EXPECT_LE(to_send.length(), 16U);
+ break;
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ // Implementations must always take all the data.
+ EXPECT_EQ(0U, to_send.length());
+ break;
+ }
+ }
+ EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+ switch (block_mode) {
+ case BlockMode::GCM:
+ EXPECT_EQ(message.size() + 16, ciphertext.size());
+ break;
+ case BlockMode::CTR:
+ EXPECT_EQ(message.size(), ciphertext.size());
+ break;
+ case BlockMode::CBC:
+ case BlockMode::ECB:
+ EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+ break;
+ }
+
+ auto iv = output_params.GetTagValue(TAG_NONCE);
+ switch (block_mode) {
+ case BlockMode::CBC:
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+ EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+ params.push_back(TAG_NONCE, iv.value());
+ break;
+
+ case BlockMode::ECB:
+ EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+ break;
+ }
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+ << "Decrypt begin() failed for block mode " << block_mode;
+
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment) {
+ to_send.append(ciphertext.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+ to_send = to_send.substr(input_consumed);
+ }
+ ErrorCode error = Finish(to_send, &plaintext);
+ ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+ << " and increment " << increment;
+ if (error == ErrorCode::OK) {
+ ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
+ << block_mode << " and increment " << increment;
+ }
+ }
+ }
+}
+
+struct AesCtrSp80038aTestVector {
+ const char* key;
+ const char* nonce;
+ const char* plaintext;
+ const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+ // AES-128
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+ "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+ },
+ // AES-192
+ {
+ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+ "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+ },
+ // AES-256
+ {
+ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+ "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+ },
+};
+
+/*
+ * EncryptionOperationsTest.AesCtrSp80038aTestVector
+ *
+ * Verifies AES CTR implementation against SP800-38A test vectors.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+ std::vector<uint32_t> InvalidSizes = InvalidKeySizes(Algorithm::AES);
+ for (size_t i = 0; i < 3; i++) {
+ const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+ const string key = hex2str(test.key);
+ if (std::find(InvalidSizes.begin(), InvalidSizes.end(), (key.size() * 8)) !=
+ InvalidSizes.end())
+ continue;
+ const string nonce = hex2str(test.nonce);
+ const string plaintext = hex2str(test.plaintext);
+ const string ciphertext = hex2str(test.ciphertext);
+ CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode
+ *
+ * Verifies that keymint rejects use of CTR mode with PKCS7 padding in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Padding(PaddingMode::PKCS7)));
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf(string(1, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf(string(15, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf(string(17, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv1 = CopyIv(out_params);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ out_params.Clear();
+
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv2 = CopyIv(out_params);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ params.push_back(TAG_NONCE, iv1);
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonce
+ *
+ * Verifies that AES caller-provided nonces work correctly.
+ */
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+
+ // Don't specify nonce, should get a random one.
+ AuthorizationSetBuilder params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+ params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should also work.
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop"));
+ out_params.Clear();
+ ciphertext = EncryptMessage(message, params, &out_params);
+
+ // Decrypt with correct nonce.
+ plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Try with wrong nonce.
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf("aaaaaaaaaaaaaaaa"));
+ plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonceProhibited
+ *
+ * Verifies that caller-provided nonces are not permitted when not specified in the key
+ * authorizations.
+ */
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+
+ // Don't specify nonce, should get a random one.
+ AuthorizationSetBuilder params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+ params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should fail
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop"));
+ out_params.Clear();
+ EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripSuccess
+ *
+ * Verifies that AES GCM mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+ << "Begin encrypt";
+ string ciphertext;
+ AuthorizationSet update_out_params;
+ ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext));
+
+ ASSERT_EQ(ciphertext.length(), message.length() + 16);
+
+ // Grab nonce
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+ string plaintext;
+ int32_t input_consumed;
+ ASSERT_EQ(ErrorCode::OK,
+ Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+ EXPECT_EQ(message.length(), plaintext.length());
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripWithDelaySuccess
+ *
+ * Verifies that AES GCM mode works, even when there's a long delay
+ * between operations.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+ << "Begin encrypt";
+ string ciphertext;
+ AuthorizationSet update_out_params;
+ sleep(5);
+ ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext));
+
+ ASSERT_EQ(ciphertext.length(), message.length() + 16);
+
+ // Grab nonce
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+ string plaintext;
+ int32_t input_consumed;
+ sleep(5);
+ ASSERT_EQ(ErrorCode::OK,
+ Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ sleep(5);
+ EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+ EXPECT_EQ(message.length(), plaintext.length());
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmDifferentNonces
+ *
+ * Verifies that encrypting the same data with different nonces produces different outputs.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmDifferentNonces) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_CALLER_NONCE)));
+
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ string nonce1 = "000000000000";
+ string nonce2 = "111111111111";
+ string nonce3 = "222222222222";
+
+ string ciphertext1 =
+ EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce1));
+ string ciphertext2 =
+ EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce2));
+ string ciphertext3 =
+ EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce3));
+
+ ASSERT_NE(ciphertext1, ciphertext2);
+ ASSERT_NE(ciphertext1, ciphertext3);
+ ASSERT_NE(ciphertext2, ciphertext3);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTag
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "123456789012345678901234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 96);
+
+ EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ EXPECT_EQ(1U, begin_out_params.size());
+ ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
+
+ AuthorizationSet finish_out_params;
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+ params = AuthorizationSetBuilder()
+ .Authorizations(begin_out_params)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 96);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptKey
+ *
+ * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
+ const uint8_t nonce_bytes[] = {
+ 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+ };
+ string nonce = make_string(nonce_bytes);
+ const uint8_t ciphertext_bytes[] = {
+ 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc,
+ 0xd2, 0xcb, 0x16, 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78,
+ 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a, 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d,
+ 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76, 0x76, 0x5e, 0xfb,
+ 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+ 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+ };
+ string ciphertext = make_string(ciphertext_bytes);
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128)
+ .Authorization(TAG_NONCE, nonce.data(), nonce.size());
+
+ auto import_params = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_CALLER_NONCE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128);
+
+ // Import correct key and decrypt
+ const uint8_t key_bytes[] = {
+ 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+ 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+ };
+ string key = make_string(key_bytes);
+ ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+ string plaintext = DecryptMessage(ciphertext, params);
+ CheckedDeleteKey();
+
+ // Corrupt key and attempt to decrypt
+ key[0] = 0;
+ ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
+ CheckedDeleteKey();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadNoData
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
+ * encrypt.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "1234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(finish_params, "" /* input */, "" /* signature */,
+ &finish_out_params, &ciphertext));
+ EXPECT_TRUE(finish_out_params.empty());
+
+ // Grab nonce
+ params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Finish(finish_params, ciphertext, "" /* signature */,
+ &finish_out_params, &plaintext));
+
+ EXPECT_TRUE(finish_out_params.empty());
+
+ EXPECT_EQ("", plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmMultiPartAad
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data in multiple
+ * chunks.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
+ const size_t tag_bits = 128;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "123456789012345678901234567890123456";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, tag_bits);
+ AuthorizationSet begin_out_params;
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+ // No data, AAD only.
+ string ciphertext;
+ int32_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ // AAD and data.
+ EXPECT_EQ(ErrorCode::OK,
+ Update(update_params, message, &update_out_params, &ciphertext, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_TRUE(update_out_params.empty());
+
+ EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext));
+ // Expect 128-bit (16-byte) tag appended to ciphertext.
+ EXPECT_EQ(message.size() + (tag_bits >> 3), ciphertext.size());
+
+ // Grab nonce.
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt
+ update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Finish(update_params, ciphertext, "" /* signature */,
+ &update_out_params, &plaintext));
+ EXPECT_TRUE(update_out_params.empty());
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadOutOfOrder
+ *
+ * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "123456789012345678901234567890123456";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+ AuthorizationSet begin_out_params;
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+ // No data, AAD only.
+ string ciphertext;
+ int32_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ // AAD and data.
+ EXPECT_EQ(ErrorCode::OK,
+ Update(update_params, message, &update_out_params, &ciphertext, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_TRUE(update_out_params.empty());
+
+ // More AAD
+ EXPECT_EQ(ErrorCode::INVALID_TAG,
+ Update(update_params, "", &update_out_params, &ciphertext, &input_consumed));
+
+ op_.clear();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmBadAad
+ *
+ * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "12345678901234567890123456789012";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+ // Grab nonce
+ begin_params.push_back(begin_out_params);
+
+ finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA,
+ "barfoo" /* Wrong AAD */, (size_t)6);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+ &finish_out_params, &plaintext));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmWrongNonce
+ *
+ * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "12345678901234567890123456789012";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+ // Wrong nonce
+ begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+ &finish_out_params, &plaintext));
+
+ // With wrong nonce, should have gotten garbage plaintext (or none).
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptTag
+ *
+ * Verifies that AES GCM decryption fails correctly when the tag is wrong.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "1234567890123456";
+ string message = "123456789012345678901234567890123456";
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+ EXPECT_TRUE(finish_out_params.empty());
+
+ // Corrupt tag
+ ++(*ciphertext.rbegin());
+
+ // Grab nonce
+ params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+ &finish_out_params, &plaintext));
+ EXPECT_TRUE(finish_out_params.empty());
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess
+ *
+ * Verifies that 3DES is basically functional.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+ auto auths = AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE);
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(auths));
+ // Two-block message.
+ string message = "1234567890123456";
+ auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ string ciphertext1 = EncryptMessage(message, inParams);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), inParams);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // ECB is deterministic.
+ EXPECT_EQ(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, inParams);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNotAuthorized
+ *
+ * Verifies that CBC keys reject ECB usage.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7Padding
+ *
+ * Tests ECB mode with PKCS#7 padding, various message sizes.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::PKCS7)));
+
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ auto inParams =
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, inParams);
+ EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, inParams);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that keys configured for no padding reject PKCS7 padding
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+ for (size_t i = 0; i < 32; ++i) {
+ auto inParams =
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted padding is detected.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::PKCS7)));
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
+ EXPECT_EQ(8U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ AuthorizationSetBuilder begin_params;
+ begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
+ begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ int32_t input_consumed;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+struct TripleDesTestVector {
+ const char* name;
+ const KeyPurpose purpose;
+ const BlockMode block_mode;
+ const PaddingMode padding_mode;
+ const char* key;
+ const char* iv;
+ const char* input;
+ const char* output;
+};
+
+// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all
+// of the NIST vectors are multiples of the block size.
+static const TripleDesTestVector kTripleDesTestVectors[] = {
+ {
+ "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd", // key
+ "", // IV
+ "329d86bdf1bc5af4", // input
+ "d946c2756d78633f", // output
+ },
+ {
+ "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49", // key
+ "", // IV
+ "6b1540781b01ce1997adae102dbf3c5b", // input
+ "4d0dc182d6e481ac4a3dc6ab6976ccae", // output
+ },
+ {
+ "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9", // key
+ "", // IV
+ "6daad94ce08acfe7", // input
+ "660e7d32dcc90e79", // output
+ },
+ {
+ "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce", // key
+ "", // IV
+ "e9653a0a1f05d31b9acd12d73aa9879d", // input
+ "9b2ae9d998efe62f1b592e7e1df8ff38", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37", // key
+ "43f791134c5647ba", // IV
+ "dcc153cef81d6f24", // input
+ "92538bd8af18d3ba", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "c689aee38a301bb316da75db36f110b5", // input
+ "e9afaba5ec75ea1bbe65506655bb4ecb", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC,
+ PaddingMode::PKCS7,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "c689aee38a301bb316da75db36f110b500", // input
+ "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC,
+ PaddingMode::PKCS7,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // input
+ "c689aee38a301bb316da75db36f110b500", // output
+ },
+ {
+ "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1", // key
+ "41746c7e442d3681", // IV
+ "c53a7b0ec40600fe", // input
+ "d4f00eb455de1034", // output
+ },
+ {
+ "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549", // key
+ "3982bc02c3727d45", // IV
+ "6006f10adef52991fcc777a1238bbb65", // input
+ "edae09288e9e3bc05746d872b48e3b29", // output
+ },
+};
+
+/*
+ * EncryptionOperationsTest.TripleDesTestVector
+ *
+ * Verifies that NIST (plus a few extra) test vectors produce the correct results.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesTestVector) {
+ constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
+ for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
+ SCOPED_TRACE(test->name);
+ CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode,
+ hex2str(test->key), hex2str(test->iv), hex2str(test->input),
+ hex2str(test->output));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess
+ *
+ * Validates CBC mode functionality.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ ASSERT_GT(key_blob_.size(), 0U);
+
+ // Two-block message.
+ string message = "1234567890123456";
+ vector<uint8_t> iv1;
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ vector<uint8_t> iv2;
+ string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(iv1, iv2);
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCallerIv
+ *
+ * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCallerIv) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+ string message = "1234567890123456";
+ vector<uint8_t> iv;
+ // Don't specify IV, should get a random one.
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(8U, iv.size());
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify an IV, should also work.
+ iv = AidlBuf("abcdefgh");
+ string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv);
+
+ // Decrypt with correct IV.
+ plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now try with wrong IV.
+ plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, AidlBuf("aaaaaaaa"));
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCallerNonceProhibited.
+ *
+ * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+ vector<uint8_t> iv;
+ // Don't specify nonce, should get a random one.
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(8U, iv.size());
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should fail.
+ auto input_params = AuthorizationSetBuilder()
+ .Authorization(TAG_NONCE, AidlBuf("abcdefgh"))
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED,
+ Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNotAuthorized
+ *
+ * Verifies that 3DES ECB-only keys do not allow CBC usage.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "1234567890123456";
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize
+ *
+ * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+ // Message is slightly shorter than two blocks.
+ string message = "123456789012345";
+
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcPkcs7Padding.
+ *
+ * Verifies that PKCS7 padding works correctly in CBC mode.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::PKCS7)));
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ vector<uint8_t> iv;
+ string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+ EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ // Try various message lengths; all should fail.
+ for (size_t i = 0; i < 32; ++i) {
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted PKCS7 padding is rejected during decryption.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::PKCS7)));
+
+ string message = "a";
+ vector<uint8_t> iv;
+ string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+ EXPECT_EQ(8U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_NONCE, iv);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ int32_t input_consumed;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding.
+ *
+ * Verifies that 3DES CBC works with many different input sizes.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ int increment = 7;
+ string message(240, 'a');
+ AuthorizationSet input_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+
+ string ciphertext;
+ int32_t input_consumed;
+ for (size_t i = 0; i < message.size(); i += increment)
+ EXPECT_EQ(ErrorCode::OK,
+ Update(message.substr(i, increment), &ciphertext, &input_consumed));
+ EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+ EXPECT_EQ(message.size(), ciphertext.size());
+
+ // Move TAG_NONCE into input_params
+ input_params = output_params;
+ input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC);
+ input_params.push_back(TAG_PADDING, PaddingMode::NONE);
+ output_params.Clear();
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment)
+ EXPECT_EQ(ErrorCode::OK,
+ Update(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+ EXPECT_EQ(ErrorCode::OK, Finish(&plaintext));
+ EXPECT_EQ(ciphertext.size(), plaintext.size());
+ EXPECT_EQ(message, plaintext);
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(EncryptionOperationsTest);
+
+typedef KeyMintAidlTestBase MaxOperationsTest;
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with AES keys.
+ */
+TEST_P(MaxOperationsTest, TestLimitAes) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+
+ auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
+
+ EncryptMessage(message, params);
+ EncryptMessage(message, params);
+ EncryptMessage(message, params);
+
+ // Fourth time should fail.
+ EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with RSA keys.
+ */
+TEST_P(MaxOperationsTest, TestLimitRsa) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 65537)
+ .NoDigestOrPadding()
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+
+ auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+ SignMessage(message, params);
+ SignMessage(message, params);
+ SignMessage(message, params);
+
+ // Fourth time should fail.
+ EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(MaxOperationsTest);
+
+typedef KeyMintAidlTestBase AddEntropyTest;
+
+/*
+ * AddEntropyTest.AddEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up. There's no way to test that entropy
+ * is actually added.
+ */
+TEST_P(AddEntropyTest, AddEntropy) {
+ string data = "foo";
+ EXPECT_TRUE(keyMint().addRngEntropy(vector<uint8_t>(data.begin(), data.end())).isOk());
+}
+
+/*
+ * AddEntropyTest.AddEmptyEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
+ */
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
+ EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf()).isOk());
+}
+
+/*
+ * AddEntropyTest.AddLargeEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
+ */
+TEST_P(AddEntropyTest, AddLargeEntropy) {
+ EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf(string(2 * 1024, 'a'))).isOk());
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(AddEntropyTest);
+
+typedef KeyMintAidlTestBase AttestationTest;
+
+/*
+ * AttestationTest.RsaAttestation
+ *
+ * Verifies that attesting to RSA keys works and generates the expected output.
+ */
+// TODO(seleneh) add attestation tests back after decided on the new attestation
+// behavior under generateKey and importKey
+
+typedef KeyMintAidlTestBase KeyDeletionTest;
+
+/**
+ * KeyDeletionTest.DeleteKey
+ *
+ * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
+ * valid key blob.
+ */
+TEST_P(KeyDeletionTest, DeleteKey) {
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+ // Delete must work if rollback protection is implemented
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+ ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params));
+ AbortIfNeeded();
+ key_blob_ = AidlBuf();
+ }
+}
+
+/**
+ * KeyDeletionTest.DeleteInvalidKey
+ *
+ * This test checks that the HAL excepts invalid key blobs..
+ */
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
+ // Generate key just to check if rollback protection is implemented
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+ // Delete must work if rollback protection is implemented
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+ // Delete the key we don't care about the result at this point.
+ DeleteKey();
+
+ // Now create an invalid key blob and delete it.
+ key_blob_ = AidlBuf("just some garbage data which is not a valid key blob");
+
+ ASSERT_EQ(ErrorCode::OK, DeleteKey());
+ }
+}
+
+/**
+ * KeyDeletionTest.DeleteAllKeys
+ *
+ * This test is disarmed by default. To arm it use --arm_deleteAllKeys.
+ *
+ * BEWARE: This test has serious side effects. All user keys will be lost! This includes
+ * FBE/FDE encryption keys, which means that the device will not even boot until after the
+ * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
+ * been provisioned. Use this test only on dedicated testing devices that have no valuable
+ * credentials stored in Keystore/Keymint.
+ */
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
+ if (!arm_deleteAllKeys) return;
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+ // Delete must work if rollback protection is implemented
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+ ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params));
+ AbortIfNeeded();
+ key_blob_ = AidlBuf();
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(KeyDeletionTest);
+
+using UpgradeKeyTest = KeyMintAidlTestBase;
+
+/*
+ * UpgradeKeyTest.UpgradeKey
+ *
+ * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
+ */
+TEST_P(UpgradeKeyTest, UpgradeKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ auto result = UpgradeKey(key_blob_);
+
+ // Key doesn't need upgrading. Should get okay, but no new key blob.
+ EXPECT_EQ(result, std::make_pair(ErrorCode::OK, vector<uint8_t>()));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(UpgradeKeyTest);
+
+using ClearOperationsTest = KeyMintAidlTestBase;
+
+/*
+ * ClearSlotsTest.TooManyOperations
+ *
+ * Verifies that TOO_MANY_OPERATIONS is returned after the max number of
+ * operations are started without being finished or aborted. Also verifies
+ * that aborting the operations clears the operations.
+ *
+ */
+TEST_P(ClearOperationsTest, TooManyOperations) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ constexpr size_t max_operations = 100; // set to arbituary large number
+ sp<IKeyMintOperation> op_handles[max_operations];
+ AuthorizationSet out_params;
+ ErrorCode result;
+ size_t i;
+
+ for (i = 0; i < max_operations; i++) {
+ result = Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, op_handles[i]);
+ if (ErrorCode::OK != result) {
+ break;
+ }
+ }
+ EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, result);
+ // Try again just in case there's a weird overflow bug
+ EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+ Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
+ << "Aboort failed for i = " << j << std::endl;
+ }
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
+ AbortIfNeeded();
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ClearOperationsTest);
+
+typedef KeyMintAidlTestBase TransportLimitTest;
+
+/*
+ * TransportLimitTest.FinishInput
+ *
+ * Verifies that passing input data to finish succeeds as expected.
+ */
+TEST_P(TransportLimitTest, LargeFinishInput) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+
+ for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
+ auto cipher_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+ AuthorizationSet out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+
+ string plain_message = std::string(1 << msg_size, 'x');
+ string encrypted_message;
+ auto rc = Finish(plain_message, &encrypted_message);
+
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), encrypted_message.size())
+ << "Encrypt finish returned OK, but did not consume all of the given input";
+ cipher_params.push_back(out_params);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+
+ string decrypted_message;
+ rc = Finish(encrypted_message, &decrypted_message);
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), decrypted_message.size())
+ << "Decrypt finish returned OK, did not consume all of the given input";
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest);
+
+} // namespace android::hardware::security::keymint::test
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (std::string(argv[i]) == "--arm_deleteAllKeys") {
+ arm_deleteAllKeys = true;
+ }
+ if (std::string(argv[i]) == "--dump_attestations") {
+ dump_Attestations = true;
+ }
+ }
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/security/keymint/aidl/vts/functional/VerificationTokenTest.cpp b/security/keymint/aidl/vts/functional/VerificationTokenTest.cpp
new file mode 100644
index 0000000..6d3a34e
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/VerificationTokenTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "KeyMintAidlTestBase.h"
+
+namespace android::hardware::security::keymint::test {
+
+class VerificationTokenTest : public KeyMintAidlTestBase {
+ protected:
+ struct VerifyAuthorizationResult {
+ ErrorCode error;
+ VerificationToken token;
+ };
+
+ VerifyAuthorizationResult verifyAuthorization(uint64_t operationHandle,
+ const HardwareAuthToken& authToken) {
+ VerifyAuthorizationResult result;
+
+ Status err;
+ err = keyMint().verifyAuthorization(operationHandle, //
+ authToken, //
+ &result.token);
+
+ result.error = GetReturnErrorCode(err);
+ return result;
+ }
+
+ uint64_t getTime() {
+ struct timespec timespec;
+ EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, ×pec));
+ return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+ }
+
+ int sleep_ms(uint32_t milliseconds) {
+ struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000),
+ static_cast<long>(milliseconds % 1000) * 1000000};
+ while (sleep_time.tv_sec || sleep_time.tv_nsec) {
+ if (nanosleep(&sleep_time /* to wait */,
+ &sleep_time /* remaining (on interrruption) */) == 0) {
+ sleep_time = {};
+ } else {
+ if (errno != EINTR) return errno;
+ }
+ }
+ return 0;
+ }
+};
+
+/*
+ * VerificationTokens exist to facilitate cross-KeyMint verification of requirements. As
+ * such, the precise capabilities required will vary depending on the specific vendor
+ * implementations. Essentially, VerificationTokens are a "hook" to enable vendor
+ * implementations to communicate, so the precise usage is defined by those vendors. The only
+ * thing we really can test is that tokens can be created by TEE keyMints, and that the
+ * timestamps increase as expected.
+ */
+TEST_P(VerificationTokenTest, TestCreation) {
+ auto result1 = verifyAuthorization(1 /* operation handle */, HardwareAuthToken());
+ auto result1_time = getTime();
+
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ // StrongBox should not implement verifyAuthorization.
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+ return;
+ }
+
+ ASSERT_EQ(ErrorCode::OK, result1.error);
+ EXPECT_EQ(1U, result1.token.challenge);
+ EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+ EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+ constexpr uint32_t time_to_sleep = 200;
+ sleep_ms(time_to_sleep);
+
+ auto result2 = verifyAuthorization(2 /* operation handle */, HardwareAuthToken());
+
+ auto result2_time = getTime();
+ ASSERT_EQ(ErrorCode::OK, result2.error);
+ EXPECT_EQ(2U, result2.token.challenge);
+ EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+
+ auto host_time_delta = result2_time - result1_time;
+
+ EXPECT_GE(host_time_delta, time_to_sleep)
+ << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+ EXPECT_LE(host_time_delta, time_to_sleep + 20)
+ << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+ << " ms? That's awful!";
+
+ auto km_time_delta =
+ result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+
+ // If not too much else is going on on the system, the time delta should be quite close. Allow
+ // 2 ms of slop just to avoid test flakiness.
+ //
+ // TODO(swillden): see if we can output values so they can be gathered across many runs and
+ // report if times aren't nearly always <1ms apart.
+ EXPECT_LE(host_time_delta, km_time_delta + 2);
+ EXPECT_LE(km_time_delta, host_time_delta + 2);
+ ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+ ASSERT_NE(0,
+ memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+/*
+ * Test that the mac changes when the time stamp changes. This is does not guarantee that the time
+ * stamp is included in the mac but on failure we know that it is not. Other than in the test
+ * case above we call verifyAuthorization with the exact same set of parameters.
+ */
+TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) {
+ auto result1 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
+ auto result1_time = getTime();
+
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ // StrongBox should not implement verifyAuthorization.
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+ return;
+ }
+
+ EXPECT_EQ(ErrorCode::OK, result1.error);
+ EXPECT_EQ(0U, result1.token.challenge);
+ EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+ EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+ constexpr uint32_t time_to_sleep = 200;
+ sleep_ms(time_to_sleep);
+
+ auto result2 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
+ // ASSERT_TRUE(result2.callSuccessful);
+ auto result2_time = getTime();
+ EXPECT_EQ(ErrorCode::OK, result2.error);
+ EXPECT_EQ(0U, result2.token.challenge);
+ EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+
+ auto host_time_delta = result2_time - result1_time;
+
+ EXPECT_GE(host_time_delta, time_to_sleep)
+ << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+ EXPECT_LE(host_time_delta, time_to_sleep + 20)
+ << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+ << " ms? That's awful!";
+
+ auto km_time_delta =
+ result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+
+ EXPECT_LE(host_time_delta, km_time_delta + 2);
+ EXPECT_LE(km_time_delta, host_time_delta + 2);
+ ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+ ASSERT_NE(0,
+ memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VerificationTokenTest);
+
+} // namespace android::hardware::security::keymint::test
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
new file mode 100644
index 0000000..ddac92f
--- /dev/null
+++ b/security/keymint/support/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_library {
+ name: "libkeymint_support",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "attestation_record.cpp",
+ "authorization_set.cpp",
+ "keymint_utils.cpp",
+ "key_param_output.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "android.hardware.security.keymint-cpp",
+ "libbase",
+ "libcrypto",
+ "libutils",
+ ],
+}
diff --git a/security/keymint/support/OWNERS b/security/keymint/support/OWNERS
new file mode 100644
index 0000000..a93b171
--- /dev/null
+++ b/security/keymint/support/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+seleneh@google.com
+swillden@google.com
diff --git a/security/keymint/support/attestation_record.cpp b/security/keymint/support/attestation_record.cpp
new file mode 100644
index 0000000..afdb208
--- /dev/null
+++ b/security/keymint/support/attestation_record.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include <keymint_support/attestation_record.h>
+
+#include <assert.h>
+
+#include <android-base/logging.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <android/hardware/security/keymint/Tag.h>
+#include <android/hardware/security/keymint/TagType.h>
+
+#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+namespace android::hardware::security::keymint {
+
+struct stack_st_ASN1_TYPE_Delete {
+ void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+ void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+ void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+ ASN1_OCTET_STRING* verified_boot_key;
+ ASN1_BOOLEAN device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
+ ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* digest;
+ ASN1_INTEGER_SET* padding;
+ ASN1_INTEGER* ec_curve;
+ ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_INTEGER* creation_date_time;
+ ASN1_INTEGER* origin;
+ ASN1_NULL* rollback_resistance;
+ KM_ROOT_OF_TRUST* root_of_trust;
+ ASN1_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+ ASN1_OCTET_STRING* attestation_application_id;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
+ ASN1_INTEGER* vendor_patchlevel;
+ ASN1_INTEGER* boot_patchlevel;
+ ASN1_NULL* early_boot_only;
+ ASN1_NULL* device_unique_attestation;
+ ASN1_NULL* storage_key;
+ ASN1_NULL* identity_credential;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+ TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+ TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+ TAG_VENDOR_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+ TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
+ TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
+
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
+ ASN1_INTEGER* keymint_version;
+ ASN1_ENUMERATED* keymint_security_level;
+ ASN1_OCTET_STRING* attestation_challenge;
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+ ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+ auth_list->push_back(
+ ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+ }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+ BIGNUM* value = BN_new();
+ BIGNUM_Ptr one(BN_new());
+ BN_one(one.get());
+ BN_lshift(value, one.get(), 32);
+ return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+ static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+ "This implementation only supports 32 and 64-bit BN_ULONG");
+ if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+ BIGNUM_Ptr uint_max(construct_uint_max());
+ BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+ return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+ } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+ return BN_get_word(num);
+ } else {
+ return 0;
+ }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_null) return;
+ auth_list->push_back(ttag);
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_string) return;
+ vector<uint8_t> buf(asn1_string->data, asn1_string->data + asn1_string->length);
+ auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+ if (!record) return ErrorCode::OK;
+
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+ copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+ copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+ copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+ auth_list);
+ copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+ auth_list);
+ copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+ copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+ copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
+ copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
+
+ return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymint_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ SecurityLevel* attestation_security_level,
+ uint32_t* keymint_version, SecurityLevel* keymint_security_level,
+ vector<uint8_t>* attestation_challenge,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced, //
+ vector<uint8_t>* unique_id) {
+ const uint8_t* p = asn1_key_desc;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+ if (!record.get()) return ErrorCode::UNKNOWN_ERROR;
+
+ *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ *attestation_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+ *keymint_version = ASN1_INTEGER_get(record->keymint_version);
+ *keymint_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymint_security_level));
+
+ auto& chall = record->attestation_challenge;
+ attestation_challenge->resize(chall->length);
+ memcpy(attestation_challenge->data(), chall->data, chall->length);
+ auto& uid = record->unique_id;
+ unique_id->resize(uid->length);
+ memcpy(unique_id->data(), uid->data, uid->length);
+
+ ErrorCode error = extract_auth_list(record->software_enforced, software_enforced);
+ if (error != ErrorCode::OK) return error;
+
+ return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ vector<uint8_t>* verified_boot_key,
+ keymint_verified_boot_t* verified_boot_state, bool* device_locked,
+ vector<uint8_t>* verified_boot_hash) {
+ if (!verified_boot_key || !verified_boot_state || !device_locked || !verified_boot_hash) {
+ LOG(ERROR) << AT << "null pointer input(s)";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+ const uint8_t* p = asn1_key_desc;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+ if (!record.get()) {
+ LOG(ERROR) << AT << "Failed record parsing";
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ auto& vb_key = root_of_trust->verified_boot_key;
+ verified_boot_key->resize(vb_key->length);
+ memcpy(verified_boot_key->data(), vb_key->data, vb_key->length);
+
+ *verified_boot_state = static_cast<keymint_verified_boot_t>(
+ ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+ if (!verified_boot_state) {
+ LOG(ERROR) << AT << " Failed verified boot state parsing";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ *device_locked = root_of_trust->device_locked;
+ if (!device_locked) {
+ LOG(ERROR) << AT << " Failed device locked parsing";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ auto& vb_hash = root_of_trust->verified_boot_hash;
+ if (!vb_hash) {
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+ verified_boot_hash->resize(vb_hash->length);
+ memcpy(verified_boot_hash->data(), vb_hash->data, vb_hash->length);
+ return ErrorCode::OK; // KM_ERROR_OK;
+}
+
+} // namespace android::hardware::security::keymint
diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp
new file mode 100644
index 0000000..aa9638f
--- /dev/null
+++ b/security/keymint/support/authorization_set.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include <keymint_support/authorization_set.h>
+
+#include <assert.h>
+#include <sstream>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/security/keymint/Algorithm.h>
+#include <android/hardware/security/keymint/BlockMode.h>
+#include <android/hardware/security/keymint/Digest.h>
+#include <android/hardware/security/keymint/KeyParameter.h>
+#include <android/hardware/security/keymint/KeyPurpose.h>
+#include <android/hardware/security/keymint/TagType.h>
+
+namespace android::hardware::security::keymint {
+
+void AuthorizationSet::Sort() {
+ std::sort(data_.begin(), data_.end());
+}
+
+void AuthorizationSet::Deduplicate() {
+ if (data_.empty()) return;
+
+ Sort();
+ std::vector<KeyParameter> result;
+
+ auto curr = data_.begin();
+ auto prev = curr++;
+ for (; curr != data_.end(); ++prev, ++curr) {
+ if (prev->tag == Tag::INVALID) continue;
+
+ if (*prev != *curr) {
+ result.push_back(std::move(*prev));
+ }
+ }
+ result.push_back(std::move(*prev));
+
+ std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+ data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+ Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+ Deduplicate();
+
+ auto i = other.begin();
+ while (i != other.end()) {
+ int pos = -1;
+ do {
+ pos = find(i->tag, pos);
+ if (pos != -1 && (*i == data_[pos])) {
+ data_.erase(data_.begin() + pos);
+ break;
+ }
+ } while (pos != -1);
+ ++i;
+ }
+}
+
+void AuthorizationSet::Filter(std::function<bool(const KeyParameter&)> doKeep) {
+ std::vector<KeyParameter> result;
+ for (auto& param : data_) {
+ if (doKeep(param)) {
+ result.push_back(std::move(param));
+ }
+ }
+ std::swap(data_, result);
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+ return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+ return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+ data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+ size_t count = 0;
+ for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
+ return count;
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+ auto iter = data_.begin() + (1 + begin);
+
+ while (iter != data_.end() && iter->tag != tag) ++iter;
+
+ if (iter != data_.end()) return iter - data_.begin();
+ return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+ auto pos = data_.begin() + index;
+ if (pos != data_.end()) {
+ data_.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+ int pos = find(tag);
+ if (pos == -1) return {};
+ return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size |
+ * --------------------------------
+ * | indirect_size bytes of data | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count | number of entries
+ * | 32 bit elements_size | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag |
+ * | 32 bit blob_length |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+ std::ostream& indirect;
+ std::ostream& elements;
+ size_t skipped;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const vector<uint8_t>& blob) {
+ uint32_t buffer;
+
+ // write blob_length
+ auto blob_length = blob.size();
+ if (blob_length > std::numeric_limits<uint32_t>::max()) {
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = blob_length;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write indirect_offset
+ auto offset = out.indirect.tellp();
+ if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+ uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = offset;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write blob to indirect stream
+ if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+ return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+ out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+ return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+ // skip invalid entries.
+ ++out.skipped;
+ return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+ out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t));
+ return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<Tags...>::serialize(out, param);
+ }
+};
+
+template <>
+struct choose_serializer<> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag)
+ << ". Did you forget to add it to all_tags_t?";
+ ++out.skipped;
+ return out;
+ }
+};
+
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<android::hardware::security::keymint::TypedTag<tag_type, tag>, Tail...> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ if (param.tag == tag) {
+ return android::hardware::security::keymint::serialize(TypedTag<tag_type, tag>(), out,
+ param);
+ } else {
+ return choose_serializer<Tail...>::serialize(out, param);
+ }
+ }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+ std::stringstream indirect;
+ std::stringstream elements;
+ OutStreams streams = {indirect, elements, 0};
+ for (const auto& param : params) {
+ serialize(streams, param);
+ }
+ if (indirect.bad() || elements.bad()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ auto pos = indirect.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t indirect_size = pos;
+ pos = elements.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t elements_size = pos;
+ uint32_t element_count = params.size() - streams.skipped;
+
+ out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (indirect_size) out << indirect.rdbuf();
+ assert(out.tellp() - pos == indirect_size);
+
+ out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+ out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (elements_size) out << elements.rdbuf();
+ assert(out.tellp() - pos == elements_size);
+
+ return out;
+}
+
+struct InStreams {
+ std::istream& indirect;
+ std::istream& elements;
+ size_t invalids;
+};
+
+InStreams& deserializeParamValue(InStreams& in, vector<uint8_t>* blob) {
+ uint32_t blob_length = 0;
+ uint32_t offset = 0;
+ in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+ blob->resize(blob_length);
+ in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+ in.indirect.seekg(offset);
+ in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+ return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+ in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+ return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+ // there should be no invalid KeyParameters but if handle them as zero sized.
+ ++in.invalids;
+ return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+ return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ return choose_deserializer<Tags...>::deserialize(in, param);
+ }
+};
+template <>
+struct choose_deserializer<> {
+ static InStreams& deserialize(InStreams& in, KeyParameter*) {
+ // encountered an unknown tag -> fail parsing
+ in.elements.setstate(std::ios_base::badbit);
+ return in;
+ }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ if (param->tag == tag) {
+ return android::hardware::security::keymint::deserialize(TypedTag<tag_type, tag>(), in,
+ param);
+ } else {
+ return choose_deserializer<Tail...>::deserialize(in, param);
+ }
+ }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag));
+ return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+ uint32_t indirect_size = 0;
+ in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+ std::string indirect_buffer(indirect_size, '\0');
+ if (indirect_buffer.size() != indirect_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&indirect_buffer[0], indirect_buffer.size());
+
+ uint32_t element_count = 0;
+ in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+ uint32_t elements_size = 0;
+ in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+ std::string elements_buffer(elements_size, '\0');
+ if (elements_buffer.size() != elements_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&elements_buffer[0], elements_buffer.size());
+
+ if (in.bad()) return in;
+
+ // TODO write one-shot stream buffer to avoid copying here
+ std::stringstream indirect(indirect_buffer);
+ std::stringstream elements(elements_buffer);
+ InStreams streams = {indirect, elements, 0};
+
+ params->resize(element_count);
+
+ for (uint32_t i = 0; i < element_count; ++i) {
+ deserialize(streams, &(*params)[i]);
+ }
+
+ /*
+ * There are legacy blobs which have invalid tags in them due to a bug during serialization.
+ * This makes sure that invalid tags are filtered from the result before it is returned.
+ */
+ if (streams.invalids > 0) {
+ std::vector<KeyParameter> filtered(element_count - streams.invalids);
+ auto ifiltered = filtered.begin();
+ for (auto& p : *params) {
+ if (p.tag != Tag::INVALID) {
+ *ifiltered++ = std::move(p);
+ }
+ }
+ *params = std::move(filtered);
+ }
+ return in;
+}
+
+void AuthorizationSet::Serialize(std::ostream* out) const {
+ serialize(*out, data_);
+}
+
+void AuthorizationSet::Deserialize(std::istream* in) {
+ deserialize(*in, &data_);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ Authorization(TAG_ALGORITHM, Algorithm::RSA);
+ Authorization(TAG_KEY_SIZE, key_size);
+ Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::EC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) {
+ Authorization(TAG_ALGORITHM, Algorithm::EC);
+ Authorization(TAG_EC_CURVE, curve);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::AES);
+ return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES);
+ return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+ EcdsaKey(key_size);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
+ EcdsaKey(curve);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+ AesKey(key_size);
+ return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) {
+ TripleDesKey(key_size);
+ return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+ Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+ return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+ Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+ return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+ Authorization(TAG_DIGEST, Digest::NONE);
+ return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+ return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) {
+ return BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, minMacLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) {
+ return BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, macLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
+ std::initializer_list<android::hardware::security::keymint::BlockMode> blockModes) {
+ for (auto mode : blockModes) {
+ push_back(TAG_BLOCK_MODE, mode);
+ }
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(std::vector<keymint::Digest> digests) {
+ for (auto digest : digests) {
+ push_back(TAG_DIGEST, digest);
+ }
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Padding(
+ std::initializer_list<PaddingMode> paddingModes) {
+ for (auto paddingMode : paddingModes) {
+ push_back(TAG_PADDING, paddingMode);
+ }
+ return *this;
+}
+
+} // namespace android::hardware::security::keymint
diff --git a/security/keymint/support/include/keymint_support/attestation_record.h b/security/keymint/support/include/keymint_support/attestation_record.h
new file mode 100644
index 0000000..d71624c
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/attestation_record.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/security/keymint/ErrorCode.h>
+#include <android/hardware/security/keymint/IKeyMintDevice.h>
+
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+
+namespace android::hardware::security::keymint {
+
+class AuthorizationSet;
+
+/**
+ * The OID for Android attestation records. For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+enum keymint_verified_boot_t {
+ KM_VERIFIED_BOOT_VERIFIED = 0,
+ KM_VERIFIED_BOOT_SELF_SIGNED = 1,
+ KM_VERIFIED_BOOT_UNVERIFIED = 2,
+ KM_VERIFIED_BOOT_FAILED = 3,
+};
+
+struct RootOfTrust {
+ SecurityLevel security_level;
+ vector<uint8_t> verified_boot_key;
+ vector<uint8_t> verified_boot_hash;
+ keymint_verified_boot_t verified_boot_state;
+ bool device_locked;
+};
+
+struct AttestationRecord {
+ RootOfTrust root_of_trust;
+ uint32_t attestation_version;
+ SecurityLevel attestation_security_level;
+ uint32_t keymint_version;
+ SecurityLevel keymint_security_level;
+ std::vector<uint8_t> attestation_challenge;
+ AuthorizationSet software_enforced;
+ AuthorizationSet hardware_enforced;
+ std::vector<uint8_t> unique_id;
+};
+
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ SecurityLevel* attestation_security_level,
+ uint32_t* keymint_version, SecurityLevel* keymint_security_level,
+ std::vector<uint8_t>* attestation_challenge,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced, //
+ std::vector<uint8_t>* unique_id);
+
+ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ std::vector<uint8_t>* verified_boot_key,
+ keymint_verified_boot_t* verified_boot_state, bool* device_locked,
+ std::vector<uint8_t>* verified_boot_hash);
+
+} // namespace android::hardware::security::keymint
diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h
new file mode 100644
index 0000000..97e1022
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/authorization_set.h
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+
+#include <vector>
+
+#include <android/hardware/security/keymint/BlockMode.h>
+#include <android/hardware/security/keymint/Digest.h>
+#include <android/hardware/security/keymint/EcCurve.h>
+#include <android/hardware/security/keymint/PaddingMode.h>
+
+#include <keymint_support/keymint_tags.h>
+
+namespace android::hardware::security::keymint {
+
+using std::vector;
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a vector<KeyParameter>.
+ */
+class AuthorizationSet {
+ public:
+ typedef KeyParameter value_type;
+
+ /**
+ * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+ */
+ AuthorizationSet(){};
+
+ // Copy constructor.
+ AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+ // Move constructor.
+ AuthorizationSet(AuthorizationSet&& other) noexcept : data_(std::move(other.data_)) {}
+
+ // Constructor from vector<KeyParameter>
+ AuthorizationSet(const vector<KeyParameter>& other) { *this = other; }
+
+ // Copy assignment.
+ AuthorizationSet& operator=(const AuthorizationSet& other) {
+ data_ = other.data_;
+ return *this;
+ }
+
+ // Move assignment.
+ AuthorizationSet& operator=(AuthorizationSet&& other) noexcept {
+ data_ = std::move(other.data_);
+ return *this;
+ }
+
+ AuthorizationSet& operator=(const vector<KeyParameter>& other) {
+ if (other.size() > 0) {
+ data_.resize(other.size());
+ for (size_t i = 0; i < data_.size(); ++i) {
+ /* This makes a deep copy even of embedded blobs.
+ * See assignment operator/copy constructor of vector.*/
+ data_[i] = other[i];
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Clear existing authorization set data
+ */
+ void Clear();
+
+ ~AuthorizationSet() = default;
+
+ /**
+ * Returns the size of the set.
+ */
+ size_t size() const { return data_.size(); }
+
+ /**
+ * Returns true if the set is empty.
+ */
+ bool empty() const { return size() == 0; }
+
+ /**
+ * Returns the data in the set, directly. Be careful with this.
+ */
+ const KeyParameter* data() const { return data_.data(); }
+
+ /**
+ * Sorts the set
+ */
+ void Sort();
+
+ /**
+ * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+ * AuthorizationSetBuilder).
+ */
+ void Deduplicate();
+
+ /**
+ * Adds all elements from \p set that are not already present in this AuthorizationSet. As a
+ * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+ */
+ void Union(const AuthorizationSet& set);
+
+ /**
+ * Removes all elements in \p set from this AuthorizationSet.
+ */
+ void Subtract(const AuthorizationSet& set);
+
+ /**
+ * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+ * begin. If not found, returns -1.
+ */
+ int find(Tag tag, int begin = -1) const;
+
+ /**
+ * Removes the entry at the specified index. Returns true if successful, false if the index was
+ * out of bounds.
+ */
+ bool erase(int index);
+
+ /**
+ * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+ */
+ std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+ /**
+ * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+ */
+ std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+ /**
+ * Modifies this Authorization set such that it only keeps the entries for which doKeep
+ * returns true.
+ */
+ void Filter(std::function<bool(const KeyParameter&)> doKeep);
+ /**
+ * Returns the nth element of the set.
+ * Like for std::vector::operator[] there is no range check performed. Use of out of range
+ * indices is undefined.
+ */
+ KeyParameter& operator[](int n);
+
+ /**
+ * Returns the nth element of the set.
+ * Like for std::vector::operator[] there is no range check performed. Use of out of range
+ * indices is undefined.
+ */
+ const KeyParameter& operator[](int n) const;
+
+ /**
+ * Returns true if the set contains at least one instance of \p tag
+ */
+ bool Contains(Tag tag) const { return find(tag) != -1; }
+
+ template <TagType tag_type, Tag tag, typename ValueT>
+ bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+ for (const auto& param : data_) {
+ auto entry = authorizationValue(ttag, param);
+ if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
+ }
+ return false;
+ }
+ /**
+ * Returns the number of \p tag entries.
+ */
+ size_t GetTagCount(Tag tag) const;
+
+ template <typename T>
+ inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+ auto entry = GetEntry(tag);
+ if (entry.isOk()) return authorizationValue(tag, entry.value());
+ return {};
+ }
+
+ void push_back(const KeyParameter& param) { data_.push_back(param); }
+ void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+ void push_back(const AuthorizationSet& set) {
+ for (auto& entry : set) {
+ push_back(entry);
+ }
+ }
+ void push_back(AuthorizationSet&& set) {
+ std::move(set.begin(), set.end(), std::back_inserter(*this));
+ }
+
+ /**
+ * Append the tag and enumerated value to the set.
+ * "val" may be exactly one parameter unless a boolean parameter is added.
+ * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+ */
+ template <typename TypedTagT, typename... Value>
+ void push_back(TypedTagT tag, Value&&... val) {
+ push_back(Authorization(tag, std::forward<Value>(val)...));
+ }
+
+ template <typename Iterator>
+ void append(Iterator begin, Iterator end) {
+ while (begin != end) {
+ push_back(*begin);
+ ++begin;
+ }
+ }
+
+ vector<KeyParameter> vector_data() const {
+ vector<KeyParameter> result(begin(), end());
+ return result;
+ }
+
+ void Serialize(std::ostream* out) const;
+ void Deserialize(std::istream* in);
+
+ private:
+ NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+ std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+ public:
+ template <typename TagType, typename... ValueType>
+ AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+ push_back(ttag, std::forward<ValueType>(value)...);
+ return *this;
+ }
+
+ template <Tag tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+ size_t data_length) {
+ vector<uint8_t> new_blob(data, data + data_length);
+ push_back(ttag, new_blob);
+ return *this;
+ }
+
+ template <Tag tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+ size_t data_length) {
+ return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+ }
+
+ template <Tag tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data,
+ size_t data_length) {
+ return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+ }
+
+ template <Tag tag, size_t size>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag,
+ const char (&data)[size]) {
+ return Authorization(ttag, reinterpret_cast<const uint8_t*>(&data[0]),
+ size - 1); // drop the terminating '\0'
+ }
+
+ AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) {
+ for (const auto& entry : set) {
+ push_back(entry);
+ }
+ return *this;
+ }
+
+ AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+ AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
+ AuthorizationSetBuilder& AesKey(uint32_t key_size);
+ AuthorizationSetBuilder& TripleDesKey(uint32_t key_size);
+ AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+ AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
+ AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+ AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& SigningKey();
+ AuthorizationSetBuilder& EncryptionKey();
+
+ AuthorizationSetBuilder& NoDigestOrPadding();
+
+ AuthorizationSetBuilder& EcbMode();
+ AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength);
+ AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
+
+ AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
+ AuthorizationSetBuilder& Digest(std::vector<Digest> digests);
+ AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
+
+ template <typename... T>
+ AuthorizationSetBuilder& BlockMode(T&&... a) {
+ return BlockMode({std::forward<T>(a)...});
+ }
+ template <typename... T>
+ AuthorizationSetBuilder& Digest(T&&... a) {
+ return Digest({std::forward<T>(a)...});
+ }
+ template <typename... T>
+ AuthorizationSetBuilder& Padding(T&&... a) {
+ return Padding({std::forward<T>(a)...});
+ }
+};
+
+} // namespace android::hardware::security::keymint
+
+#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
diff --git a/security/keymint/support/include/keymint_support/key_param_output.h b/security/keymint/support/include/keymint_support/key_param_output.h
new file mode 100644
index 0000000..82c9689
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/key_param_output.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
+#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
+
+#include <iostream>
+#include <vector>
+
+#include <android/hardware/security/keymint/Algorithm.h>
+#include <android/hardware/security/keymint/BlockMode.h>
+#include <android/hardware/security/keymint/Digest.h>
+#include <android/hardware/security/keymint/EcCurve.h>
+#include <android/hardware/security/keymint/ErrorCode.h>
+#include <android/hardware/security/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/security/keymint/KeyCharacteristics.h>
+#include <android/hardware/security/keymint/KeyOrigin.h>
+#include <android/hardware/security/keymint/KeyParameter.h>
+#include <android/hardware/security/keymint/KeyPurpose.h>
+#include <android/hardware/security/keymint/PaddingMode.h>
+#include <android/hardware/security/keymint/SecurityLevel.h>
+#include <android/hardware/security/keymint/Tag.h>
+#include <android/hardware/security/keymint/TagType.h>
+
+#include "keymint_tags.h"
+
+namespace android::hardware::security::keymint {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Digest value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) {
+ return os << toString(value);
+}
+
+template <typename ValueT>
+::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
+ if (!value.isOk()) {
+ os << "(value not present)";
+ } else {
+ os << value.value();
+ }
+ return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const ::std::vector<KeyParameter>& set);
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& param);
+
+inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) {
+ return os << "SW: " << value.softwareEnforced << ::std::endl
+ << "HW: " << value.hardwareEnforced << ::std::endl;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+ return os << toString(tag);
+}
+
+} // namespace android::hardware::security::keymint
+
+#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h
new file mode 100644
index 0000000..f23e4f2
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/keymint_tags.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
+#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
+
+#include <android/hardware/security/keymint/Algorithm.h>
+#include <android/hardware/security/keymint/BlockMode.h>
+#include <android/hardware/security/keymint/Digest.h>
+#include <android/hardware/security/keymint/EcCurve.h>
+#include <android/hardware/security/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/security/keymint/KeyOrigin.h>
+#include <android/hardware/security/keymint/KeyParameter.h>
+#include <android/hardware/security/keymint/KeyPurpose.h>
+#include <android/hardware/security/keymint/PaddingMode.h>
+#include <android/hardware/security/keymint/SecurityLevel.h>
+#include <android/hardware/security/keymint/Tag.h>
+#include <android/hardware/security/keymint/TagType.h>
+
+namespace android::hardware::security::keymint {
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We
+// need these old values to be able to support old keys that use them.
+// TODO(seleneh) we should delete this code when we stop supporting keymaster1
+// and deletes it.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+ return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of
+ * keymint tag types. Instances are convertible to Tag, so they can be used wherever
+ * Tag is expected, and because they encode the tag type it's possible to create
+ * function overloads that only operate on tags with a particular type.
+ */
+template <TagType tag_type, Tag tag>
+struct TypedTag {
+ inline TypedTag() {
+ // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+ // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile
+ // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+ static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+ }
+ operator Tag() const { return tag; }
+ int32_t maskedTag() { return static_cast<uint32_t>(tag) & 0x0FFFFFFF; }
+};
+
+template <Tag tag>
+struct Tag2TypedTag {
+ typedef TypedTag<typeFromTag(tag), tag> type;
+};
+
+#define DECLARE_TYPED_TAG(name) \
+ typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
+ static TAG_##name##_t TAG_##name;
+
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND);
+DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE);
+DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
+DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER);
+DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(BOOT_PATCHLEVEL);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(CONFIRMATION_TOKEN);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(EARLY_BOOT_ONLY);
+DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(HARDWARE_TYPE);
+DECLARE_TYPED_TAG(IDENTITY_CREDENTIAL_KEY);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(STORAGE_KEY);
+DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
+DECLARE_TYPED_TAG(TRUSTED_USER_PRESENCE_REQUIRED);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(USER_ID);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL);
+
+template <typename... Elems>
+struct MetaList {};
+
+using all_tags_t = MetaList<
+ TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+ TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
+ TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+ TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t,
+ TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
+ TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
+ TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_HARDWARE_TYPE_t,
+ TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t,
+ TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
+ TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t,
+ TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t,
+ TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t,
+ TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t,
+ TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>;
+
+template <typename TypedTagType>
+struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
+ template <Tag tag> \
+ struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
+ typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
+ }; \
+ template <Tag tag> \
+ inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
+ ->const decltype(param.field_name)& { \
+ return param.field_name; \
+ } \
+ template <Tag tag> \
+ inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \
+ ->decltype(param.field_name)& { \
+ return param.field_name; \
+ }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+// TODO(seleneh) change these MAKE_TAG_ENUM_VALUE_ACCESSOR back to the 2 parameter
+// version when aidl supports union
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name, field_type) \
+ template <> \
+ struct TypedTag2ValueType<decltype(typed_tag)> { \
+ typedef field_type type; \
+ }; \
+ inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \
+ ->const field_type& { \
+ return *reinterpret_cast<const field_type*>(¶m.field_name); \
+ } \
+ inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)->field_type& { \
+ return *reinterpret_cast<field_type*>(¶m.field_name); \
+ }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, integer, Algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, integer, BlockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, integer, Digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, integer, EcCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, integer, KeyOrigin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, integer, PaddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, integer, KeyPurpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, integer, HardwareAuthenticatorType)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, integer, SecurityLevel)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+ KeyParameter param;
+ param.tag = tag;
+ param.longInteger = 0;
+ accessTagValue(ttag, param) = std::forward<ValueT>(value);
+ return param;
+}
+
+// the boolean case
+template <Tag tag>
+inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+ KeyParameter param;
+ param.tag = tag;
+ param.boolValue = true;
+ return param;
+}
+
+template <typename... Pack>
+struct FirstOrNoneHelper;
+template <typename First>
+struct FirstOrNoneHelper<First> {
+ typedef First type;
+};
+template <>
+struct FirstOrNoneHelper<> {
+ struct type {};
+};
+
+template <typename... Pack>
+using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+ static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+ "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+ static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+ "Authorization other then TagType::BOOL take exactly one parameter.");
+ static_assert(
+ tag_type == TagType::BOOL ||
+ std::is_convertible<
+ std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+ typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+ "Invalid argument type for given tag.");
+
+ return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ *
+ * TODO(seleneh) replace this with std::optional.
+ */
+template <typename ValueT>
+class NullOr {
+ using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value,
+ std::remove_reference_t<ValueT>*, ValueT>;
+
+ struct pointer_initializer {
+ static std::nullptr_t init() { return nullptr; }
+ };
+ struct value_initializer {
+ static ValueT init() { return ValueT(); }
+ };
+ struct value_pointer_deref_t {
+ static ValueT& deref(ValueT& v) { return v; }
+ };
+ struct reference_deref_t {
+ static auto& deref(internal_t v) { return *v; }
+ };
+ using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value ||
+ std::is_pointer<ValueT>::value,
+ pointer_initializer, value_initializer>;
+ using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t,
+ value_pointer_deref_t>;
+
+ public:
+ NullOr() : value_(initializer_t::init()), null_(true) {}
+ template <typename T>
+ NullOr(T&& value, typename std::enable_if<
+ !std::is_lvalue_reference<ValueT>::value &&
+ std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+ int>::type = 0)
+ : value_(std::forward<ValueT>(value)), null_(false) {}
+ template <typename T>
+ NullOr(T& value, typename std::enable_if<
+ std::is_lvalue_reference<ValueT>::value &&
+ std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+ int>::type = 0)
+ : value_(&value), null_(false) {}
+
+ bool isOk() const { return !null_; }
+
+ const ValueT& value() const& { return deref_t::deref(value_); }
+ ValueT& value() & { return deref_t::deref(value_); }
+ ValueT&& value() && { return std::move(deref_t::deref(value_)); }
+
+ private:
+ internal_t value_;
+ bool null_;
+};
+
+template <typename T>
+std::remove_reference_t<T> NullOrOr(T&& v) {
+ if (v.isOk()) return v;
+ return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+ if (head.isOk()) return head;
+ return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+ static_assert(std::is_convertible<std::remove_reference_t<Default>,
+ std::remove_reference_t<Wrapped>>::value,
+ "Type of default value must match the type wrapped by NullOr");
+ if (optional.isOk()) return optional.value();
+ return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
+ TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+ if (tag != param.tag) return {};
+ return accessTagValue(ttag, param);
+}
+
+} // namespace android::hardware::security::keymint
+
+#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
diff --git a/security/keymint/support/include/keymint_support/keymint_utils.h b/security/keymint/support/include/keymint_support/keymint_utils.h
new file mode 100644
index 0000000..fda1b6c
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/keymint_utils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
+
+#include <android/hardware/security/keymint/HardwareAuthToken.h>
+
+namespace android::hardware::security::keymint {
+
+using std::vector;
+
+inline static std::vector<uint8_t> blob2vector(const uint8_t* data, const size_t length) {
+ std::vector<uint8_t> result(data, data + length);
+ return result;
+}
+
+inline static std::vector<uint8_t> blob2vector(const std::string& value) {
+ vector<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()),
+ reinterpret_cast<const uint8_t*>(value.data()) + value.size());
+ return result;
+}
+
+HardwareAuthToken vector2AuthToken(const vector<uint8_t>& buffer);
+vector<uint8_t> authToken2vector(const HardwareAuthToken& token);
+
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
+} // namespace android::hardware::security::keymint
+
+#endif // HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h
new file mode 100644
index 0000000..cb09968
--- /dev/null
+++ b/security/keymint/support/include/keymint_support/openssl_utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
+
+#include <android/hardware/security/keymint/Digest.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+namespace android::hardware::security::keymint {
+
+template <typename T, void (*F)(T*)>
+struct UniquePtrDeleter {
+ void operator()(T* p) const { F(p); }
+};
+
+typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
+
+#define MAKE_OPENSSL_PTR_TYPE(type) \
+ typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
+
+MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
+MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
+MAKE_OPENSSL_PTR_TYPE(RSA)
+MAKE_OPENSSL_PTR_TYPE(X509)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+
+typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
+
+inline const EVP_MD* openssl_digest(Digest digest) {
+ switch (digest) {
+ case Digest::NONE:
+ return nullptr;
+ case Digest::MD5:
+ return EVP_md5();
+ case Digest::SHA1:
+ return EVP_sha1();
+ case Digest::SHA_2_224:
+ return EVP_sha224();
+ case Digest::SHA_2_256:
+ return EVP_sha256();
+ case Digest::SHA_2_384:
+ return EVP_sha384();
+ case Digest::SHA_2_512:
+ return EVP_sha512();
+ }
+ return nullptr;
+}
+
+} // namespace android::hardware::security::keymint
+
+#endif // HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
diff --git a/security/keymint/support/key_param_output.cpp b/security/keymint/support/key_param_output.cpp
new file mode 100644
index 0000000..b699b22
--- /dev/null
+++ b/security/keymint/support/key_param_output.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <keymint_support/key_param_output.h>
+
+#include <iomanip>
+
+#include <keymint_support/keymint_tags.h>
+
+namespace android::hardware::security::keymint {
+
+using ::std::endl;
+using ::std::ostream;
+
+ostream& operator<<(ostream& os, const ::std::vector<KeyParameter>& set) {
+ if (set.size() == 0) {
+ os << "(Empty)" << endl;
+ } else {
+ os << "\n";
+ for (const auto& elem : set) os << elem << endl;
+ }
+ return os;
+}
+
+// TODO(seleneh) update this to a parsing that looks at each tags individually
+// such as ALGORITHM BLOCK_MODE when aidl union support is added.
+ostream& operator<<(ostream& os, const KeyParameter& param) {
+ os << param.tag << ": ";
+ switch (typeFromTag(param.tag)) {
+ case TagType::INVALID:
+ return os << " Invalid";
+ case TagType::ENUM_REP:
+ case TagType::ENUM:
+ case TagType::UINT_REP:
+ case TagType::UINT:
+ return os << param.integer;
+ case TagType::ULONG_REP:
+ case TagType::ULONG:
+ case TagType::DATE:
+ return os << param.longInteger;
+ case TagType::BOOL:
+ return os << "true";
+ case TagType::BIGNUM:
+ os << " Bignum: ";
+ for (size_t i = 0; i < param.blob.size(); ++i) {
+ os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+ }
+ return os;
+ case TagType::BYTES:
+ os << " Bytes: ";
+ for (size_t i = 0; i < param.blob.size(); ++i) {
+ os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+ }
+ return os;
+ }
+ return os << "UNKNOWN TAG TYPE!";
+}
+
+} // namespace android::hardware::security::keymint
diff --git a/security/keymint/support/keymint_utils.cpp b/security/keymint/support/keymint_utils.cpp
new file mode 100644
index 0000000..cd4cca2
--- /dev/null
+++ b/security/keymint/support/keymint_utils.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <regex.h>
+
+#include <android-base/properties.h>
+#include <hardware/hw_auth_token.h>
+#include <keymint_support/keymint_utils.h>
+
+#include <arpa/inet.h>
+
+namespace android::hardware::security::keymint {
+
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+ if (match.rm_so == -1) return 0;
+
+ size_t len = match.rm_eo - match.rm_so;
+ std::string s(expression + match.rm_so, len);
+ return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+ std::string prop_value;
+ while (!::android::base::WaitForPropertyCreation(prop))
+ ;
+ prop_value = ::android::base::GetProperty(prop, "" /* default */);
+ return prop_value;
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ int not_match =
+ regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+ uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+ uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+ return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ int not_match =
+ regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+ uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+ if (month < 1 || month > 12) {
+ return 0;
+ }
+ return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+ return getOsPatchlevel(patchlevel.c_str());
+}
+
+} // namespace android::hardware::security::keymint
diff --git a/sensors/2.0/default/SensorsV2_0.h b/sensors/2.0/default/SensorsV2_0.h
index 345835a..8270a35 100644
--- a/sensors/2.0/default/SensorsV2_0.h
+++ b/sensors/2.0/default/SensorsV2_0.h
@@ -28,6 +28,19 @@
namespace implementation {
struct SensorsV2_0 : public ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors> {
+ Return<void>
+ getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+ std::vector<V1_0::SensorInfo> sensors;
+ for (const auto &sensor : mSensors) {
+ sensors.push_back(V2_1::implementation::convertToOldSensorInfo(
+ sensor.second->getSensorInfo()));
+ }
+
+ // Call the HIDL callback with the SensorInfo
+ _hidl_cb(sensors);
+
+ return Void();
+ }
};
} // namespace implementation
diff --git a/sensors/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp
index 2e3d315..4c5386a 100644
--- a/sensors/2.1/default/SensorsV2_1.cpp
+++ b/sensors/2.1/default/SensorsV2_1.cpp
@@ -45,7 +45,8 @@
mSensorInfo.fifoReservedEventCount = 0;
mSensorInfo.fifoMaxEventCount = 0;
mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(V1_0::SensorFlagBits::ON_CHANGE_MODE);
+ mSensorInfo.flags = static_cast<uint32_t>(V1_0::SensorFlagBits::ON_CHANGE_MODE |
+ V1_0::SensorFlagBits::WAKE_UP);
}
};
diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h
index 9f7fe04..c748383 100644
--- a/sensors/2.1/default/SensorsV2_1.h
+++ b/sensors/2.1/default/SensorsV2_1.h
@@ -54,6 +54,23 @@
// Methods from ::android::hardware::sensors::V2_1::ISensors follow.
Return<void> getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override;
+ Return<void>
+ getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+ std::vector<V1_0::SensorInfo> sensors;
+ for (const auto &sensor : mSensors) {
+ auto &info = sensor.second->getSensorInfo();
+ if (info.type != SensorType::HINGE_ANGLE) {
+ sensors.push_back(V2_1::implementation::convertToOldSensorInfo(
+ sensor.second->getSensorInfo()));
+ }
+ }
+
+ // Call the HIDL callback with the SensorInfo
+ _hidl_cb(sensors);
+
+ return Void();
+ }
+
Return<Result> initialize_2_1(
const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
@@ -71,4 +88,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_SENSORS_V2_1_H
\ No newline at end of file
+#endif // ANDROID_HARDWARE_SENSORS_V2_1_H
diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
index 1841dff..642fc89 100644
--- a/sensors/common/default/2.X/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -26,6 +26,7 @@
namespace V2_X {
namespace implementation {
+using ::android::hardware::sensors::V1_0::EventPayload;
using ::android::hardware::sensors::V1_0::MetaDataEventType;
using ::android::hardware::sensors::V1_0::OperationMode;
using ::android::hardware::sensors::V1_0::Result;
@@ -57,11 +58,11 @@
return mSensorInfo;
}
-void Sensor::batch(int32_t samplingPeriodNs) {
- if (samplingPeriodNs < mSensorInfo.minDelay * 1000) {
- samplingPeriodNs = mSensorInfo.minDelay * 1000;
- } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) {
- samplingPeriodNs = mSensorInfo.maxDelay * 1000;
+void Sensor::batch(int64_t samplingPeriodNs) {
+ if (samplingPeriodNs < mSensorInfo.minDelay * 1000ll) {
+ samplingPeriodNs = mSensorInfo.minDelay * 1000ll;
+ } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000ll) {
+ samplingPeriodNs = mSensorInfo.maxDelay * 1000ll;
}
if (mSamplingPeriodNs != samplingPeriodNs) {
@@ -138,10 +139,8 @@
event.sensorHandle = mSensorInfo.sensorHandle;
event.sensorType = mSensorInfo.type;
event.timestamp = ::android::elapsedRealtimeNano();
- event.u.vec3.x = 0;
- event.u.vec3.y = 0;
- event.u.vec3.z = 0;
- event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ memset(&event.u, 0, sizeof(event.u));
+ readEventPayload(event.u);
events.push_back(event);
return events;
}
@@ -189,7 +188,7 @@
for (auto iter = events.begin(); iter != events.end(); ++iter) {
Event ev = *iter;
- if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+ if (!mPreviousEventSet || memcmp(&mPreviousEvent.u, &ev.u, sizeof(ev.u)) != 0) {
outputEvents.push_back(ev);
mPreviousEvent = ev;
mPreviousEventSet = true;
@@ -208,7 +207,7 @@
mSensorInfo.maxRange = 78.4f; // +/- 8g
mSensorInfo.resolution = 1.52e-5;
mSensorInfo.power = 0.001f; // mA
- mSensorInfo.minDelay = 20 * 1000; // microseconds
+ mSensorInfo.minDelay = 10 * 1000; // microseconds
mSensorInfo.maxDelay = kDefaultMaxDelayUs;
mSensorInfo.fifoReservedEventCount = 0;
mSensorInfo.fifoMaxEventCount = 0;
@@ -216,6 +215,13 @@
mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
};
+void AccelSensor::readEventPayload(EventPayload& payload) {
+ payload.vec3.x = 0;
+ payload.vec3.y = 0;
+ payload.vec3.z = -9.8;
+ payload.vec3.status = SensorStatus::ACCURACY_HIGH;
+}
+
PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: Sensor(callback) {
mSensorInfo.sensorHandle = sensorHandle;
@@ -235,6 +241,10 @@
mSensorInfo.flags = 0;
};
+void PressureSensor::readEventPayload(EventPayload& payload) {
+ payload.scalar = 1013.25f;
+}
+
MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: Sensor(callback) {
mSensorInfo.sensorHandle = sensorHandle;
@@ -330,25 +340,6 @@
mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
};
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
- mSensorInfo.name = "Device Temp Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
- mSensorInfo.type = SensorType::TEMPERATURE;
- mSensorInfo.typeAsString = "";
- mSensorInfo.maxRange = 80.0f;
- mSensorInfo.resolution = 0.01f;
- mSensorInfo.power = 0.001f;
- mSensorInfo.minDelay = 40 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-}
-
RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
ISensorsEventCallback* callback)
: OnChangeSensor(callback) {
diff --git a/sensors/common/default/2.X/Sensor.h b/sensors/common/default/2.X/Sensor.h
index 2f8a143..8ef11be 100644
--- a/sensors/common/default/2.X/Sensor.h
+++ b/sensors/common/default/2.X/Sensor.h
@@ -32,7 +32,7 @@
namespace V2_X {
namespace implementation {
-static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+static constexpr int32_t kDefaultMaxDelayUs = 10 * 1000 * 1000;
class ISensorsEventCallback {
public:
@@ -47,6 +47,7 @@
using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
using Result = ::android::hardware::sensors::V1_0::Result;
using Event = ::android::hardware::sensors::V2_1::Event;
+ using EventPayload = ::android::hardware::sensors::V1_0::EventPayload;
using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
using SensorType = ::android::hardware::sensors::V2_1::SensorType;
@@ -54,7 +55,7 @@
virtual ~Sensor();
const SensorInfo& getSensorInfo() const;
- void batch(int32_t samplingPeriodNs);
+ void batch(int64_t samplingPeriodNs);
virtual void activate(bool enable);
Result flush();
@@ -65,6 +66,7 @@
protected:
void run();
virtual std::vector<Event> readEvents();
+ virtual void readEventPayload(EventPayload&) {}
static void startThread(Sensor* sensor);
bool isWakeUpSensor();
@@ -101,6 +103,9 @@
class AccelSensor : public Sensor {
public:
AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
};
class GyroSensor : public Sensor {
@@ -113,14 +118,12 @@
AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
-class DeviceTempSensor : public OnChangeSensor {
- public:
- DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
class PressureSensor : public Sensor {
public:
PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
};
class MagnetometerSensor : public Sensor {
diff --git a/sensors/common/default/2.X/Sensors.h b/sensors/common/default/2.X/Sensors.h
index ee8240d..1124425 100644
--- a/sensors/common/default/2.X/Sensors.h
+++ b/sensors/common/default/2.X/Sensors.h
@@ -64,7 +64,6 @@
AddSensor<AccelSensor>();
AddSensor<GyroSensor>();
AddSensor<AmbientTempSensor>();
- AddSensor<DeviceTempSensor>();
AddSensor<PressureSensor>();
AddSensor<MagnetometerSensor>();
AddSensor<LightSensor>();
@@ -79,19 +78,6 @@
}
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
- Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
- std::vector<V1_0::SensorInfo> sensors;
- for (const auto& sensor : mSensors) {
- sensors.push_back(
- V2_1::implementation::convertToOldSensorInfo(sensor.second->getSensorInfo()));
- }
-
- // Call the HIDL callback with the SensorInfo
- _hidl_cb(sensors);
-
- return Void();
- }
-
Return<Result> setOperationMode(OperationMode mode) override {
for (auto sensor : mSensors) {
sensor.second->setOperationMode(mode);
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index 8dda0af..f5fc066 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -124,7 +124,9 @@
Return<void> HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) {
std::vector<V1_0::SensorInfo> sensors;
for (const auto& iter : mSensors) {
+ if (iter.second.type != SensorType::HINGE_ANGLE) {
sensors.push_back(convertToOldSensorInfo(iter.second));
+ }
}
_hidl_cb(sensors);
return Void();
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
index 1efd971..69debb6 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
@@ -71,9 +71,10 @@
return mSensorInfo;
}
-void Sensor::batch(int32_t samplingPeriodNs) {
- samplingPeriodNs =
- std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+void Sensor::batch(int64_t samplingPeriodNs) {
+ samplingPeriodNs = std::clamp(samplingPeriodNs,
+ static_cast<int64_t>(mSensorInfo.minDelay) * 1000,
+ static_cast<int64_t>(mSensorInfo.maxDelay) * 1000);
if (mSamplingPeriodNs != samplingPeriodNs) {
mSamplingPeriodNs = samplingPeriodNs;
@@ -323,17 +324,6 @@
mSensorInfo.minDelay = 40 * 1000; // microseconds
}
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : ContinuousSensor(sensorHandle, callback) {
- mSensorInfo.name = "Device Temp Sensor";
- mSensorInfo.type = SensorType::TEMPERATURE;
- mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
- mSensorInfo.maxRange = 80.0f;
- mSensorInfo.resolution = 0.01f;
- mSensorInfo.power = 0.001f;
- mSensorInfo.minDelay = 40 * 1000; // microseconds
-}
-
RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
ISensorsEventCallback* callback)
: OnChangeSensor(sensorHandle, callback) {
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
index 5cf9f83..08c8647 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
@@ -49,7 +49,7 @@
virtual ~Sensor();
const SensorInfo& getSensorInfo() const;
- void batch(int32_t samplingPeriodNs);
+ void batch(int64_t samplingPeriodNs);
virtual void activate(bool enable);
Result flush();
@@ -114,11 +114,6 @@
std::vector<Event> readEvents() override;
};
-class DeviceTempSensor : public ContinuousSensor {
- public:
- DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
class PressureSensor : public ContinuousSensor {
public:
PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
index 1a78e84..353563c 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -206,7 +206,6 @@
ISensorsSubHalBase::AddSensor<GyroSensor>();
ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
ISensorsSubHalBase::AddSensor<PressureSensor>();
- ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
}
};
@@ -231,7 +230,6 @@
ISensorsSubHalBase::AddSensor<GyroSensor>();
ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
ISensorsSubHalBase::AddSensor<PressureSensor>();
- ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
ISensorsSubHalBase::AddSensor<AmbientTempSensor>();
ISensorsSubHalBase::AddSensor<LightSensor>();
ISensorsSubHalBase::AddSensor<ProximitySensor>();
diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
index e674ddb..8cf5003 100644
--- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -366,7 +366,7 @@
for (const SensorInfoType& sensor : getSensorsList()) {
maxHandle = std::max(maxHandle, sensor.sensorHandle);
}
- return maxHandle + 1;
+ return maxHandle + 42;
}
// Test if sensor list returned is valid
@@ -845,7 +845,11 @@
std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
char* buffer = mem->getBuffer();
- memset(buffer, 0xff, mem->getSize());
+ size_t size = mem->getSize();
+
+ if (supportsSharedMemType) {
+ memset(buffer, 0xff, size);
+ }
registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
if (supportsSharedMemType) {
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index 03bec87..a8e1996 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -109,7 +109,6 @@
case SensorTypeT::MAGNETIC_FIELD:
case SensorTypeT::ORIENTATION:
case SensorTypeT::PRESSURE:
- case SensorTypeT::TEMPERATURE:
case SensorTypeT::GRAVITY:
case SensorTypeT::LINEAR_ACCELERATION:
case SensorTypeT::ROTATION_VECTOR:
@@ -145,6 +144,10 @@
case SensorTypeT::DYNAMIC_SENSOR_META:
return SensorFlagBits::SPECIAL_REPORTING_MODE;
+ case SensorTypeT::TEMPERATURE:
+ ALOGW("Device temperature sensor is deprecated, ignoring for test");
+ return (SensorFlagBits)-1;
+
default:
ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
return (SensorFlagBits)-1;
@@ -334,7 +337,7 @@
usleep(500000); // sleep 0.5 sec to wait for change rate to happen
events1 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment());
- // second collection, without stop sensor
+ // second collection, without stopping the sensor
ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
usleep(500000); // sleep 0.5 sec to wait for change rate to happen
diff --git a/soundtrigger/2.1/ISoundTriggerHwCallback.hal b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
index 42e851b..b7720b6 100644
--- a/soundtrigger/2.1/ISoundTriggerHwCallback.hal
+++ b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
@@ -22,7 +22,6 @@
/**
* SoundTrigger HAL Callback interface. Obtained during SoundTrigger setup.
*/
-@hidl_callback
interface ISoundTriggerHwCallback extends @2.0::ISoundTriggerHwCallback {
/**
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
index ed40d25..80f7727 100644
--- a/tests/extension/vibrator/aidl/default/Android.bp
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -19,7 +19,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.vibrator-ndk_platform",
- "android.hardware.tests.extension.vibrator-ndk_platform",
+ "android.hardware.vibrator-unstable-ndk_platform",
+ "android.hardware.tests.extension.vibrator-unstable-ndk_platform",
],
}
diff --git a/tests/foo/1.0/IFoo.hal b/tests/foo/1.0/IFoo.hal
index 4c54427..e242616 100644
--- a/tests/foo/1.0/IFoo.hal
+++ b/tests/foo/1.0/IFoo.hal
@@ -21,6 +21,7 @@
import ISimple;
import ITheirTypes.FloatArray;
+@SensitiveData // for test
interface IFoo {
enum SomeBaseEnum : uint8_t {
diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp
index c51dd8b..c397df4 100644
--- a/tetheroffload/control/1.0/vts/functional/Android.bp
+++ b/tetheroffload/control/1.0/vts/functional/Android.bp
@@ -15,10 +15,18 @@
cc_test {
name: "VtsHalTetheroffloadControlV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
- srcs: ["VtsHalTetheroffloadControlV1_0TargetTest.cpp"],
+ local_include_dirs: ["include"],
+ srcs: [
+ "VtsHalTetheroffloadControlV1_0TargetTest.cpp",
+ "OffloadControlTestBase.cpp",
+ "OffloadControlTestUtils.cpp",
+ ],
static_libs: [
"android.hardware.tetheroffload.config@1.0",
"android.hardware.tetheroffload.control@1.0",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp b/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp
new file mode 100644
index 0000000..bd0dad7
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <OffloadControlTestBase.h>
+
+void OffloadControlTestBase::TearDown() {
+ // For good measure, the teardown should try stopOffload() once more, since
+ // different HAL call test cycles might enter this function. Also the
+ // return code cannot be actually expected for all cases, hence ignore it.
+ stopOffload(ExpectBoolean::Ignored);
+}
+
+// The IOffloadConfig HAL is tested more thoroughly elsewhere. Here the class
+// just setup everything correctly and verify basic readiness.
+void OffloadControlTestBase::setupConfigHal() {
+ config = IOffloadConfig::getService(std::get<0>(GetParam()));
+ ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
+
+ unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
+ if (fd1.get() < 0) {
+ ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
+ FAIL();
+ }
+ native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
+ nativeHandle1->data[0] = fd1.release();
+ hidl_handle h1;
+ h1.setTo(nativeHandle1, true);
+
+ unique_fd fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
+ if (fd2.get() < 0) {
+ ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
+ FAIL();
+ }
+ native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
+ nativeHandle2->data[0] = fd2.release();
+ hidl_handle h2;
+ h2.setTo(nativeHandle2, true);
+
+ const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
+ ASSERT_TRUE(ret.isOk());
+}
+
+void OffloadControlTestBase::prepareControlHal() {
+ control = createControl(std::get<1>(GetParam()));
+ ASSERT_NE(nullptr, control.get()) << "Could not get HIDL instance";
+
+ control_cb = new TetheringOffloadCallback();
+ ASSERT_NE(nullptr, control_cb.get()) << "Could not get get offload callback";
+}
+
+void OffloadControlTestBase::initOffload(const bool expected_result) {
+ auto init_cb = [&](bool success, std::string errMsg) {
+ std::string msg = StringPrintf("Unexpectedly %s to init offload: %s",
+ success ? "succeeded" : "failed", errMsg.c_str());
+ ASSERT_EQ(expected_result, success) << msg;
+ };
+ const Return<void> ret = control->initOffload(control_cb, init_cb);
+ ASSERT_TRUE(ret.isOk());
+}
+
+void OffloadControlTestBase::setupControlHal() {
+ prepareControlHal();
+ initOffload(true);
+}
+
+void OffloadControlTestBase::stopOffload(const ExpectBoolean value) {
+ auto cb = [&](bool success, const hidl_string& errMsg) {
+ switch (value) {
+ case ExpectBoolean::False:
+ ASSERT_EQ(false, success) << "Unexpectedly able to stop offload: " << errMsg;
+ break;
+ case ExpectBoolean::True:
+ ASSERT_EQ(true, success) << "Unexpectedly failed to stop offload: " << errMsg;
+ break;
+ case ExpectBoolean::Ignored:
+ break;
+ }
+ };
+ const Return<void> ret = control->stopOffload(cb);
+ ASSERT_TRUE(ret.isOk());
+}
diff --git a/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp b/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp
new file mode 100644
index 0000000..c784fe1
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <OffloadControlTestUtils.h>
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
+ return reinterpret_cast<const sockaddr*>(nladdr);
+}
+
+int conntrackSocket(unsigned groups) {
+ unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
+ if (s.get() < 0) {
+ return -errno;
+ }
+
+ const struct sockaddr_nl bind_addr = {
+ .nl_family = AF_NETLINK,
+ .nl_pad = 0,
+ .nl_pid = 0,
+ .nl_groups = groups,
+ };
+ if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) < 0) {
+ return -errno;
+ }
+
+ const struct sockaddr_nl kernel_addr = {
+ .nl_family = AF_NETLINK,
+ .nl_pad = 0,
+ .nl_pid = 0,
+ .nl_groups = groups,
+ };
+ if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
+ return -errno;
+ }
+
+ return s.release();
+}
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
index d3a7020..ad4ef12 100644
--- a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
+++ b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
@@ -16,215 +16,24 @@
#define LOG_TAG "VtsOffloadControlV1_0TargetTest"
-#include <VtsHalHidlTargetCallbackBase.h>
+#include <OffloadControlTestV1_0.h>
#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
-#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
-#include <android/hardware/tetheroffload/control/1.0/types.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netlink.h>
-#include <log/log.h>
#include <net/if.h>
#include <sys/socket.h>
-#include <unistd.h>
-#include <set>
using android::base::StringPrintf;
-using android::base::unique_fd;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
using android::hardware::tetheroffload::control::V1_0::IOffloadControl;
-using android::hardware::tetheroffload::control::V1_0::IPv4AddrPortPair;
-using android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
-using android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent;
-using android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate;
-using android::hardware::tetheroffload::control::V1_0::NetworkProtocol;
using android::hardware::Void;
-using android::sp;
-
-enum class ExpectBoolean {
- Ignored = -1,
- False = 0,
- True = 1,
-};
constexpr const char* TEST_IFACE = "rmnet_data0";
-// We use #defines here so as to get local lamba captures and error message line numbers
-#define ASSERT_TRUE_CALLBACK \
- [&](bool success, std::string errMsg) { \
- std::string msg = StringPrintf("unexpected error: %s", errMsg.c_str()); \
- ASSERT_TRUE(success) << msg; \
- }
-
-#define ASSERT_FALSE_CALLBACK \
- [&](bool success, std::string errMsg) { \
- std::string msg = StringPrintf("expected error: %s", errMsg.c_str()); \
- ASSERT_FALSE(success) << msg; \
- }
-
-#define ASSERT_ZERO_BYTES_CALLBACK \
- [&](uint64_t rxBytes, uint64_t txBytes) { \
- EXPECT_EQ(0ULL, rxBytes); \
- EXPECT_EQ(0ULL, txBytes); \
- }
-
-inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
- return reinterpret_cast<const sockaddr*>(nladdr);
-}
-
-int conntrackSocket(unsigned groups) {
- unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
- if (s.get() < 0) {
- return -errno;
- }
-
- const struct sockaddr_nl bind_addr = {
- .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
- };
- if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) < 0) {
- return -errno;
- }
-
- const struct sockaddr_nl kernel_addr = {
- .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
- };
- if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
- return -errno;
- }
-
- return s.release();
-}
-
-constexpr char kCallbackOnEvent[] = "onEvent";
-constexpr char kCallbackUpdateTimeout[] = "updateTimeout";
-
-class TetheringOffloadCallbackArgs {
- public:
- OffloadCallbackEvent last_event;
- NatTimeoutUpdate last_params;
-};
-
-class OffloadControlHidlTestBase
- : public testing::TestWithParam<std::tuple<std::string, std::string>> {
- public:
- virtual void SetUp() override {
- setupConfigHal();
- prepareControlHal();
- }
-
- virtual void TearDown() override {
- // For good measure, we should try stopOffload() once more. Since we
- // don't know where we are in HAL call test cycle we don't know what
- // return code to actually expect, so we just ignore it.
- stopOffload(ExpectBoolean::Ignored);
- }
-
- // The IOffloadConfig HAL is tested more thoroughly elsewhere. He we just
- // setup everything correctly and verify basic readiness.
- void setupConfigHal() {
- config = IOffloadConfig::getService(std::get<0>(GetParam()));
- ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
-
- unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
- if (fd1.get() < 0) {
- ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
- FAIL();
- }
- native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
- nativeHandle1->data[0] = fd1.release();
- hidl_handle h1;
- h1.setTo(nativeHandle1, true);
-
- unique_fd fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
- if (fd2.get() < 0) {
- ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
- FAIL();
- }
- native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
- nativeHandle2->data[0] = fd2.release();
- hidl_handle h2;
- h2.setTo(nativeHandle2, true);
-
- const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
- ASSERT_TRUE(ret.isOk());
- }
-
- void prepareControlHal() {
- control = IOffloadControl::getService(std::get<1>(GetParam()));
- ASSERT_NE(nullptr, control.get()) << "Could not get HIDL instance";
-
- control_cb = new TetheringOffloadCallback();
- ASSERT_NE(nullptr, control_cb.get()) << "Could not get get offload callback";
- }
-
- void initOffload(const bool expected_result) {
- auto init_cb = [&](bool success, std::string errMsg) {
- std::string msg = StringPrintf("Unexpectedly %s to init offload: %s",
- success ? "succeeded" : "failed", errMsg.c_str());
- ASSERT_EQ(expected_result, success) << msg;
- };
- const Return<void> ret = control->initOffload(control_cb, init_cb);
- ASSERT_TRUE(ret.isOk());
- }
-
- void setupControlHal() {
- prepareControlHal();
- initOffload(true);
- }
-
- void stopOffload(const ExpectBoolean value) {
- auto cb = [&](bool success, const hidl_string& errMsg) {
- switch (value) {
- case ExpectBoolean::False:
- ASSERT_EQ(false, success) << "Unexpectedly able to stop offload: " << errMsg;
- break;
- case ExpectBoolean::True:
- ASSERT_EQ(true, success) << "Unexpectedly failed to stop offload: " << errMsg;
- break;
- case ExpectBoolean::Ignored:
- break;
- }
- };
- const Return<void> ret = control->stopOffload(cb);
- ASSERT_TRUE(ret.isOk());
- }
-
- // Callback class for both events and NAT timeout updates.
- class TetheringOffloadCallback
- : public testing::VtsHalHidlTargetCallbackBase<TetheringOffloadCallbackArgs>,
- public ITetheringOffloadCallback {
- public:
- TetheringOffloadCallback() = default;
- virtual ~TetheringOffloadCallback() = default;
-
- Return<void> onEvent(OffloadCallbackEvent event) override {
- const TetheringOffloadCallbackArgs args{.last_event = event};
- NotifyFromCallback(kCallbackOnEvent, args);
- return Void();
- };
-
- Return<void> updateTimeout(const NatTimeoutUpdate& params) override {
- const TetheringOffloadCallbackArgs args{.last_params = params};
- NotifyFromCallback(kCallbackUpdateTimeout, args);
- return Void();
- };
- };
-
- sp<IOffloadConfig> config;
- sp<IOffloadControl> control;
- sp<TetheringOffloadCallback> control_cb;
-};
-
// Call initOffload() multiple times. Check that non-first initOffload() calls return false.
-TEST_P(OffloadControlHidlTestBase, AdditionalInitsWithoutStopReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AdditionalInitsWithoutStopReturnFalse) {
initOffload(true);
initOffload(false);
initOffload(false);
@@ -232,7 +41,7 @@
}
// Check that calling stopOffload() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, MultipleStopsWithoutInitReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, MultipleStopsWithoutInitReturnFalse) {
stopOffload(ExpectBoolean::False);
stopOffload(ExpectBoolean::False);
stopOffload(ExpectBoolean::False);
@@ -251,7 +60,7 @@
}
// Check that calling stopOffload() after a complete init/stop cycle returns false.
-TEST_P(OffloadControlHidlTestBase, AdditionalStopsWithInitReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AdditionalStopsWithInitReturnFalse) {
initOffload(true);
// Call setUpstreamParameters() so that "offload" can be reasonably said
// to be both requested and operational.
@@ -273,7 +82,7 @@
}
// Check that calling setLocalPrefixes() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, SetLocalPrefixesWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetLocalPrefixesWithoutInitReturnsFalse) {
const vector<hidl_string> prefixes{hidl_string("2001:db8::/64")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -281,14 +90,14 @@
// Check that calling getForwardedStats() without first having called initOffload()
// returns zero bytes statistics.
-TEST_P(OffloadControlHidlTestBase, GetForwardedStatsWithoutInitReturnsZeroValues) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, GetForwardedStatsWithoutInitReturnsZeroValues) {
const hidl_string upstream(TEST_IFACE);
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Check that calling setDataLimit() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, SetDataLimitWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetDataLimitWithoutInitReturnsFalse) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -297,7 +106,7 @@
// Check that calling setUpstreamParameters() without first having called initOffload()
// returns false.
-TEST_P(OffloadControlHidlTestBase, SetUpstreamParametersWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetUpstreamParametersWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.0/24");
const hidl_string v4Gw("192.0.2.1");
@@ -309,7 +118,7 @@
// Check that calling addDownstream() with an IPv4 prefix without first having called
// initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, AddIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AddIPv4DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -318,7 +127,7 @@
// Check that calling addDownstream() with an IPv6 prefix without first having called
// initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, AddIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AddIPv6DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -327,7 +136,7 @@
// Check that calling removeDownstream() with an IPv4 prefix without first having called
// initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -336,48 +145,33 @@
// Check that calling removeDownstream() with an IPv6 prefix without first having called
// initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
-class OffloadControlHidlTest : public OffloadControlHidlTestBase {
- public:
- virtual void SetUp() override {
- setupConfigHal();
- setupControlHal();
- }
-
- virtual void TearDown() override {
- // For good measure, we should try stopOffload() once more. Since we
- // don't know where we are in HAL call test cycle we don't know what
- // return code to actually expect, so we just ignore it.
- stopOffload(ExpectBoolean::Ignored);
- }
-};
-
/*
* Tests for IOffloadControl::setLocalPrefixes().
*/
// Test setLocalPrefixes() accepts an IPv4 address.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4AddressOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv4AddressOk) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.1")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() accepts an IPv6 address.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv6AddressOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv6AddressOk) {
const vector<hidl_string> prefixes{hidl_string("fe80::1")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() accepts both IPv4 and IPv6 prefixes.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4v6PrefixesOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv4v6PrefixesOk) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("fe80::/64")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -386,14 +180,14 @@
// Test that setLocalPrefixes() fails given empty input. There is always
// a non-empty set of local prefixes; when all networking interfaces are down
// we still apply {127.0.0.0/8, ::1/128, fe80::/64} here.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesEmptyFails) {
const vector<hidl_string> prefixes{};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() fails on incorrectly formed input strings.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesInvalidFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesInvalidFails) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("invalid")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -404,7 +198,7 @@
*/
// Test that getForwardedStats() for a non-existent upstream yields zero bytes statistics.
-TEST_P(OffloadControlHidlTest, GetForwardedStatsInvalidUpstreamIface) {
+TEST_P(OffloadControlTestV1_0_HalStarted, GetForwardedStatsInvalidUpstreamIface) {
const hidl_string upstream("invalid");
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -412,7 +206,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, GetForwardedStatsDummyIface) {
+TEST_P(OffloadControlTestV1_0_HalStarted, GetForwardedStatsDummyIface) {
const hidl_string upstream(TEST_IFACE);
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -423,7 +217,7 @@
*/
// Test that setDataLimit() for an empty interface name fails.
-TEST_P(OffloadControlHidlTest, SetDataLimitEmptyUpstreamIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitEmptyUpstreamIfaceFails) {
const hidl_string upstream("");
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -432,7 +226,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetDataLimitNonZeroOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitNonZeroOk) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -441,7 +235,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetDataLimitZeroOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitZeroOk) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 0ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -454,7 +248,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv6OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv6OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("");
const hidl_string v4Gw("");
@@ -466,7 +260,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersAlternateIPv6OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersAlternateIPv6OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr;
const hidl_string v4Gw;
@@ -478,7 +272,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv4OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -490,7 +284,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4v6Ok) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv4v6Ok) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -501,7 +295,7 @@
}
// Test that setUpstreamParameters() fails when all parameters are empty.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersEmptyFails) {
const hidl_string iface("");
const hidl_string v4Addr("");
const hidl_string v4Gw("");
@@ -512,7 +306,7 @@
}
// Test that setUpstreamParameters() fails when given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersBogusIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersBogusIfaceFails) {
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -526,7 +320,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv4 addresses.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4AddrFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersInvalidIPv4AddrFails) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Gw("192.0.2.1");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -540,7 +334,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv4 gateways.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4GatewayFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersInvalidIPv4GatewayFails) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -554,7 +348,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv6 gateways.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersBadIPv6GatewaysFail) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersBadIPv6GatewaysFail) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -572,7 +366,7 @@
*/
// Test addDownstream() works given an IPv4 prefix.
-TEST_P(OffloadControlHidlTest, AddDownstreamIPv4) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamIPv4) {
const hidl_string iface("dummy0");
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -580,7 +374,7 @@
}
// Test addDownstream() works given an IPv6 prefix.
-TEST_P(OffloadControlHidlTest, AddDownstreamIPv6) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamIPv6) {
const hidl_string iface("dummy0");
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -588,7 +382,7 @@
}
// Test addDownstream() fails given all empty parameters.
-TEST_P(OffloadControlHidlTest, AddDownstreamEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamEmptyFails) {
const hidl_string iface("");
const hidl_string prefix("");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -596,7 +390,7 @@
}
// Test addDownstream() fails given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, AddDownstreamInvalidIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamInvalidIfaceFails) {
const hidl_string prefix("192.0.2.0/24");
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -607,7 +401,7 @@
}
// Test addDownstream() fails given unparseable prefix arguments.
-TEST_P(OffloadControlHidlTest, AddDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamBogusPrefixFails) {
const hidl_string iface("dummy0");
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -622,7 +416,7 @@
*/
// Test removeDownstream() works given an IPv4 prefix.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv4) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamIPv4) {
const hidl_string iface("dummy0");
const hidl_string prefix("192.0.2.0/24");
// First add the downstream, otherwise removeDownstream logic can reasonably
@@ -634,7 +428,7 @@
}
// Test removeDownstream() works given an IPv6 prefix.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv6) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamIPv6) {
const hidl_string iface("dummy0");
const hidl_string prefix("2001:db8::/64");
// First add the downstream, otherwise removeDownstream logic can reasonably
@@ -646,7 +440,7 @@
}
// Test removeDownstream() fails given all empty parameters.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamEmptyFails) {
const hidl_string iface("");
const hidl_string prefix("");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -654,7 +448,7 @@
}
// Test removeDownstream() fails given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamBogusIfaceFails) {
const hidl_string prefix("192.0.2.0/24");
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -665,7 +459,7 @@
}
// Test removeDownstream() fails given unparseable prefix arguments.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamBogusPrefixFails) {
const hidl_string iface("dummy0");
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -677,21 +471,18 @@
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTestBase);
INSTANTIATE_TEST_CASE_P(
- PerInstance, OffloadControlHidlTestBase,
- testing::Combine(
- testing::ValuesIn(
- android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
- testing::ValuesIn(
- android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
+ PerInstance, OffloadControlTestV1_0_HalNotStarted,
+ testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IOffloadConfig::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IOffloadControl::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTest);
INSTANTIATE_TEST_CASE_P(
- PerInstance, OffloadControlHidlTest,
- testing::Combine(
- testing::ValuesIn(
- android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
- testing::ValuesIn(
- android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
-
+ PerInstance, OffloadControlTestV1_0_HalStarted,
+ testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IOffloadConfig::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IOffloadControl::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h
new file mode 100644
index 0000000..004019a
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <OffloadControlTestUtils.h>
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
+#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
+#include <android/hardware/tetheroffload/control/1.0/types.h>
+#include <gtest/gtest.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <log/log.h>
+
+using android::sp;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
+using android::hardware::tetheroffload::control::V1_0::IOffloadControl;
+using android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
+using android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate;
+using android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent;
+
+constexpr char kCallbackOnEvent[] = "onEvent";
+constexpr char kCallbackUpdateTimeout[] = "updateTimeout";
+
+enum class ExpectBoolean {
+ Ignored = -1,
+ False = 0,
+ True = 1,
+};
+
+class TetheringOffloadCallbackArgs {
+ public:
+ OffloadCallbackEvent last_event;
+ NatTimeoutUpdate last_params;
+};
+
+class OffloadControlTestBase : public testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() = 0;
+
+ virtual void TearDown();
+
+ // Called once in setup stage to retrieve correct version of
+ // IOffloadControl object.
+ virtual sp<IOffloadControl> createControl(const std::string& serviceName) = 0;
+
+ // The IOffloadConfig HAL is tested more thoroughly elsewhere. Here the
+ // class just setup everything correctly and verify basic readiness.
+ void setupConfigHal();
+
+ void prepareControlHal();
+
+ void initOffload(const bool expected_result);
+
+ void setupControlHal();
+
+ void stopOffload(const ExpectBoolean value);
+
+ // Callback class for both events and NAT timeout updates.
+ class TetheringOffloadCallback
+ : public testing::VtsHalHidlTargetCallbackBase<TetheringOffloadCallbackArgs>,
+ public ITetheringOffloadCallback {
+ public:
+ TetheringOffloadCallback() = default;
+ virtual ~TetheringOffloadCallback() = default;
+
+ Return<void> onEvent(OffloadCallbackEvent event) override {
+ const TetheringOffloadCallbackArgs args{.last_event = event};
+ NotifyFromCallback(kCallbackOnEvent, args);
+ return Void();
+ };
+
+ Return<void> updateTimeout(const NatTimeoutUpdate& params) override {
+ const TetheringOffloadCallbackArgs args{.last_params = params};
+ NotifyFromCallback(kCallbackUpdateTimeout, args);
+ return Void();
+ };
+ };
+
+ sp<IOffloadConfig> config;
+ sp<IOffloadControl> control;
+ sp<TetheringOffloadCallback> control_cb;
+};
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h
new file mode 100644
index 0000000..f9e5783
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+// We use #defines here so as to get local lamba captures and error message line numbers
+#define ASSERT_TRUE_CALLBACK \
+ [&](bool success, std::string errMsg) { \
+ ASSERT_TRUE(success) << "unexpected error: " << errMsg; \
+ }
+
+#define ASSERT_FALSE_CALLBACK \
+ [&](bool success, std::string errMsg) { ASSERT_FALSE(success) << "expected error: " << errMsg; }
+
+#define ASSERT_ZERO_BYTES_CALLBACK \
+ [&](uint64_t rxBytes, uint64_t txBytes) { \
+ EXPECT_EQ(0ULL, rxBytes); \
+ EXPECT_EQ(0ULL, txBytes); \
+ }
+
+inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr);
+
+int conntrackSocket(unsigned groups);
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.h
new file mode 100644
index 0000000..7492f8a
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <OffloadControlTestBase.h>
+
+class OffloadControlTestV1_0_HalNotStarted : public OffloadControlTestBase {
+ public:
+ virtual void SetUp() override {
+ setupConfigHal();
+ // Create tether offload control object without calling its initOffload.
+ prepareControlHal();
+ }
+
+ virtual sp<IOffloadControl> createControl(const std::string& serviceName) override {
+ return IOffloadControl::getService(serviceName);
+ }
+};
+
+class OffloadControlTestV1_0_HalStarted : public OffloadControlTestV1_0_HalNotStarted {
+ public:
+ virtual void SetUp() override {
+ setupConfigHal();
+ setupControlHal();
+ }
+};
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index 1765915..7b130ea 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -41,6 +41,9 @@
shared_libs: [
"libbinder",
],
+ data: [
+ ":tuner_frontend_input_ts",
+ ],
test_suites: [
"general-tests",
"vts",
diff --git a/tv/tuner/1.0/vts/functional/AndroidTest.xml b/tv/tuner/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..3a2db27
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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.
+-->
+<configuration description="Runs VtsHalTvTunerV1_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalTvTunerV1_0TargetTest->/data/local/tmp/VtsHalTvTunerV1_0TargetTest" />
+ <option name="push" value="test.es->/data/local/tmp/test.es" />
+ <option name="push" value="segment000000.ts->/data/local/tmp/segment000000.ts" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalTvTunerV1_0TargetTest" />
+ </test>
+</configuration>
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
index df736aa..1e94114 100644
--- a/tv/tuner/1.1/IFilter.hal
+++ b/tv/tuner/1.1/IFilter.hal
@@ -26,6 +26,8 @@
* To access the v1.1 IFilter APIs, the implementation can cast the IFilter
* interface returned from the @1.0::IDemux openFilter into a v1.1 IFiler
* using V1_1::IFilter::castFrom(V1_0::IFilter).
+ *
+ * Note that reconfiguring Filter must happen after the Filter is stopped.
*/
interface IFilter extends @1.0::IFilter {
/**
@@ -83,19 +85,23 @@
configureAvStreamType(AvStreamType avStreamType) generates (Result result);
/**
- * Configure the filter to monitor specific Scrambling Status.
+ * Configure the monitor event.
*
- * Scrambling Status should be sent through the filer callback at the following two scenarios:
+ * The event for Scrambling Status should be sent at the following two scenarios:
* 1. When this method is called, the first detected scrambling status should be sent.
- * 2. When the filter transits into the monitored statuses configured through this method,
- * event should be sent.
+ * 2. When the Scrambling status transits into different status, event should be sent.
*
- * @param statuses Scrambling Statuses to monitor. Set corresponding bit to monitor. Reset to
- * stop monitoring.
+ * The event for IP CID change should be sent at the following two scenarios:
+ * 1. When this method is called, the first detected CID for the IP should be sent.
+ * 2. When the CID is changed to different value for the IP filter, event should be sent.
+ *
+ * @param monitorEventypes the events to monitor. Set corresponding bit of the event to monitor.
+ * Reset to stop monitoring.
* @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if configure can't be applied,
- * UNKNOWN_ERROR if failed for other reasons.
+ * SUCCESS if successful,
+ * INVALID_STATE if configure can't be applied,
+ * UNKNOWN_ERROR if failed for other reasons.
*/
- configureScramblingEvent(bitfield<ScramblingStatus> statuses) generates (Result result);
+ configureMonitorEvent(bitfield<DemuxFilterMonitorEventType> monitorEventTypes)
+ generates (Result result);
};
diff --git a/tv/tuner/1.1/IFilterCallback.hal b/tv/tuner/1.1/IFilterCallback.hal
index 9960a23..23ae844 100644
--- a/tv/tuner/1.1/IFilterCallback.hal
+++ b/tv/tuner/1.1/IFilterCallback.hal
@@ -25,7 +25,8 @@
* Notify the client that a new filter event happened.
*
* @param filterEvent a v1_0 filter event.
- * @param filterEventExt a v1_1 extended filter event.
+ * @param filterEventExt a v1_1 extended filter event. Send an empty filterEvent along with
+ * startId or scramblingStatus filterEventExt
*/
oneway onFilterEvent_1_1(DemuxFilterEvent filterEvent, DemuxFilterEventExt filterEventExt);
};
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index 139e98a..6b2413c 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -131,6 +131,7 @@
break;
}
+ mConfigured = true;
return Result::SUCCESS;
}
@@ -145,8 +146,6 @@
mFilterThreadRunning = false;
- std::lock_guard<std::mutex> lock(mFilterThreadLock);
-
return Result::SUCCESS;
}
@@ -166,8 +165,9 @@
Return<Result> Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) {
ALOGV("%s", __FUNCTION__);
- if ((avMemory.getNativeHandle()->numFds > 0) &&
+ if (mSharedAvMemHandle != NULL && avMemory != NULL &&
(mSharedAvMemHandle.getNativeHandle()->numFds > 0) &&
+ (avMemory.getNativeHandle()->numFds > 0) &&
(sameFile(avMemory.getNativeHandle()->data[0],
mSharedAvMemHandle.getNativeHandle()->data[0]))) {
freeSharedAvHandle();
@@ -251,25 +251,49 @@
return Result::SUCCESS;
}
-Return<Result> Filter::configureScramblingEvent(uint32_t statuses) {
+Return<Result> Filter::configureMonitorEvent(uint32_t monitorEventTypes) {
ALOGV("%s", __FUNCTION__);
- mStatuses = statuses;
- if (mCallback_1_1 != nullptr) {
- // Assuming current status is always NOT_SCRAMBLED
- V1_1::DemuxFilterEventExt filterEventExt;
- V1_1::DemuxFilterEventExt::Event event;
- event.scramblingStatus(V1_1::ScramblingStatus::NOT_SCRAMBLED);
- int size = filterEventExt.events.size();
- filterEventExt.events.resize(size + 1);
- filterEventExt.events[size] = event;
- DemuxFilterEvent emptyFilterEvent;
+ DemuxFilterEvent emptyFilterEvent;
+ V1_1::DemuxFilterMonitorEvent monitorEvent;
+ V1_1::DemuxFilterEventExt eventExt;
- mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, filterEventExt);
- mFilterEventExt.events.resize(0);
- } else {
- return Result::INVALID_STATE;
+ uint32_t newScramblingStatus =
+ monitorEventTypes & V1_1::DemuxFilterMonitorEventType::SCRAMBLING_STATUS;
+ uint32_t newIpCid = monitorEventTypes & V1_1::DemuxFilterMonitorEventType::IP_CID_CHANGE;
+
+ // if scrambling status monitoring flipped, record the new state and send msg on enabling
+ if (newScramblingStatus ^ mScramblingStatusMonitored) {
+ mScramblingStatusMonitored = newScramblingStatus;
+ if (mScramblingStatusMonitored) {
+ if (mCallback_1_1 != nullptr) {
+ // Assuming current status is always NOT_SCRAMBLED
+ monitorEvent.scramblingStatus(V1_1::ScramblingStatus::NOT_SCRAMBLED);
+ eventExt.events.resize(1);
+ eventExt.events[0].monitorEvent(monitorEvent);
+ mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, eventExt);
+ } else {
+ return Result::INVALID_STATE;
+ }
+ }
}
+
+ // if ip cid monitoring flipped, record the new state and send msg on enabling
+ if (newIpCid ^ mIpCidMonitored) {
+ mIpCidMonitored = newIpCid;
+ if (mIpCidMonitored) {
+ if (mCallback_1_1 != nullptr) {
+ // Return random cid
+ monitorEvent.cid(1);
+ eventExt.events.resize(1);
+ eventExt.events[0].monitorEvent(monitorEvent);
+ mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, eventExt);
+ } else {
+ return Result::INVALID_STATE;
+ }
+ }
+ }
+
return Result::SUCCESS;
}
@@ -321,8 +345,17 @@
usleep(1000 * 1000);
continue;
}
+
// After successfully write, send a callback and wait for the read to be done
if (mCallback_1_1 != nullptr) {
+ if (mConfigured) {
+ DemuxFilterEvent emptyEvent;
+ V1_1::DemuxFilterEventExt startEvent;
+ startEvent.events.resize(1);
+ startEvent.events[0].startId(mStartId++);
+ mCallback_1_1->onFilterEvent_1_1(emptyEvent, startEvent);
+ mConfigured = false;
+ }
mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
mFilterEventExt.events.resize(0);
} else if (mCallback != nullptr) {
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
index a7b3fd2..3a4246e 100644
--- a/tv/tuner/1.1/default/Filter.h
+++ b/tv/tuner/1.1/default/Filter.h
@@ -84,7 +84,7 @@
virtual Return<Result> configureAvStreamType(const V1_1::AvStreamType& avStreamType) override;
- virtual Return<Result> configureScramblingEvent(uint32_t statuses) override;
+ virtual Return<Result> configureMonitorEvent(uint32_t monitorEventTypes) override;
/**
* To create a FilterMQ and its Event Flag.
@@ -235,6 +235,11 @@
// Scrambling status to be monitored
uint32_t mStatuses = 0;
+
+ bool mConfigured = false;
+ int mStartId = 0;
+ uint8_t mScramblingStatusMonitored = 0;
+ uint8_t mIpCidMonitored = 0;
};
} // namespace implementation
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
index 006e597..938cb6e 100644
--- a/tv/tuner/1.1/types.hal
+++ b/tv/tuner/1.1/types.hal
@@ -151,16 +151,44 @@
struct DemuxFilterEventExt {
safe_union Event {
/**
- * No extended record filter Event. This is used by the tsRecord or mmtpRecord filter event
- * that does not contain the DemuxFilterTs/MmtpRecordEventExt information.
+ * No extended filter Event.
*/
Monostate noinit;
+ /**
+ * Extended TS Record event sent along with @1.0::DemuxFilterEvent::Event::tsRecord.
+ * DemuxFilterEventExt.events[i] is corresponding to @1.0::DemuxFilterEvent.events[i]. If
+ * @1.0::DemuxFilterEvent.events[i] does not have extended event,
+ * DemuxFilterEventExt.events[i] should use Monostate.
+ */
DemuxFilterTsRecordEventExt tsRecord;
+ /**
+ * Extended MMTP Record event sent along with @1.0::DemuxFilterEvent::Event::mmtpRecord.
+ * DemuxFilterEventExt.events[i] is corresponding to @1.0::DemuxFilterEvent.events[i]. If
+ * @1.0::DemuxFilterEvent.events[i] does not have extended event,
+ * DemuxFilterEventExt.events[i] should use Monostate.
+ */
DemuxFilterMmtpRecordEventExt mmtpRecord;
- ScramblingStatus scramblingStatus;
+ /**
+ * Monitor event to notify monitored status change.
+ *
+ * When sending monitorEvent, DemuxFilterEventExt.events should only contain one
+ * monitorEvent. MonitorEvent should be sent with an empty @1.0::DemuxFilterEvent.
+ */
+ DemuxFilterMonitorEvent monitorEvent;
+
+ /**
+ * An unique ID to mark the start point of receiving the valid filter events after
+ * reconfiguring the filter. It must be sent at least once in the first event after the
+ * filter is restarted. 0 is reserved for the newly opened filter's first start, which is
+ * optional for HAL to send.
+ *
+ * When sending starId, DemuxFilterEventExt.events should only contain one startId event.
+ * StardId event should be sent with an empty @1.0::DemuxFilterEvent.
+ */
+ uint32_t startId;
};
/**
@@ -188,6 +216,24 @@
SCRAMBLED = 1 << 2,
};
+@export
+enum DemuxFilterMonitorEventType : uint32_t {
+ SCRAMBLING_STATUS = 1 << 0,
+ IP_CID_CHANGE = 1 << 1,
+};
+
+safe_union DemuxFilterMonitorEvent {
+ /**
+ * New scrambling status.
+ */
+ ScramblingStatus scramblingStatus;
+
+ /**
+ * New cid for the IP filter.
+ */
+ uint32_t cid;
+};
+
typedef FrontendDvbcSpectralInversion FrontendSpectralInversion;
/**
diff --git a/tv/tuner/1.1/vts/functional/Android.bp b/tv/tuner/1.1/vts/functional/Android.bp
index 1fc36f1..73cd057 100644
--- a/tv/tuner/1.1/vts/functional/Android.bp
+++ b/tv/tuner/1.1/vts/functional/Android.bp
@@ -40,6 +40,9 @@
shared_libs: [
"libbinder",
],
+ data: [
+ ":tuner_frontend_input_es",
+ ],
test_suites: [
"general-tests",
"vts",
diff --git a/tv/tuner/1.1/vts/functional/AndroidTest.xml b/tv/tuner/1.1/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..28f95db
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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.
+-->
+<configuration description="Runs VtsHalTvTunerV1_1TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalTvTunerV1_1TargetTest->/data/local/tmp/VtsHalTvTunerV1_1TargetTest" />
+ <option name="push" value="test.es->/data/local/tmp/test.es" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalTvTunerV1_1TargetTest" />
+ </test>
+</configuration>
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
index d2535e5..d8fad3d 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -40,6 +40,30 @@
ALOGW("[vts] pass and stop");
}
+void FilterCallback::testFilterIpCidEvent() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mIpCidEvent < 1) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "ip cid change event does not output within timeout";
+ return;
+ }
+ }
+ mIpCidEvent = 0;
+ ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::testStartIdAfterReconfigure() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mStartIdReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "does not receive start id within timeout";
+ return;
+ }
+ }
+ mStartIdReceived = false;
+ ALOGW("[vts] pass and stop");
+}
+
void FilterCallback::readFilterEventData() {
ALOGW("[vts] reading filter event");
// todo separate filter handlers
@@ -68,8 +92,21 @@
eventExt.mmtpRecord().pts, eventExt.mmtpRecord().firstMbInSlice,
eventExt.mmtpRecord().mpuSequenceNumber, eventExt.mmtpRecord().tsIndexMask);
break;
- case DemuxFilterEventExt::Event::hidl_discriminator::scramblingStatus:
- mScramblingStatusEvent++;
+ case DemuxFilterEventExt::Event::hidl_discriminator::monitorEvent:
+ switch (eventExt.monitorEvent().getDiscriminator()) {
+ case DemuxFilterMonitorEvent::hidl_discriminator::scramblingStatus:
+ mScramblingStatusEvent++;
+ break;
+ case DemuxFilterMonitorEvent::hidl_discriminator::cid:
+ mIpCidEvent++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case DemuxFilterEventExt::Event::hidl_discriminator::startId:
+ ALOGD("[vts] Extended restart filter event, startId=%d", eventExt.startId());
+ mStartIdReceived = true;
break;
default:
break;
@@ -90,8 +127,8 @@
}
int av_fd = handle.getNativeHandle()->data[0];
- uint8_t* buffer =
- static_cast<uint8_t*>(mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
+ uint8_t* buffer = static_cast<uint8_t*>(
+ mmap(NULL, length + offset, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
if (buffer == MAP_FAILED) {
ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
return false;
@@ -256,18 +293,25 @@
return AssertionResult(status == Result::SUCCESS);
}
-AssertionResult FilterTests::configureScramblingEvent(uint64_t filterId, uint32_t statuses) {
+AssertionResult FilterTests::configureMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes) {
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
Result status;
sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]);
if (filter_v1_1 != NULL) {
- status = filter_v1_1->configureScramblingEvent(statuses);
+ status = filter_v1_1->configureMonitorEvent(monitorEventTypes);
mFilterCallbacks[filterId]->testFilterScramblingEvent();
+ mFilterCallbacks[filterId]->testFilterIpCidEvent();
} else {
ALOGW("[vts] Can't cast IFilter into v1_1.");
return failure();
}
return AssertionResult(status == Result::SUCCESS);
}
+
+AssertionResult FilterTests::startIdTest(uint64_t filterId) {
+ EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ mFilterCallbacks[filterId]->testStartIdAfterReconfigure();
+ return AssertionResult(true);
+}
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
index d88f171..6749265 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.h
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -56,6 +56,7 @@
using android::hardware::tv::tuner::V1_0::Result;
using android::hardware::tv::tuner::V1_1::AvStreamType;
using android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
+using android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEvent;
using android::hardware::tv::tuner::V1_1::IFilterCallback;
using android::hardware::tv::tuner::V1_1::ITuner;
@@ -118,6 +119,8 @@
void testFilterDataOutput();
void testFilterScramblingEvent();
+ void testFilterIpCidEvent();
+ void testStartIdAfterReconfigure();
void readFilterEventData();
bool dumpAvData(DemuxFilterMediaEvent event);
@@ -138,6 +141,8 @@
int mPidFilterOutputCount = 0;
int mScramblingStatusEvent = 0;
+ int mIpCidEvent = 0;
+ bool mStartIdReceived = false;
};
class FilterTests {
@@ -155,11 +160,12 @@
AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
AssertionResult configAvFilterStreamType(AvStreamType type, uint64_t filterId);
AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId);
- AssertionResult configureScramblingEvent(uint64_t filterId, uint32_t statuses);
+ AssertionResult configureMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes);
AssertionResult getFilterMQDescriptor(uint64_t filterId);
AssertionResult startFilter(uint64_t filterId);
AssertionResult stopFilter(uint64_t filterId);
AssertionResult closeFilter(uint64_t filterId);
+ AssertionResult startIdTest(uint64_t filterId);
FilterEventType getFilterEventType(DemuxFilterType type) {
FilterEventType eventType = FilterEventType::UNDEFINED;
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index 17abf49..2dcb9a1 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -46,8 +46,8 @@
if (filterConf.type.mainType == DemuxFilterMainType::IP) {
ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));
}
- if (filterConf.statuses > 0) {
- ASSERT_TRUE(mFilterTests.configureScramblingEvent(filterId, filterConf.statuses));
+ if (filterConf.monitorEventTypes > 0) {
+ ASSERT_TRUE(mFilterTests.configureMonitorEvent(filterId, filterConf.monitorEventTypes));
}
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
ASSERT_TRUE(mFilterTests.startFilter(filterId));
@@ -57,6 +57,39 @@
ASSERT_TRUE(mFrontendTests.closeFrontend());
}
+void TunerFilterHidlTest::reconfigSingleFilterInDemuxTest(FilterConfig filterConf,
+ FilterConfig filterReconf,
+ FrontendConfig frontendConf) {
+ uint32_t feId;
+ uint32_t demuxId;
+ sp<IDemux> demux;
+ uint64_t filterId;
+
+ mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDemux(demux);
+ mFilterTests.setDemux(demux);
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterReconf.settings, filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
void TunerBroadcastHidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf,
FrontendConfig frontendConf) {
uint32_t feId;
@@ -146,6 +179,13 @@
configSingleFilterInDemuxTest(filterArray[IP_IP0], frontendArray[DVBT]);
}
+TEST_P(TunerFilterHidlTest, ReconfigFilterToReceiveStartId) {
+ description("Recofigure and restart a filter to test start id.");
+ // TODO use parameterized tests
+ reconfigSingleFilterInDemuxTest(filterArray[TS_VIDEO0], filterArray[TS_VIDEO1],
+ frontendArray[DVBT]);
+}
+
TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
description("Feed ts data from frontend to recording and test with ts record filter");
recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
index 773224e..d14a2e8 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
@@ -58,7 +58,8 @@
}
void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
-
+ void reconfigSingleFilterInDemuxTest(FilterConfig filterConf, FilterConfig filterReconf,
+ FrontendConfig frontendConf);
sp<ITuner> mService;
FrontendTests mFrontendTests;
DemuxTests mDemuxTests;
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
index 76bf765..beae223 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -96,7 +96,7 @@
DemuxFilterSettings settings;
AvStreamType streamType;
uint32_t ipCid;
- uint32_t statuses;
+ uint32_t monitorEventTypes;
bool operator<(const FilterConfig& /*c*/) const { return false; }
};
@@ -188,7 +188,9 @@
filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M;
filterArray[TS_VIDEO0].settings.ts().tpid = 256;
filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
- filterArray[TS_VIDEO0].statuses = 1;
+ filterArray[TS_VIDEO0].monitorEventTypes =
+ android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEventType::SCRAMBLING_STATUS |
+ android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEventType::IP_CID_CHANGE;
filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;
diff --git a/tv/tuner/assets/Android.bp b/tv/tuner/assets/Android.bp
new file mode 100644
index 0000000..b58b645
--- /dev/null
+++ b/tv/tuner/assets/Android.bp
@@ -0,0 +1,17 @@
+genrule {
+ name: "tuner_frontend_input_es",
+ srcs: ["tuner_frontend_input.es"],
+ out: [
+ "test.es",
+ ],
+ cmd: "cp -f $(in) $(genDir)/test.es",
+}
+
+genrule {
+ name: "tuner_frontend_input_ts",
+ srcs: ["tuner_frontend_input.ts"],
+ out: [
+ "segment000000.ts",
+ ],
+ cmd: "cp -f $(in) $(genDir)/segment000000.ts",
+}
diff --git a/tv/tuner/assets/tuner_frontend_input.es b/tv/tuner/assets/tuner_frontend_input.es
new file mode 100644
index 0000000..b53c957
--- /dev/null
+++ b/tv/tuner/assets/tuner_frontend_input.es
Binary files differ
diff --git a/tv/tuner/assets/tuner_frontend_input.ts b/tv/tuner/assets/tuner_frontend_input.ts
new file mode 100644
index 0000000..8992c7b
--- /dev/null
+++ b/tv/tuner/assets/tuner_frontend_input.ts
Binary files differ
diff --git a/usb/gadget/1.2/Android.bp b/usb/gadget/1.2/Android.bp
new file mode 100644
index 0000000..386f00f
--- /dev/null
+++ b/usb/gadget/1.2/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.usb.gadget@1.2",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IUsbGadget.hal",
+ "IUsbGadgetCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb.gadget@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/usb/gadget/1.2/IUsbGadget.hal b/usb/gadget/1.2/IUsbGadget.hal
new file mode 100644
index 0000000..5c6e930
--- /dev/null
+++ b/usb/gadget/1.2/IUsbGadget.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.hardware.usb.gadget@1.2;
+
+import IUsbGadgetCallback;
+import android.hardware.usb.gadget@1.1::IUsbGadget;
+
+interface IUsbGadget extends @1.1::IUsbGadget {
+ /**
+ * The function is used to query current USB speed.
+ *
+ * @param callback IUsbGadgetCallback::getUsbSpeedCb used to propagate
+ * current USB speed.
+ */
+ oneway getUsbSpeed(IUsbGadgetCallback callback);
+};
diff --git a/usb/gadget/1.2/IUsbGadgetCallback.hal b/usb/gadget/1.2/IUsbGadgetCallback.hal
new file mode 100644
index 0000000..4170573
--- /dev/null
+++ b/usb/gadget/1.2/IUsbGadgetCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.hardware.usb.gadget@1.2;
+
+import UsbSpeed;
+import android.hardware.usb.gadget@1.0::IUsbGadgetCallback;
+
+interface IUsbGadgetCallback extends @1.0::IUsbGadgetCallback {
+ /**
+ * Used to convey the current USB speed to the caller.
+ * Must be called either when USB state changes due to USB enumeration or
+ * when caller requested for USB speed through getUsbSpeed.
+ *
+ * @param speed USB Speed defined by UsbSpeed showed current USB
+ * connection speed.
+ */
+ oneway getUsbSpeedCb(UsbSpeed speed);
+};
+
diff --git a/usb/gadget/1.2/default/Android.bp b/usb/gadget/1.2/default/Android.bp
new file mode 100644
index 0000000..9c73a59
--- /dev/null
+++ b/usb/gadget/1.2/default/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+cc_binary {
+ name: "android.hardware.usb.gadget@1.2-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.usb.gadget@1.2-service.rc"],
+ vintf_fragments: ["android.hardware.usb.gadget@1.2-service.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "UsbGadget.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb.gadget@1.1",
+ "android.hardware.usb.gadget@1.2",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: ["libusbconfigfs-2"],
+}
diff --git a/usb/gadget/1.2/default/UsbGadget.cpp b/usb/gadget/1.2/default/UsbGadget.cpp
new file mode 100644
index 0000000..8dd229e
--- /dev/null
+++ b/usb/gadget/1.2/default/UsbGadget.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.2-service"
+
+#include "UsbGadget.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_2 {
+namespace implementation {
+
+UsbGadget::UsbGadget() {
+ if (access(OS_DESC_PATH, R_OK) != 0) {
+ ALOGE("configfs setup not done yet");
+ abort();
+ }
+}
+
+void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
+ UsbGadget* gadget = (UsbGadget*)payload;
+ gadget->mCurrentUsbFunctionsApplied = functionsApplied;
+}
+
+Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) {
+ Return<void> ret = callback->getCurrentUsbFunctionsCb(
+ mCurrentUsbFunctions, mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED
+ : Status::FUNCTIONS_NOT_APPLIED);
+ if (!ret.isOk()) ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
+
+ return Void();
+}
+
+Return<void> UsbGadget::getUsbSpeed(const sp<V1_2::IUsbGadgetCallback>& callback) {
+ std::string current_speed;
+ if (ReadFileToString(SPEED_PATH, ¤t_speed)) {
+ current_speed = Trim(current_speed);
+ ALOGI("current USB speed is %s", current_speed.c_str());
+ if (current_speed == "low-speed")
+ mUsbSpeed = UsbSpeed::LOWSPEED;
+ else if (current_speed == "full-speed")
+ mUsbSpeed = UsbSpeed::FULLSPEED;
+ else if (current_speed == "high-speed")
+ mUsbSpeed = UsbSpeed::HIGHSPEED;
+ else if (current_speed == "super-speed")
+ mUsbSpeed = UsbSpeed::SUPERSPEED;
+ else if (current_speed == "super-speed-plus")
+ mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
+ else if (current_speed == "UNKNOWN")
+ mUsbSpeed = UsbSpeed::UNKNOWN;
+ else {
+ /**
+ * This part is used for USB4 or reserved speed.
+ *
+ * If reserved speed is detected, it needs to convert to other speeds.
+ * For example:
+ * If the bandwidth of new speed is 7G, adding new if
+ * statement and set mUsbSpeed to SUPERSPEED.
+ * If the bandwidth of new speed is 80G, adding new if
+ * statement and set mUsbSpeed to USB4_GEN3_40Gb.
+ */
+ mUsbSpeed = UsbSpeed::RESERVED_SPEED;
+ }
+ } else {
+ ALOGE("Fail to read current speed");
+ mUsbSpeed = UsbSpeed::UNKNOWN;
+ }
+
+ if (callback) {
+ Return<void> ret = callback->getUsbSpeedCb(mUsbSpeed);
+
+ if (!ret.isOk()) ALOGE("Call to getUsbSpeedCb failed %s", ret.description().c_str());
+ }
+
+ return Void();
+}
+
+V1_0::Status UsbGadget::tearDownGadget() {
+ if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+
+ if (monitorFfs.isMonitorRunning()) {
+ monitorFfs.reset();
+ } else {
+ ALOGI("mMonitor not running");
+ }
+ return V1_0::Status::SUCCESS;
+}
+
+Return<Status> UsbGadget::reset() {
+ if (!WriteStringToFile("none", PULLUP_PATH)) {
+ ALOGI("Gadget cannot be pulled down");
+ return Status::ERROR;
+ }
+
+ usleep(kDisconnectWaitUs);
+
+ if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
+ ALOGI("Gadget cannot be pulled up");
+ return Status::ERROR;
+ }
+
+ return Status::SUCCESS;
+}
+
+static V1_0::Status validateAndSetVidPid(uint64_t functions) {
+ V1_0::Status ret = V1_0::Status::SUCCESS;
+
+ switch (functions) {
+ case static_cast<uint64_t>(V1_2::GadgetFunction::MTP):
+ ret = setVidPid("0x18d1", "0x4ee1");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::MTP:
+ ret = setVidPid("0x18d1", "0x4ee2");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::RNDIS):
+ ret = setVidPid("0x18d1", "0x4ee3");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::RNDIS:
+ ret = setVidPid("0x18d1", "0x4ee4");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::PTP):
+ ret = setVidPid("0x18d1", "0x4ee5");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::PTP:
+ ret = setVidPid("0x18d1", "0x4ee6");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::ADB):
+ ret = setVidPid("0x18d1", "0x4ee7");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::MIDI):
+ ret = setVidPid("0x18d1", "0x4ee8");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::MIDI:
+ ret = setVidPid("0x18d1", "0x4ee9");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::NCM):
+ ret = setVidPid("0x18d1", "0x4eeb");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::NCM:
+ ret = setVidPid("0x18d1", "0x4eec");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::ACCESSORY):
+ ret = setVidPid("0x18d1", "0x2d00");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::ACCESSORY:
+ ret = setVidPid("0x18d1", "0x2d01");
+ break;
+ case static_cast<uint64_t>(V1_2::GadgetFunction::AUDIO_SOURCE):
+ ret = setVidPid("0x18d1", "0x2d02");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d03");
+ break;
+ case V1_2::GadgetFunction::ACCESSORY | V1_2::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d04");
+ break;
+ case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::ACCESSORY |
+ V1_2::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d05");
+ break;
+ default:
+ ALOGE("Combination not supported");
+ ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED;
+ }
+ return ret;
+}
+
+V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) {
+ bool ffsEnabled = false;
+ int i = 0;
+
+ if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
+ V1_0::Status::SUCCESS)
+ return V1_0::Status::ERROR;
+
+ if ((functions & V1_2::GadgetFunction::ADB) != 0) {
+ ffsEnabled = true;
+ if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+ }
+
+ // Pull up the gadget right away when there are no ffs functions.
+ if (!ffsEnabled) {
+ if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
+ mCurrentUsbFunctionsApplied = true;
+ if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+ return V1_0::Status::SUCCESS;
+ }
+
+ monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this);
+ // Monitors the ffs paths to pull up the gadget when descriptors are written.
+ // Also takes of the pulling up the gadget again if the userspace process
+ // dies and restarts.
+ monitorFfs.startMonitor();
+
+ if (kDebug) ALOGI("Mainthread in Cv");
+
+ if (callback) {
+ bool pullup = monitorFfs.waitForPullUp(timeout);
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(
+ functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
+ if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
+ }
+
+ return V1_0::Status::SUCCESS;
+}
+
+Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) {
+ std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
+
+ mCurrentUsbFunctions = functions;
+ mCurrentUsbFunctionsApplied = false;
+
+ // Unlink the gadget and stop the monitor if running.
+ V1_0::Status status = tearDownGadget();
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ ALOGI("Returned from tearDown gadget");
+
+ // Leave the gadget pulled down to give time for the host to sense disconnect.
+ usleep(kDisconnectWaitUs);
+
+ if (functions == static_cast<uint64_t>(V1_2::GadgetFunction::NONE)) {
+ if (callback == NULL) return Void();
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+ if (!ret.isOk())
+ ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+ return Void();
+ }
+
+ status = validateAndSetVidPid(functions);
+
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ status = setupFunctions(functions, callback, timeout);
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ ALOGI("Usb Gadget setcurrent functions called successfully");
+ return Void();
+
+error:
+ ALOGI("Usb Gadget setcurrent functions failed");
+ if (callback == NULL) return Void();
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
+ if (!ret.isOk())
+ ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+ return Void();
+}
+} // namespace implementation
+} // namespace V1_2
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.2/default/UsbGadget.h b/usb/gadget/1.2/default/UsbGadget.h
new file mode 100644
index 0000000..12ad8ee
--- /dev/null
+++ b/usb/gadget/1.2/default/UsbGadget.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_HARDWARE_USB_GADGET_V1_2_USBGADGET_H
+#define ANDROID_HARDWARE_USB_GADGET_V1_2_USBGADGET_H
+
+#include <UsbGadgetCommon.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/usb/gadget/1.2/IUsbGadget.h>
+#include <android/hardware/usb/gadget/1.2/types.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::base::GetProperty;
+using ::android::base::ReadFileToString;
+using ::android::base::SetProperty;
+using ::android::base::Trim;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::usb::gadget::addAdb;
+using ::android::hardware::usb::gadget::addEpollFd;
+using ::android::hardware::usb::gadget::getVendorFunctions;
+using ::android::hardware::usb::gadget::kDebug;
+using ::android::hardware::usb::gadget::kDisconnectWaitUs;
+using ::android::hardware::usb::gadget::linkFunction;
+using ::android::hardware::usb::gadget::MonitorFfs;
+using ::android::hardware::usb::gadget::resetGadget;
+using ::android::hardware::usb::gadget::setVidPid;
+using ::android::hardware::usb::gadget::unlinkFunctions;
+using ::std::string;
+
+constexpr char kGadgetName[] = "11110000.usb";
+static MonitorFfs monitorFfs(kGadgetName);
+
+#define UDC_PATH "/sys/class/udc/11110000.usb/"
+#define SPEED_PATH UDC_PATH "current_speed"
+
+struct UsbGadget : public IUsbGadget {
+ UsbGadget();
+
+ // Makes sure that only one request is processed at a time.
+ std::mutex mLockSetCurrentFunction;
+ uint64_t mCurrentUsbFunctions;
+ bool mCurrentUsbFunctionsApplied;
+ UsbSpeed mUsbSpeed;
+
+ Return<void> setCurrentUsbFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) override;
+
+ Return<void> getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) override;
+
+ Return<Status> reset() override;
+
+ Return<void> getUsbSpeed(const sp<V1_2::IUsbGadgetCallback>& callback) override;
+
+ private:
+ V1_0::Status tearDownGadget();
+ V1_0::Status setupFunctions(uint64_t functions, const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout);
+};
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_USB_V1_2_USBGADGET_H
diff --git a/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.rc b/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.rc
new file mode 100644
index 0000000..650b085
--- /dev/null
+++ b/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.rc
@@ -0,0 +1,7 @@
+service vendor.usb-gadget-hal-1-2 /vendor/bin/hw/android.hardware.usb.gadget@1.2-service
+ interface android.hardware.usb.gadget@1.0::IUsbGadget default
+ interface android.hardware.usb.gadget@1.1::IUsbGadget default
+ interface android.hardware.usb.gadget@1.2::IUsbGadget default
+ class hal
+ user system
+ group system shell mtp
diff --git a/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.xml b/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.xml
new file mode 100644
index 0000000..8557f6f
--- /dev/null
+++ b/usb/gadget/1.2/default/android.hardware.usb.gadget@1.2-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.usb.gadget</name>
+ <transport>hwbinder</transport>
+ <version>1.2</version>
+ <interface>
+ <name>IUsbGadget</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/usb/gadget/1.2/default/lib/Android.bp b/usb/gadget/1.2/default/lib/Android.bp
new file mode 100644
index 0000000..727de13
--- /dev/null
+++ b/usb/gadget/1.2/default/lib/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+cc_library_static {
+ name: "libusbconfigfs-2",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "UsbGadgetUtils.cpp",
+ "MonitorFfs.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb.gadget@1.1",
+ "android.hardware.usb.gadget@1.2",
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libutils",
+ ],
+}
diff --git a/usb/gadget/1.2/default/lib/MonitorFfs.cpp b/usb/gadget/1.2/default/lib/MonitorFfs.cpp
new file mode 100644
index 0000000..0cdf038
--- /dev/null
+++ b/usb/gadget/1.2/default/lib/MonitorFfs.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+static volatile bool gadgetPullup;
+
+MonitorFfs::MonitorFfs(const char* const gadget)
+ : mWatchFd(),
+ mEndpointList(),
+ mLock(),
+ mCv(),
+ mLockFd(),
+ mCurrentUsbFunctionsApplied(false),
+ mMonitor(),
+ mCallback(NULL),
+ mPayload(NULL),
+ mGadgetName(gadget),
+ mMonitorRunning(false) {
+ unique_fd eventFd(eventfd(0, 0));
+ if (eventFd == -1) {
+ ALOGE("mEventFd failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd epollFd(epoll_create(2));
+ if (epollFd == -1) {
+ ALOGE("mEpollFd failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd inotifyFd(inotify_init());
+ if (inotifyFd < 0) {
+ ALOGE("inotify init failed");
+ abort();
+ }
+
+ if (addEpollFd(epollFd, inotifyFd) == -1) abort();
+
+ if (addEpollFd(epollFd, eventFd) == -1) abort();
+
+ mEpollFd = move(epollFd);
+ mInotifyFd = move(inotifyFd);
+ mEventFd = move(eventFd);
+ gadgetPullup = false;
+}
+
+static void displayInotifyEvent(struct inotify_event* i) {
+ ALOGE(" wd =%2d; ", i->wd);
+ if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie);
+
+ ALOGE("mask = ");
+ if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS ");
+ if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB ");
+ if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE ");
+ if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE ");
+ if (i->mask & IN_CREATE) ALOGE("IN_CREATE ");
+ if (i->mask & IN_DELETE) ALOGE("IN_DELETE ");
+ if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF ");
+ if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED ");
+ if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR ");
+ if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY ");
+ if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF ");
+ if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM ");
+ if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO ");
+ if (i->mask & IN_OPEN) ALOGE("IN_OPEN ");
+ if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW ");
+ if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT ");
+ ALOGE("\n");
+
+ if (i->len > 0) ALOGE(" name = %s\n", i->name);
+}
+
+void* MonitorFfs::startMonitorFd(void* param) {
+ MonitorFfs* monitorFfs = (MonitorFfs*)param;
+ char buf[kBufferSize];
+ bool writeUdc = true, stopMonitor = false;
+ struct epoll_event events[kEpollEvents];
+ steady_clock::time_point disconnect;
+
+ bool descriptorWritten = true;
+ for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
+ if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
+ descriptorWritten = false;
+ break;
+ }
+ }
+
+ // notify here if the endpoints are already present.
+ if (descriptorWritten) {
+ usleep(kPullUpDelay);
+ if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+ lock_guard<mutex> lock(monitorFfs->mLock);
+ monitorFfs->mCurrentUsbFunctionsApplied = true;
+ monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
+ gadgetPullup = true;
+ writeUdc = false;
+ ALOGI("GADGET pulled up");
+ monitorFfs->mCv.notify_all();
+ }
+ }
+
+ while (!stopMonitor) {
+ int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
+
+ if (nrEvents <= 0) {
+ ALOGE("epoll wait did not return descriptor number");
+ continue;
+ }
+
+ for (int i = 0; i < nrEvents; i++) {
+ ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
+
+ if (events[i].data.fd == monitorFfs->mInotifyFd) {
+ // Process all of the events in buffer returned by read().
+ int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
+ for (char* p = buf; p < buf + numRead;) {
+ struct inotify_event* event = (struct inotify_event*)p;
+ if (kDebug) displayInotifyEvent(event);
+
+ p += sizeof(struct inotify_event) + event->len;
+
+ bool descriptorPresent = true;
+ for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
+ if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
+ if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
+ descriptorPresent = false;
+ break;
+ }
+ }
+
+ if (!descriptorPresent && !writeUdc) {
+ if (kDebug) ALOGI("endpoints not up");
+ writeUdc = true;
+ disconnect = std::chrono::steady_clock::now();
+ } else if (descriptorPresent && writeUdc) {
+ steady_clock::time_point temp = steady_clock::now();
+
+ if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
+ kPullUpDelay)
+ usleep(kPullUpDelay);
+
+ if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+ lock_guard<mutex> lock(monitorFfs->mLock);
+ monitorFfs->mCurrentUsbFunctionsApplied = true;
+ monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
+ monitorFfs->mPayload);
+ ALOGI("GADGET pulled up");
+ writeUdc = false;
+ gadgetPullup = true;
+ // notify the main thread to signal userspace.
+ monitorFfs->mCv.notify_all();
+ }
+ }
+ }
+ } else {
+ uint64_t flag;
+ read(monitorFfs->mEventFd, &flag, sizeof(flag));
+ if (flag == 100) {
+ stopMonitor = true;
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void MonitorFfs::reset() {
+ lock_guard<mutex> lock(mLockFd);
+ uint64_t flag = 100;
+ unsigned long ret;
+
+ if (mMonitorRunning) {
+ // Stop the monitor thread by writing into signal fd.
+ ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
+ if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno);
+
+ ALOGI("mMonitor signalled to exit");
+ mMonitor->join();
+ ALOGI("mMonitor destroyed");
+ mMonitorRunning = false;
+ }
+
+ for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
+ inotify_rm_watch(mInotifyFd, mWatchFd[i]);
+
+ mEndpointList.clear();
+ gadgetPullup = false;
+ mCallback = NULL;
+ mPayload = NULL;
+}
+
+bool MonitorFfs::startMonitor() {
+ mMonitor = unique_ptr<thread>(new thread(this->startMonitorFd, this));
+ mMonitorRunning = true;
+ return true;
+}
+
+bool MonitorFfs::isMonitorRunning() {
+ return mMonitorRunning;
+}
+
+bool MonitorFfs::waitForPullUp(int timeout_ms) {
+ std::unique_lock<std::mutex> lk(mLock);
+
+ if (gadgetPullup) return true;
+
+ if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
+ ALOGI("monitorFfs signalled true");
+ return true;
+ } else {
+ ALOGI("monitorFfs signalled error");
+ // continue monitoring as the descriptors might be written at a later
+ // point.
+ return false;
+ }
+}
+
+bool MonitorFfs::addInotifyFd(string fd) {
+ lock_guard<mutex> lock(mLockFd);
+ int wfd;
+
+ wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
+ if (wfd == -1)
+ return false;
+ else
+ mWatchFd.push_back(wfd);
+
+ return true;
+}
+
+void MonitorFfs::addEndPoint(string ep) {
+ lock_guard<mutex> lock(mLockFd);
+
+ mEndpointList.push_back(ep);
+}
+
+void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
+ void* payload),
+ void* payload) {
+ mCallback = callback;
+ mPayload = payload;
+}
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
new file mode 100644
index 0000000..8986556
--- /dev/null
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+int unlinkFunctions(const char* path) {
+ DIR* config = opendir(path);
+ struct dirent* function;
+ char filepath[kMaxFilePathLength];
+ int ret = 0;
+
+ if (config == NULL) return -1;
+
+ // d_type does not seems to be supported in /config
+ // so filtering by name.
+ while (((function = readdir(config)) != NULL)) {
+ if ((strstr(function->d_name, FUNCTION_NAME) == NULL)) continue;
+ // build the path for each file in the folder.
+ sprintf(filepath, "%s/%s", path, function->d_name);
+ ret = remove(filepath);
+ if (ret) {
+ ALOGE("Unable remove file %s errno:%d", filepath, errno);
+ break;
+ }
+ }
+
+ closedir(config);
+ return ret;
+}
+
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd) {
+ struct epoll_event event;
+ int ret;
+
+ event.data.fd = fd;
+ event.events = EPOLLIN;
+
+ ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
+ if (ret) ALOGE("epoll_ctl error %d", errno);
+
+ return ret;
+}
+
+int linkFunction(const char* function, int index) {
+ char functionPath[kMaxFilePathLength];
+ char link[kMaxFilePathLength];
+
+ sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
+ sprintf(link, "%s%d", FUNCTION_PATH, index);
+ if (symlink(functionPath, link)) {
+ ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
+ return -1;
+ }
+ return 0;
+}
+
+Status setVidPid(const char* vid, const char* pid) {
+ if (!WriteStringToFile(vid, VENDOR_ID_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile(pid, PRODUCT_ID_PATH)) return Status::ERROR;
+
+ return Status::SUCCESS;
+}
+
+std::string getVendorFunctions() {
+ if (GetProperty(kBuildType, "") == "user") return "user";
+
+ std::string bootMode = GetProperty(PERSISTENT_BOOT_MODE, "");
+ std::string persistVendorFunctions = GetProperty(kPersistentVendorConfig, "");
+ std::string vendorFunctions = GetProperty(kVendorConfig, "");
+ std::string ret = "";
+
+ if (vendorFunctions != "") {
+ ret = vendorFunctions;
+ } else if (bootMode == "usbradio" || bootMode == "factory" || bootMode == "ffbm-00" ||
+ bootMode == "ffbm-01") {
+ if (persistVendorFunctions != "")
+ ret = persistVendorFunctions;
+ else
+ ret = "diag";
+ // vendor.usb.config will reflect the current configured functions
+ SetProperty(kVendorConfig, ret);
+ }
+
+ return ret;
+}
+
+Status resetGadget() {
+ ALOGI("setCurrentUsbFunctions None");
+
+ if (!WriteStringToFile("none", PULLUP_PATH)) ALOGI("Gadget cannot be pulled down");
+
+ if (!WriteStringToFile("0", DEVICE_CLASS_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DEVICE_SUB_CLASS_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DEVICE_PROTOCOL_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DESC_USE_PATH)) return Status::ERROR;
+
+ if (unlinkFunctions(CONFIG_PATH)) return Status::ERROR;
+
+ return Status::SUCCESS;
+}
+
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+ int* functionCount) {
+ if (((functions & GadgetFunction::MTP) != 0)) {
+ *ffsEnabled = true;
+ ALOGI("setCurrentUsbFunctions mtp");
+ if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
+
+ if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
+
+ // Add endpoints to be monitored.
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
+ } else if (((functions & GadgetFunction::PTP) != 0)) {
+ *ffsEnabled = true;
+ ALOGI("setCurrentUsbFunctions ptp");
+ if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
+
+ if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
+
+ // Add endpoints to be monitored.
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
+ }
+
+ if ((functions & GadgetFunction::MIDI) != 0) {
+ ALOGI("setCurrentUsbFunctions MIDI");
+ if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::ACCESSORY) != 0) {
+ ALOGI("setCurrentUsbFunctions Accessory");
+ if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
+ ALOGI("setCurrentUsbFunctions Audio Source");
+ if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::RNDIS) != 0) {
+ ALOGI("setCurrentUsbFunctions rndis");
+ if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
+ std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
+ if (rndisFunction != "") {
+ if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
+ } else {
+ // link gsi.rndis for older pixel projects
+ if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
+ }
+ }
+
+ if ((functions & GadgetFunction::NCM) != 0) {
+ ALOGI("setCurrentUsbFunctions ncm");
+ if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
+ }
+
+ return Status::SUCCESS;
+}
+
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
+ ALOGI("setCurrentUsbFunctions Adb");
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
+
+ if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
+ monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep2");
+ ALOGI("Service started");
+ return Status::SUCCESS;
+}
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h b/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h
new file mode 100644
index 0000000..18b8101
--- /dev/null
+++ b/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef HARDWARE_USB_USBGADGETCOMMON_H
+#define HARDWARE_USB_USBGADGETCOMMON_H
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include <android/hardware/usb/gadget/1.2/IUsbGadget.h>
+#include <android/hardware/usb/gadget/1.2/types.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+constexpr int kBufferSize = 512;
+constexpr int kMaxFilePathLength = 256;
+constexpr int kEpollEvents = 10;
+constexpr bool kDebug = false;
+constexpr int kDisconnectWaitUs = 100000;
+constexpr int kPullUpDelay = 500000;
+constexpr int kShutdownMonitor = 100;
+
+constexpr char kBuildType[] = "ro.build.type";
+constexpr char kPersistentVendorConfig[] = "persist.vendor.usb.usbradio.config";
+constexpr char kVendorConfig[] = "vendor.usb.config";
+constexpr char kVendorRndisConfig[] = "vendor.usb.rndis.config";
+
+#define GADGET_PATH "/config/usb_gadget/g1/"
+#define PULLUP_PATH GADGET_PATH "UDC"
+#define PERSISTENT_BOOT_MODE "ro.bootmode"
+#define VENDOR_ID_PATH GADGET_PATH "idVendor"
+#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
+#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
+#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
+#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
+#define DESC_USE_PATH GADGET_PATH "os_desc/use"
+#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
+#define CONFIG_PATH GADGET_PATH "configs/b.1/"
+#define FUNCTIONS_PATH GADGET_PATH "functions/"
+#define FUNCTION_NAME "function"
+#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
+#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"
+
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::usb::gadget::V1_0::Status;
+using ::android::hardware::usb::gadget::V1_2::GadgetFunction;
+
+using ::std::lock_guard;
+using ::std::move;
+using ::std::mutex;
+using ::std::string;
+using ::std::thread;
+using ::std::unique_ptr;
+using ::std::vector;
+using ::std::chrono::microseconds;
+using ::std::chrono::steady_clock;
+using ::std::literals::chrono_literals::operator""ms;
+
+// MonitorFfs automously manages gadget pullup by monitoring
+// the ep file status. Restarts the usb gadget when the ep
+// owner restarts.
+class MonitorFfs {
+ private:
+ // Monitors the endpoints Inotify events.
+ unique_fd mInotifyFd;
+ // Control pipe for shutting down the mMonitor thread.
+ // mMonitor exits when SHUTDOWN_MONITOR is written into
+ // mEventFd/
+ unique_fd mEventFd;
+ // Pools on mInotifyFd and mEventFd.
+ unique_fd mEpollFd;
+ vector<int> mWatchFd;
+
+ // Maintains the list of Endpoints.
+ vector<string> mEndpointList;
+ // protects the CV.
+ std::mutex mLock;
+ std::condition_variable mCv;
+ // protects mInotifyFd, mEpollFd.
+ std::mutex mLockFd;
+
+ // Flag to maintain the current status of gadget pullup.
+ bool mCurrentUsbFunctionsApplied;
+
+ // Thread object that executes the ep monitoring logic.
+ unique_ptr<thread> mMonitor;
+ // Callback to be invoked when gadget is pulled up.
+ void (*mCallback)(bool functionsApplied, void* payload);
+ void* mPayload;
+ // Name of the USB gadget. Used for pullup.
+ const char* const mGadgetName;
+ // Monitor State
+ bool mMonitorRunning;
+
+ public:
+ MonitorFfs(const char* const gadget);
+ // Inits all the UniqueFds.
+ void reset();
+ // Starts monitoring endpoints and pullup the gadget when
+ // the descriptors are written.
+ bool startMonitor();
+ // Waits for timeout_ms for gadget pull up to happen.
+ // Returns immediately if the gadget is already pulled up.
+ bool waitForPullUp(int timeout_ms);
+ // Adds the given fd to the watch list.
+ bool addInotifyFd(string fd);
+ // Adds the given endpoint to the watch list.
+ void addEndPoint(string ep);
+ // Registers the async callback from the caller to notify the caller
+ // when the gadget pull up happens.
+ void registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, void*(payload)),
+ void* payload);
+ bool isMonitorRunning();
+ // Ep monitoring and the gadget pull up logic.
+ static void* startMonitorFd(void* param);
+};
+
+//**************** Helper functions ************************//
+
+// Adds the given fd to the epollfd(epfd).
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd);
+// Removes all the usb functions link in the specified path.
+int unlinkFunctions(const char* path);
+// Craetes a configfs link for the function.
+int linkFunction(const char* function, int index);
+// Sets the USB VID and PID.
+Status setVidPid(const char* vid, const char* pid);
+// Extracts vendor functions from the vendor init properties.
+std::string getVendorFunctions();
+// Adds Adb to the usb configuration.
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount);
+// Adds all applicable generic android usb functions other than ADB.
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+ int* functionCount);
+// Pulls down USB gadget.
+Status resetGadget();
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
+#endif
diff --git a/usb/gadget/1.2/default/service.cpp b/usb/gadget/1.2/default/service.cpp
new file mode 100644
index 0000000..80c56a6
--- /dev/null
+++ b/usb/gadget/1.2/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.2-service"
+
+#include <hidl/HidlTransportSupport.h>
+#include "UsbGadget.h"
+
+using android::sp;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::usb::gadget::V1_2::IUsbGadget;
+using android::hardware::usb::gadget::V1_2::implementation::UsbGadget;
+
+using android::OK;
+using android::status_t;
+
+int main() {
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ android::sp<IUsbGadget> service = new UsbGadget();
+
+ status_t status = service->registerAsService();
+
+ if (status != OK) {
+ ALOGE("Cannot register USB Gadget HAL service");
+ return 1;
+ }
+
+ ALOGI("USB Gadget HAL Ready.");
+ joinRpcThreadpool();
+ // Under noraml cases, execution will not reach this line.
+ ALOGI("USB Gadget HAL failed to join thread pool.");
+ return 1;
+}
diff --git a/usb/gadget/1.2/types.hal b/usb/gadget/1.2/types.hal
new file mode 100644
index 0000000..a5c079d
--- /dev/null
+++ b/usb/gadget/1.2/types.hal
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 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.hardware.usb.gadget@1.2;
+
+import android.hardware.usb.gadget@1.0::GadgetFunction;
+
+enum GadgetFunction : @1.0::GadgetFunction {
+ /**
+ * NCM - NCM function.
+ */
+ NCM = 1 << 10,
+};
+
+enum UsbSpeed : uint32_t {
+ /**
+ * UNKNOWN - Not Connected or Unsupported Speed
+ */
+ UNKNOWN = -1,
+
+ /**
+ * USB Low Speed
+ */
+ LOWSPEED = 0,
+
+ /**
+ * USB Full Speed
+ */
+ FULLSPEED = 1,
+
+ /**
+ * USB High Speed
+ */
+ HIGHSPEED = 2,
+
+ /**
+ * USB Super Speed
+ */
+ SUPERSPEED = 3,
+
+ /**
+ * USB Super Speed 10Gbps
+ */
+ SUPERSPEED_10Gb = 4,
+
+ /**
+ * USB Super Speed 20Gbps
+ */
+ SUPERSPEED_20Gb = 5,
+
+ /**
+ * USB4 Gen2 x 1 (10Gbps)
+ */
+ USB4_GEN2_10Gb = 6,
+
+ /**
+ * USB4 Gen2 x 2 (20Gbps)
+ */
+ USB4_GEN2_20Gb = 7,
+
+ /**
+ * USB4 Gen3 x 1 (20Gbps)
+ */
+ USB4_GEN3_20Gb = 8,
+
+ /**
+ * USB4 Gen3 x 2 (40Gbps)
+ */
+ USB4_GEN3_40Gb = 9,
+
+ /**
+ * This is a suggestion if needed.
+ *
+ * Reserved Speed -- It is a newer speed after USB4 v1.0 announcement.
+ * If this speed is detected, the HAL implementation should convert current
+ * speed to above speeds which is lower and the closest.
+ */
+ RESERVED_SPEED = 64,
+};
diff --git a/vibrator/aidl/TEST_MAPPING b/vibrator/aidl/TEST_MAPPING
index 5ae32e7..2414b84 100644
--- a/vibrator/aidl/TEST_MAPPING
+++ b/vibrator/aidl/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "VtsHalVibratorTargetTest"
+ },
+ {
+ "name": "VtsHalVibratorManagerTargetTest"
}
]
}
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
new file mode 100644
index 0000000..99cd448
--- /dev/null
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.vibrator;
+@VintfStability
+interface IVibratorManager {
+ int getCapabilities();
+ int[] getVibratorIds();
+ android.hardware.vibrator.IVibrator getVibrator(in int vibratorId);
+ void prepareSynced(in int[] vibratorIds);
+ void triggerSynced(in android.hardware.vibrator.IVibratorCallback callback);
+ void cancelSynced();
+ const int CAP_SYNC = 1;
+ const int CAP_PREPARE_ON = 2;
+ const int CAP_PREPARE_PERFORM = 4;
+ const int CAP_PREPARE_COMPOSE = 8;
+ const int CAP_MIXED_TRIGGER_ON = 16;
+ const int CAP_MIXED_TRIGGER_PERFORM = 32;
+ const int CAP_MIXED_TRIGGER_COMPOSE = 64;
+ const int CAP_TRIGGER_CALLBACK = 128;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 0b21248..cd7b603 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -206,7 +206,10 @@
* device/board configuration files ensuring that no ID is assigned to
* multiple clients. No client should use this API unless explicitly
* assigned an always-on source ID. Clients must develop their own way to
- * get IDs from vendor in a stable way.
+ * get IDs from vendor in a stable way. For instance, a client may expose
+ * a stable API (via HAL, sysprops, or xml overlays) to allow vendor to
+ * associate a hardware ID with a specific usecase. When that usecase is
+ * triggered, a client would use that hardware ID here.
*
* @param id The device-specific always-on source ID to enable.
* @param effect The type of haptic event to trigger.
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl
new file mode 100644
index 0000000..eb5e9cc
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 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.hardware.vibrator;
+
+import android.hardware.vibrator.IVibrator;
+import android.hardware.vibrator.IVibratorCallback;
+
+@VintfStability
+interface IVibratorManager {
+ /**
+ * Whether prepare/trigger synced are supported.
+ */
+ const int CAP_SYNC = 1 << 0;
+ /**
+ * Whether IVibrator 'on' can be used with 'prepareSynced' function.
+ */
+ const int CAP_PREPARE_ON = 1 << 1;
+ /**
+ * Whether IVibrator 'perform' can be used with 'prepareSynced' function.
+ */
+ const int CAP_PREPARE_PERFORM = 1 << 2;
+ /**
+ * Whether IVibrator 'compose' can be used with 'prepareSynced' function.
+ */
+ const int CAP_PREPARE_COMPOSE = 1 << 3;
+ /**
+ * Whether IVibrator 'on' can be triggered with other functions in sync with 'triggerSynced'.
+ */
+ const int CAP_MIXED_TRIGGER_ON = 1 << 4;
+ /**
+ * Whether IVibrator 'perform' can be triggered with other functions in sync with 'triggerSynced'.
+ */
+ const int CAP_MIXED_TRIGGER_PERFORM = 1 << 5;
+ /**
+ * Whether IVibrator 'compose' can be triggered with other functions in sync with 'triggerSynced'.
+ */
+ const int CAP_MIXED_TRIGGER_COMPOSE = 1 << 6;
+ /**
+ * Whether on w/ IVibratorCallback can be used w/ 'trigerSynced' function.
+ */
+ const int CAP_TRIGGER_CALLBACK = 1 << 7;
+
+ /**
+ * Determine capabilities of the vibrator manager HAL (CAP_* mask)
+ */
+ int getCapabilities();
+
+ /**
+ * List the id of available vibrators. This result should be static and not change.
+ */
+ int[] getVibratorIds();
+
+ /**
+ * Return an available vibrator identified with given id.
+ */
+ IVibrator getVibrator(in int vibratorId);
+
+ /**
+ * Start preparation for a synced vibration
+ *
+ * This function must only be called after the previous synced vibration was triggered or
+ * canceled (through cancelSynced()).
+ *
+ * Doing this operation while any of the specified vibrators is already on is undefined behavior.
+ * Clients should explicitly call off in each vibrator.
+ *
+ * @param vibratorIds ids of the vibrators to play vibrations in sync.
+ */
+ void prepareSynced(in int[] vibratorIds);
+
+ /**
+ * Trigger a prepared synced vibration
+ *
+ * Trigger a previously-started preparation for synced vibration, if any.
+ * A callback is only expected to be supported when getCapabilities CAP_TRIGGER_CALLBACK
+ * is specified.
+ *
+ * @param callback A callback used to inform Frameworks of state change, if supported.
+ */
+ void triggerSynced(in IVibratorCallback callback);
+
+ /**
+ * Cancel preparation of synced vibration
+ *
+ * Cancel a previously-started preparation for synced vibration, if any.
+ */
+ void cancelSynced();
+}
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 9e6d9cf..f9d45bb 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -4,10 +4,13 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.vibrator-ndk_platform",
+ "android.hardware.vibrator-unstable-ndk_platform",
],
export_include_dirs: ["include"],
- srcs: ["Vibrator.cpp"],
+ srcs: [
+ "Vibrator.cpp",
+ "VibratorManager.cpp",
+ ],
visibility: [
":__subpackages__",
"//hardware/interfaces/tests/extension/vibrator:__subpackages__",
@@ -23,7 +26,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.vibrator-ndk_platform",
+ "android.hardware.vibrator-unstable-ndk_platform",
],
static_libs: [
"libvibratorexampleimpl",
diff --git a/vibrator/aidl/default/VibratorManager.cpp b/vibrator/aidl/default/VibratorManager.cpp
new file mode 100644
index 0000000..7cf9e6a
--- /dev/null
+++ b/vibrator/aidl/default/VibratorManager.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "vibrator-impl/VibratorManager.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+static constexpr int32_t kDefaultVibratorId = 1;
+
+ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t* _aidl_return) {
+ LOG(INFO) << "Vibrator manager reporting capabilities";
+ *_aidl_return =
+ IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
+ IVibratorManager::CAP_PREPARE_PERFORM | IVibratorManager::CAP_PREPARE_COMPOSE |
+ IVibratorManager::CAP_MIXED_TRIGGER_ON | IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
+ IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE | IVibratorManager::CAP_TRIGGER_CALLBACK;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector<int32_t>* _aidl_return) {
+ LOG(INFO) << "Vibrator manager getting vibrator ids";
+ *_aidl_return = {kDefaultVibratorId};
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibratorManager::getVibrator(int32_t vibratorId,
+ std::shared_ptr<IVibrator>* _aidl_return) {
+ LOG(INFO) << "Vibrator manager getting vibrator " << vibratorId;
+ if (vibratorId == kDefaultVibratorId) {
+ *_aidl_return = mDefaultVibrator;
+ return ndk::ScopedAStatus::ok();
+ } else {
+ *_aidl_return = nullptr;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+}
+
+ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector<int32_t>& vibratorIds) {
+ LOG(INFO) << "Vibrator Manager prepare synced";
+ if (vibratorIds.size() == 1 && vibratorIds[0] == kDefaultVibratorId) {
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+}
+
+ndk::ScopedAStatus VibratorManager::triggerSynced(
+ const std::shared_ptr<IVibratorCallback>& callback) {
+ LOG(INFO) << "Vibrator Manager trigger synced";
+ std::thread([=] {
+ if (callback != nullptr) {
+ LOG(INFO) << "Notifying perform complete";
+ callback->onComplete();
+ }
+ }).detach();
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibratorManager::cancelSynced() {
+ LOG(INFO) << "Vibrator Manager cancel synced";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
new file mode 100644
index 0000000..319eb05
--- /dev/null
+++ b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibratorManager.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class VibratorManager : public BnVibratorManager {
+ public:
+ VibratorManager(std::shared_ptr<IVibrator> vibrator) : mDefaultVibrator(std::move(vibrator)){};
+ ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getVibratorIds(std::vector<int32_t>* _aidl_return) override;
+ ndk::ScopedAStatus getVibrator(int32_t vibratorId,
+ std::shared_ptr<IVibrator>* _aidl_return) override;
+ ndk::ScopedAStatus prepareSynced(const std::vector<int32_t>& vibratorIds) override;
+ ndk::ScopedAStatus triggerSynced(const std::shared_ptr<IVibratorCallback>& callback) override;
+ ndk::ScopedAStatus cancelSynced() override;
+
+ private:
+ std::shared_ptr<IVibrator> mDefaultVibrator;
+};
+
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index ebb0905..bd834d2 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -15,19 +15,29 @@
*/
#include "vibrator-impl/Vibrator.h"
+#include "vibrator-impl/VibratorManager.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::android::hardware::vibrator::Vibrator;
+using aidl::android::hardware::vibrator::VibratorManager;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
- std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>();
- const std::string instance = std::string() + Vibrator::descriptor + "/default";
- binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str());
+ // make a default vibrator service
+ auto vib = ndk::SharedRefBase::make<Vibrator>();
+ const std::string vibName = std::string() + Vibrator::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(vib->asBinder().get(), vibName.c_str());
+ CHECK(status == STATUS_OK);
+
+ // make the vibrator manager service with a different vibrator
+ auto managedVib = ndk::SharedRefBase::make<Vibrator>();
+ auto vibManager = ndk::SharedRefBase::make<VibratorManager>(std::move(managedVib));
+ const std::string vibManagerName = std::string() + VibratorManager::descriptor + "/default";
+ status = AServiceManager_addService(vibManager->asBinder().get(), vibManagerName.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
diff --git a/vibrator/aidl/default/vibrator-default.xml b/vibrator/aidl/default/vibrator-default.xml
index 49b11ec..9f9cd40 100644
--- a/vibrator/aidl/default/vibrator-default.xml
+++ b/vibrator/aidl/default/vibrator-default.xml
@@ -3,4 +3,8 @@
<name>android.hardware.vibrator</name>
<fqname>IVibrator/default</fqname>
</hal>
+ <hal format="aidl">
+ <name>android.hardware.vibrator</name>
+ <fqname>IVibratorManager/default</fqname>
+ </hal>
</manifest>
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index 28cb4d9..d06b50e 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -9,7 +9,26 @@
"libbinder",
],
static_libs: [
- "android.hardware.vibrator-cpp",
+ "android.hardware.vibrator-unstable-cpp",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
+cc_test {
+ name: "VtsHalVibratorManagerTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalVibratorManagerTargetTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.vibrator-unstable-cpp",
],
test_suites: [
"general-tests",
diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
new file mode 100644
index 0000000..9789188
--- /dev/null
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <android/hardware/vibrator/IVibratorManager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <cmath>
+#include <future>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::IVibratorManager;
+using std::chrono::high_resolution_clock;
+
+const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
+ android::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
+ android::enum_range<EffectStrength>().end()};
+const std::vector<CompositePrimitive> kPrimitives{android::enum_range<CompositePrimitive>().begin(),
+ android::enum_range<CompositePrimitive>().end()};
+
+class CompletionCallback : public BnVibratorCallback {
+ public:
+ CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
+ Status onComplete() override {
+ mCallback();
+ return Status::ok();
+ }
+
+ private:
+ std::function<void()> mCallback;
+};
+
+class VibratorAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ manager = android::waitForDeclaredService<IVibratorManager>(String16(GetParam().c_str()));
+ ASSERT_NE(manager, nullptr);
+ ASSERT_TRUE(manager->getCapabilities(&capabilities).isOk());
+ EXPECT_TRUE(manager->getVibratorIds(&vibratorIds).isOk());
+ }
+
+ sp<IVibratorManager> manager;
+ int32_t capabilities;
+ std::vector<int32_t> vibratorIds;
+};
+
+TEST_P(VibratorAidl, ValidateExistingVibrators) {
+ sp<IVibrator> vibrator;
+ for (auto& id : vibratorIds) {
+ EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ ASSERT_NE(vibrator, nullptr);
+ }
+}
+
+TEST_P(VibratorAidl, GetVibratorWithInvalidId) {
+ int32_t invalidId = *max_element(vibratorIds.begin(), vibratorIds.end()) + 1;
+ sp<IVibrator> vibrator;
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ manager->getVibrator(invalidId, &vibrator).exceptionCode());
+ ASSERT_EQ(vibrator, nullptr);
+}
+
+TEST_P(VibratorAidl, ValidatePrepareSyncedExistingVibrators) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (vibratorIds.empty()) return;
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+}
+
+TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ std::vector<int32_t> emptyIds;
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, manager->prepareSynced(emptyIds).exceptionCode());
+}
+
+TEST_P(VibratorAidl, PrepareSyncedNotSupported) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) {
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+ manager->prepareSynced(vibratorIds).exceptionCode());
+ }
+}
+
+TEST_P(VibratorAidl, PrepareOnNotSupported) {
+ if (vibratorIds.empty()) return;
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
+ uint32_t durationMs = 250;
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ sp<IVibrator> vibrator;
+ for (auto& id : vibratorIds) {
+ EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ ASSERT_NE(vibrator, nullptr);
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+ vibrator->on(durationMs, nullptr).exceptionCode());
+ }
+ EXPECT_TRUE(manager->cancelSynced().isOk());
+ }
+}
+
+TEST_P(VibratorAidl, PreparePerformNotSupported) {
+ if (vibratorIds.empty()) return;
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ sp<IVibrator> vibrator;
+ for (auto& id : vibratorIds) {
+ EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ ASSERT_NE(vibrator, nullptr);
+ int32_t lengthMs = 0;
+ Status status = vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs);
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+ }
+ EXPECT_TRUE(manager->cancelSynced().isOk());
+ }
+}
+
+TEST_P(VibratorAidl, PrepareComposeNotSupported) {
+ if (vibratorIds.empty()) return;
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
+ std::vector<CompositeEffect> composite;
+ CompositeEffect effect;
+ effect.delayMs = 10;
+ effect.primitive = kPrimitives[0];
+ effect.scale = 1.0f;
+ composite.emplace_back(effect);
+
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ sp<IVibrator> vibrator;
+ for (auto& id : vibratorIds) {
+ EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ ASSERT_NE(vibrator, nullptr);
+ Status status = vibrator->compose(composite, nullptr);
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+ }
+ EXPECT_TRUE(manager->cancelSynced().isOk());
+ }
+}
+
+TEST_P(VibratorAidl, TriggerWithCallback) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) return;
+ if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) return;
+ if (vibratorIds.empty()) return;
+
+ std::promise<void> completionPromise;
+ std::future<void> completionFuture{completionPromise.get_future()};
+ sp<CompletionCallback> callback =
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ uint32_t durationMs = 250;
+ std::chrono::milliseconds timeout{durationMs * 2};
+
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ sp<IVibrator> vibrator;
+ for (auto& id : vibratorIds) {
+ EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ ASSERT_NE(vibrator, nullptr);
+ EXPECT_TRUE(vibrator->on(durationMs, nullptr).isOk());
+ }
+
+ EXPECT_TRUE(manager->triggerSynced(callback).isOk());
+ EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+ EXPECT_TRUE(manager->cancelSynced().isOk());
+}
+
+TEST_P(VibratorAidl, TriggerSyncNotSupported) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) {
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+ manager->triggerSynced(nullptr).exceptionCode());
+ }
+}
+
+TEST_P(VibratorAidl, TriggerCallbackNotSupported) {
+ if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+ if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) {
+ sp<CompletionCallback> callback = new CompletionCallback([] {});
+ EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+ manager->triggerSynced(callback).exceptionCode());
+ }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl);
+INSTANTIATE_TEST_SUITE_P(
+ Vibrator, VibratorAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IVibratorManager::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 888a403..adbb0cf 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -18,6 +18,7 @@
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
+#include <android/hardware/vibrator/IVibratorManager.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -34,6 +35,7 @@
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::IVibratorManager;
using std::chrono::high_resolution_clock;
const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
@@ -77,10 +79,28 @@
std::function<void()> mCallback;
};
-class VibratorAidl : public testing::TestWithParam<std::string> {
+class VibratorAidl : public testing::TestWithParam<std::tuple<int32_t, int32_t>> {
public:
virtual void SetUp() override {
- vibrator = android::waitForDeclaredService<IVibrator>(String16(GetParam().c_str()));
+ int32_t managerIdx = std::get<0>(GetParam());
+ int32_t vibratorId = std::get<1>(GetParam());
+ auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
+
+ if (managerIdx < 0) {
+ // Testing a unmanaged vibrator, using vibratorId as index from registered HALs
+ auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
+ ASSERT_LT(vibratorId, vibratorAidlNames.size());
+ auto vibratorName = String16(vibratorAidlNames[vibratorId].c_str());
+ vibrator = android::waitForDeclaredService<IVibrator>(vibratorName);
+ } else {
+ // Testing a managed vibrator, using vibratorId to retrieve it from the manager
+ ASSERT_LT(managerIdx, managerAidlNames.size());
+ auto managerName = String16(managerAidlNames[managerIdx].c_str());
+ auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
+ auto vibratorResult = vibratorManager->getVibrator(vibratorId, &vibrator);
+ ASSERT_TRUE(vibratorResult.isOk());
+ }
+
ASSERT_NE(vibrator, nullptr);
ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
}
@@ -96,7 +116,7 @@
}
TEST_P(VibratorAidl, OnWithCallback) {
- if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+ if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) return;
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
@@ -110,7 +130,7 @@
}
TEST_P(VibratorAidl, OnCallbackNotSupported) {
- if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) {
+ if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) {
sp<CompletionCallback> callback = new CompletionCallback([] {});
EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->on(250, callback).exceptionCode());
}
@@ -518,10 +538,41 @@
}
}
+std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
+ std::vector<std::tuple<int32_t, int32_t>> tuples;
+ auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
+ std::vector<int32_t> vibratorIds;
+
+ for (int i = 0; i < managerAidlNames.size(); i++) {
+ auto managerName = String16(managerAidlNames[i].c_str());
+ auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
+ if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
+ for (auto& vibratorId : vibratorIds) {
+ tuples.push_back(std::make_tuple(i, vibratorId));
+ }
+ }
+ }
+
+ auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
+ for (int i = 0; i < vibratorAidlNames.size(); i++) {
+ tuples.push_back(std::make_tuple(-1, i));
+ }
+
+ return tuples;
+}
+
+std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType>& info) {
+ const auto& [managerIdx, vibratorId] = info.param;
+ if (managerIdx < 0) {
+ return std::string("TOP_LEVEL_VIBRATOR_") + std::to_string(vibratorId);
+ }
+ return std::string("MANAGER_") + std::to_string(managerIdx) + "_VIBRATOR_ID_" +
+ std::to_string(vibratorId);
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl);
-INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl,
- testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
- android::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(GenerateVibratorMapping()),
+ PrintGeneratedTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp
index 5a62a3a..e2c38ce 100644
--- a/wifi/1.5/Android.bp
+++ b/wifi/1.5/Android.bp
@@ -7,6 +7,7 @@
"types.hal",
"IWifi.hal",
"IWifiChip.hal",
+ "IWifiApIface.hal",
"IWifiNanIface.hal",
"IWifiNanIfaceEventCallback.hal",
"IWifiStaIface.hal",
diff --git a/wifi/1.5/IWifiApIface.hal b/wifi/1.5/IWifiApIface.hal
new file mode 100644
index 0000000..9625a6b
--- /dev/null
+++ b/wifi/1.5/IWifiApIface.hal
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 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.hardware.wifi@1.5;
+
+import @1.4::IWifiApIface;
+import @1.0::MacAddress;
+import @1.0::WifiStatus;
+
+/**
+ * Represents a network interface in AP mode.
+ *
+ * This can be obtained through @1.0::IWifiChip.getApIface() and casting
+ * IWifiApIface up to 1.5.
+ */
+interface IWifiApIface extends @1.4::IWifiApIface {
+ /**
+ * Reset all of the AP interfaces MAC address to the factory MAC address.
+ *
+ * @return status WifiStatus of the operation
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ resetToFactoryMacAddress() generates (WifiStatus status);
+};
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index dcc9279..e9caa3d 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -17,6 +17,8 @@
package android.hardware.wifi@1.5;
import @1.0::WifiStatus;
+import @1.0::IfaceType;
+import @1.5::IWifiApIface;
import @1.0::IWifiIface;
import @1.3::IWifiChip;
import @1.4::IWifiChip;
@@ -127,4 +129,85 @@
* |WifiStatusCode.ERROR_INVALID_ARGS|
*/
setMultiStaUseCase(MultiStaUseCase useCase) generates (WifiStatus status);
+
+ /**
+ * Create bridged IWifiApIface.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |ERROR_NOT_AVAILABLE|) if we've already reached the maximum
+ * allowed (specified in |ChipIfaceCombination|) number of ifaces of the AP
+ * type.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ * @return iface HIDL interface object representing the iface if
+ * successful, null otherwise.
+ */
+ createBridgedApIface() generates (WifiStatus status, IWifiApIface iface);
+
+ /**
+ * Removes one of the instance on the AP Iface with the provided ifaceName and
+ * ifaceInstanceName.
+ *
+ * Use the API: removeApIface with brIfaceName in the V1_0::WifiChip.hal to remove bridge Iface.
+ *
+ * @param brIfaceName Name of the bridged AP iface.
+ * @param ifaceInstanceName Name of the instance. The empty instance is
+ * invalid.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ removeIfaceInstanceFromBridgedApIface(string brIfaceName, string ifaceInstanceName)
+ generates (WifiStatus status);
+
+ /**
+ * Representation of a Wi-Fi channel for Wi-Fi coex channel avoidance.
+ */
+ struct CoexUnsafeChannel {
+ /* The band of the channel */
+ WifiBand band;
+ /* The channel number */
+ uint32_t channel;
+ /** The power cap will be a maximum power value in dbm that is allowed to be transmitted by
+ the chip on this channel. A value of PowerCapConstant.NO_POWER_CAP means no limitation
+ on transmitted power is needed by the chip for this channel.
+ */
+ int32_t powerCapDbm;
+ };
+
+ enum PowerCapConstant : int32_t {
+ NO_POWER_CAP = 0x7FFFFFFF,
+ };
+
+ /**
+ * Invoked to indicate that the provided |CoexUnsafeChannels| should be avoided with the
+ * specified restrictions.
+ *
+ * Channel avoidance is a suggestion and should be done on a best-effort approach. If a provided
+ * channel is used, then the specified power cap should be applied.
+ *
+ * In addition, hard restrictions on the Wifi modes may be indicated by |IfaceType| bits
+ * (STA, AP, P2P, NAN, etc) in the |restrictions| bitfield. If a hard restriction is provided,
+ * then the channels should be completely avoided for the provided Wifi modes instead of by
+ * best-effort.
+ *
+ * @param unsafeChannels List of |CoexUnsafeChannels| to avoid.
+ * @param restrictions Bitset of |IfaceType| values indicating Wifi modes to completely avoid.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ */
+ setCoexUnsafeChannels(
+ vec<CoexUnsafeChannel> unsafeChannels, bitfield<IfaceType> restrictions)
+ generates (WifiStatus status);
};
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index 83d06fe..8e2e647 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -2800,6 +2800,47 @@
}
CHECK(false);
}
+
+bool convertHidlCoexUnsafeChannelToLegacy(
+ const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+ legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
+ if (!legacy_unsafe_channel) {
+ return false;
+ }
+ *legacy_unsafe_channel = {};
+ switch (hidl_unsafe_channel.band) {
+ case WifiBand::BAND_24GHZ:
+ legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
+ break;
+ case WifiBand::BAND_5GHZ:
+ legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
+ break;
+ default:
+ return false;
+ };
+ legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
+ legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
+ return true;
+}
+
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+ const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+ std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
+ if (!legacy_unsafe_channels) {
+ return false;
+ }
+ *legacy_unsafe_channels = {};
+ for (const auto& hidl_unsafe_channel : hidl_unsafe_channels) {
+ legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
+ if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(
+ hidl_unsafe_channel, &legacy_unsafe_channel)) {
+ return false;
+ }
+ legacy_unsafe_channels->push_back(legacy_unsafe_channel);
+ }
+ return true;
+}
+
} // namespace hidl_struct_util
} // namespace implementation
} // namespace V1_5
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index 49d8a12..feb47ef 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -71,6 +71,12 @@
IfaceType hidl_interface_type);
legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
IWifiChip::MultiStaUseCase use_case);
+bool convertHidlCoexUnsafeChannelToLegacy(
+ const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+ legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+ const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+ std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
// STA iface conversion methods.
bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.5/default/service.cpp b/wifi/1.5/default/service.cpp
index 8539a37..23e2b47 100644
--- a/wifi/1.5/default/service.cpp
+++ b/wifi/1.5/default/service.cpp
@@ -17,6 +17,7 @@
#include <android-base/logging.h>
#include <hidl/HidlLazyUtils.h>
#include <hidl/HidlTransportSupport.h>
+#include <signal.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
@@ -45,6 +46,7 @@
#endif
int main(int /*argc*/, char** argv) {
+ signal(SIGPIPE, SIG_IGN);
android::base::InitLogging(
argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Wifi Hal is booting up...";
diff --git a/wifi/1.5/default/wifi_ap_iface.cpp b/wifi/1.5/default/wifi_ap_iface.cpp
index 04e382a..d98aa45 100644
--- a/wifi/1.5/default/wifi_ap_iface.cpp
+++ b/wifi/1.5/default/wifi_ap_iface.cpp
@@ -29,10 +29,11 @@
using hidl_return_util::validateAndCall;
WifiApIface::WifiApIface(
- const std::string& ifname,
+ const std::string& ifname, const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
+ instances_(instances),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
is_valid_(true) {}
@@ -81,6 +82,14 @@
getFactoryMacAddress_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getFactoryMacAddressInternal,
+ hidl_status_cb,
+ instances_.size() > 0 ? instances_[0] : ifname_);
+}
+
+Return<void> WifiApIface::resetToFactoryMacAddress(
+ resetToFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::resetToFactoryMacAddressInternal,
hidl_status_cb);
}
@@ -94,8 +103,8 @@
WifiStatus WifiApIface::setCountryCodeInternal(
const std::array<int8_t, 2>& code) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setCountryCode(ifname_, code);
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
+ instances_.size() > 0 ? instances_[0] : ifname_, code);
return createWifiStatusFromLegacyError(legacy_status);
}
@@ -107,13 +116,30 @@
std::vector<uint32_t> valid_frequencies;
std::tie(legacy_status, valid_frequencies) =
legacy_hal_.lock()->getValidFrequenciesForBand(
- ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+ instances_.size() > 0 ? instances_[0] : ifname_,
+ hidl_struct_util::convertHidlWifiBandToLegacy(band));
return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
}
WifiStatus WifiApIface::setMacAddressInternal(
const std::array<uint8_t, 6>& mac) {
- bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+ bool status;
+ // Support random MAC up to 2 interfaces
+ if (instances_.size() == 2) {
+ int rbyte = 1;
+ for (auto const& intf : instances_) {
+ std::array<uint8_t, 6> rmac = mac;
+ // reverse the bits to avoid clision
+ rmac[rbyte] = 0xff - rmac[rbyte];
+ status = iface_util_.lock()->setMacAddress(intf, rmac);
+ if (!status) {
+ LOG(INFO) << "Failed to set random mac address on " << intf;
+ }
+ rbyte++;
+ }
+ } else {
+ status = iface_util_.lock()->setMacAddress(ifname_, mac);
+ }
if (!status) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
@@ -121,15 +147,37 @@
}
std::pair<WifiStatus, std::array<uint8_t, 6>>
-WifiApIface::getFactoryMacAddressInternal() {
+WifiApIface::getFactoryMacAddressInternal(const std::string& ifaceName) {
std::array<uint8_t, 6> mac =
- iface_util_.lock()->getFactoryMacAddress(ifname_);
+ iface_util_.lock()->getFactoryMacAddress(ifaceName);
if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
mac[4] == 0 && mac[5] == 0) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
}
return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
}
+
+WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
+ std::pair<WifiStatus, std::array<uint8_t, 6>> getMacResult;
+ if (instances_.size() == 2) {
+ for (auto const& intf : instances_) {
+ getMacResult = getFactoryMacAddressInternal(intf);
+ LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
+ if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+ !iface_util_.lock()->setMacAddress(intf, getMacResult.second)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ }
+ } else {
+ getMacResult = getFactoryMacAddressInternal(ifname_);
+ LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
+ if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+ !iface_util_.lock()->setMacAddress(ifname_, getMacResult.second)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
} // namespace implementation
} // namespace V1_5
} // namespace wifi
diff --git a/wifi/1.5/default/wifi_ap_iface.h b/wifi/1.5/default/wifi_ap_iface.h
index 48b444a..02fb2d8 100644
--- a/wifi/1.5/default/wifi_ap_iface.h
+++ b/wifi/1.5/default/wifi_ap_iface.h
@@ -18,7 +18,7 @@
#define WIFI_AP_IFACE_H_
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifiApIface.h>
+#include <android/hardware/wifi/1.5/IWifiApIface.h>
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
@@ -33,9 +33,10 @@
/**
* HIDL interface object used to control a AP Iface instance.
*/
-class WifiApIface : public V1_4::IWifiApIface {
+class WifiApIface : public V1_5::IWifiApIface {
public:
WifiApIface(const std::string& ifname,
+ const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
@@ -55,6 +56,8 @@
setMacAddress_cb hidl_status_cb) override;
Return<void> getFactoryMacAddress(
getFactoryMacAddress_cb hidl_status_cb) override;
+ Return<void> resetToFactoryMacAddress(
+ resetToFactoryMacAddress_cb hidl_status_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -64,10 +67,12 @@
std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
getValidFrequenciesForBandInternal(V1_0::WifiBand band);
WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
- std::pair<WifiStatus, std::array<uint8_t, 6>>
- getFactoryMacAddressInternal();
+ std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal(
+ const std::string& ifaceName);
+ WifiStatus resetToFactoryMacAddressInternal();
std::string ifname_;
+ std::vector<std::string> instances_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
bool is_valid_;
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 1c238c8..1b0353b 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
+#include <net/if.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
@@ -44,6 +45,7 @@
constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
constexpr unsigned kMaxWlanIfaces = 5;
+constexpr char kApBridgeIfacePrefix[] = "ap_br_";
template <typename Iface>
void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
@@ -101,24 +103,36 @@
return "wlan" + std::to_string(idx);
}
-// Returns the dedicated iface name if one is defined.
-std::string getApIfaceName() {
+// Returns the dedicated iface name if defined.
+// Returns two ifaces in bridged mode.
+std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
+ std::vector<std::string> ifnames;
std::array<char, PROPERTY_VALUE_MAX> buffer;
+ buffer.fill(0);
if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) ==
0) {
- return {};
+ return ifnames;
}
- return buffer.data();
+ ifnames.push_back(buffer.data());
+ if (is_bridged) {
+ buffer.fill(0);
+ if (property_get("ro.vendor.wifi.sap.concurrent.interface",
+ buffer.data(), nullptr) == 0) {
+ return ifnames;
+ }
+ ifnames.push_back(buffer.data());
+ }
+ return ifnames;
}
-std::string getP2pIfaceName() {
+std::string getPredefinedP2pIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.direct.interface", buffer.data(), "p2p0");
return buffer.data();
}
// Returns the dedicated iface name if one is defined.
-std::string getNanIfaceName() {
+std::string getPredefinedNanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
return {};
@@ -434,6 +448,13 @@
&WifiChip::createApIfaceInternal, hidl_status_cb);
}
+Return<void> WifiChip::createBridgedApIface(
+ createBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createBridgedApIfaceInternal,
+ hidl_status_cb);
+}
+
Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getApIfaceNamesInternal, hidl_status_cb);
@@ -453,6 +474,15 @@
ifname);
}
+Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& ifname, const hidl_string& ifInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal,
+ hidl_status_cb, ifname, ifInstanceName);
+}
+
Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createNanIfaceInternal, hidl_status_cb);
@@ -692,7 +722,17 @@
hidl_status_cb, use_case);
}
+Return<void> WifiChip::setCoexUnsafeChannels(
+ const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
+ hidl_bitfield<IfaceType> restrictions,
+ setCoexUnsafeChannels_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setCoexUnsafeChannelsInternal,
+ hidl_status_cb, unsafeChannels, restrictions);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
+ invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
invalidateAndClearAll(nan_ifaces_);
invalidateAndClearAll(p2p_ifaces_);
@@ -861,21 +901,28 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
}
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = allocateApIfaceName();
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->createVirtualInterface(
- ifname,
- hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
+ legacy_hal::wifi_error legacy_status;
+ legacy_status = legacy_hal_.lock()->createVirtualInterface(
+ apVirtIf,
+ hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to add interface: " << ifname << " "
+ LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
<< legacyErrorToString(legacy_status);
- return {createWifiStatusFromLegacyError(legacy_status), {}};
+ return createWifiStatusFromLegacyError(legacy_status);
}
- sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+sp<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+ std::vector<std::string> ap_instances;
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ifname) {
+ ap_instances = it.second;
+ }
+ }
+ sp<WifiApIface> iface =
+ new WifiApIface(ifname, ap_instances, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
@@ -883,6 +930,61 @@
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return iface;
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
+WifiChip::createApIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateApIfaceName();
+ WifiStatus status = createVirtualApInterface(ifname);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return {status, {}};
+ }
+ sp<WifiApIface> iface = newWifiApIface(ifname);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
+WifiChip::createBridgedApIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+ if (ap_instances.size() < 2) {
+ LOG(ERROR) << "Fail to allocate two instances";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+ for (int i = 0; i < 2; i++) {
+ WifiStatus status = createVirtualApInterface(ap_instances[i]);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ if (i != 0) { // The failure happened when creating second virtual
+ // iface.
+ legacy_hal_.lock()->deleteVirtualInterface(
+ ap_instances.front()); // Remove the first virtual iface.
+ }
+ return {status, {}};
+ }
+ }
+ br_ifaces_ap_instances_[br_ifname] = ap_instances;
+ if (!iface_util_.lock()->createBridge(br_ifname)) {
+ LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
+ invalidateAndClearBridgedAp(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ for (auto const& instance : ap_instances) {
+ // Bind ap instance interface to AP bridge
+ if (!iface_util_.lock()->addIfaceToBridge(br_ifname, instance)) {
+ LOG(ERROR) << "Failed add if to Bridge - if_name="
+ << instance.c_str();
+ invalidateAndClearBridgedAp(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ }
+ sp<WifiApIface> iface = newWifiApIface(br_ifname);
return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
}
@@ -894,7 +996,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
}
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::getApIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(ap_ifaces_, ifname);
if (!iface.get()) {
@@ -913,12 +1015,8 @@
// nan/rtt objects over AP iface. But, there is no harm to do it
// here and not make that assumption all over the place.
invalidateAndRemoveDependencies(ifname);
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->deleteVirtualInterface(ifname);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to remove interface: " << ifname << " "
- << legacyErrorToString(legacy_status);
- }
+ // Clear the bridge interface and the iface instance.
+ invalidateAndClearBridgedAp(ifname);
invalidateAndClear(ap_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -929,13 +1027,49 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
+WifiStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
+ const std::string& ifname, const std::string& ifInstanceName) {
+ legacy_hal::wifi_error legacy_status;
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get() || !ifInstanceName.empty()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Requires to remove one of the instance in bridge mode
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ifname) {
+ for (auto const& iface : it.second) {
+ if (iface == ifInstanceName) {
+ if (!iface_util_.lock()->removeIfaceFromBridge(it.first,
+ iface)) {
+ LOG(ERROR) << "Failed to remove interface: " << iface
+ << " from " << ifname << ", error: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatus(
+ WifiStatusCode::ERROR_NOT_AVAILABLE);
+ }
+ legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to del interface: " << iface
+ << " " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ }
+ }
+ break;
+ }
+ }
+ br_ifaces_ap_instances_.erase(ifInstanceName);
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>>
WifiChip::createNanIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
bool is_dedicated_iface = true;
- std::string ifname = getNanIfaceName();
+ std::string ifname = getPredefinedNanIfaceName();
if (ifname.empty() || !iface_util_.lock()->ifNameToIndex(ifname)) {
// Use the first shared STA iface (wlan0) if a dedicated aware iface is
// not defined.
@@ -988,7 +1122,7 @@
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
- std::string ifname = getP2pIfaceName();
+ std::string ifname = getPredefinedP2pIfaceName();
sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
p2p_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -1322,6 +1456,18 @@
return createWifiStatusFromLegacyError(legacy_status);
}
+WifiStatus WifiChip::setCoexUnsafeChannelsInternal(
+ std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions) {
+ std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
+ if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(
+ unsafe_channels, &legacy_unsafe_channels)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ auto legacy_status = legacy_hal_.lock()->setCoexUnsafeChannels(
+ legacy_unsafe_channels, restrictions);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
WifiStatus WifiChip::handleChipConfiguration(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id) {
@@ -1607,7 +1753,7 @@
// ChipIfaceCombination.
// b) Check if the requested iface type can be added to the current mode.
bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
- // Check if we can support atleast 1 iface of type.
+ // Check if we can support at least 1 iface of type.
std::map<IfaceType, size_t> req_iface_combo;
req_iface_combo[requested_type] = 1;
return canCurrentModeSupportIfaceCombo(req_iface_combo);
@@ -1623,17 +1769,17 @@
}
bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
- // Check if we can support atleast 1 STA & 1 AP concurrently.
+ // Check if we can support at least 1 STA & 1 AP concurrently.
std::map<IfaceType, size_t> req_iface_combo;
req_iface_combo[IfaceType::AP] = 1;
req_iface_combo[IfaceType::STA] = 1;
return canCurrentModeSupportIfaceCombo(req_iface_combo);
}
-bool WifiChip::isDualApAllowedInCurrentMode() {
- // Check if we can support atleast 1 STA & 1 AP concurrently.
+bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
+ // Check if we can support at least 2 STA concurrently.
std::map<IfaceType, size_t> req_iface_combo;
- req_iface_combo[IfaceType::AP] = 2;
+ req_iface_combo[IfaceType::STA] = 2;
return canCurrentModeSupportIfaceCombo(req_iface_combo);
}
@@ -1653,6 +1799,7 @@
uint32_t start_idx) {
for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
const auto ifname = getWlanIfaceNameWithType(type, idx);
+ if (findUsingNameFromBridgedApInstances(ifname)) continue;
if (findUsingName(ap_ifaces_, ifname)) continue;
if (findUsingName(sta_ifaces_, ifname)) continue;
return ifname;
@@ -1662,19 +1809,46 @@
return {};
}
+uint32_t WifiChip::startIdxOfApIface() {
+ if (isDualStaConcurrencyAllowedInCurrentMode()) {
+ // When the HAL support dual STAs, AP should start with idx 2.
+ return 2;
+ } else if (isStaApConcurrencyAllowedInCurrentMode()) {
+ // When the HAL support STA + AP but it doesn't support dual STAs.
+ // AP should start with idx 1.
+ return 1;
+ }
+ // No concurrency support.
+ return 0;
+}
+
// AP iface names start with idx 1 for modes supporting
// concurrent STA and not dual AP, else start with idx 0.
std::string WifiChip::allocateApIfaceName() {
// Check if we have a dedicated iface for AP.
- std::string ifname = getApIfaceName();
- if (!ifname.empty()) {
- return ifname;
+ std::vector<std::string> ifnames = getPredefinedApIfaceNames(false);
+ if (!ifnames.empty()) {
+ return ifnames[0];
}
- return allocateApOrStaIfaceName(IfaceType::AP,
- (isStaApConcurrencyAllowedInCurrentMode() &&
- !isDualApAllowedInCurrentMode())
- ? 1
- : 0);
+ return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
+}
+
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
+ // Check if we have a dedicated iface for AP.
+ std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+ if (instances.size() == 2) {
+ return instances;
+ } else {
+ int num_ifaces_need_to_allocate = 2 - instances.size();
+ for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
+ std::string instance_name =
+ allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
+ if (!instance_name.empty()) {
+ instances.push_back(instance_name);
+ }
+ }
+ }
+ return instances;
}
// STA iface names start with idx 0.
@@ -1727,6 +1901,48 @@
return getWlanIfaceName(idx);
}
+void WifiChip::invalidateAndClearBridgedApAll() {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ for (auto const& iface : it.second) {
+ iface_util_.lock()->removeIfaceFromBridge(it.first, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_.lock()->deleteBridge(it.first);
+ }
+ br_ifaces_ap_instances_.clear();
+}
+
+void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
+ if (br_name.empty()) return;
+ // delete managed interfaces
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == br_name) {
+ for (auto const& iface : it.second) {
+ iface_util_.lock()->removeIfaceFromBridge(br_name, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_.lock()->deleteBridge(br_name);
+ br_ifaces_ap_instances_.erase(br_name);
+ break;
+ }
+ }
+ return;
+}
+
+bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == name) {
+ return true;
+ }
+ for (auto const& iface : it.second) {
+ if (iface == name) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
} // namespace implementation
} // namespace V1_5
} // namespace wifi
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index 693d480..95c122d 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -94,11 +94,16 @@
Return<void> requestFirmwareDebugDump(
requestFirmwareDebugDump_cb hidl_status_cb) override;
Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+ Return<void> createBridgedApIface(
+ createBridgedApIface_cb hidl_status_cb) override;
Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
Return<void> getApIface(const hidl_string& ifname,
getApIface_cb hidl_status_cb) override;
Return<void> removeApIface(const hidl_string& ifname,
removeApIface_cb hidl_status_cb) override;
+ Return<void> removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
Return<void> getNanIface(const hidl_string& ifname,
@@ -169,6 +174,10 @@
Return<void> setMultiStaUseCase(
MultiStaUseCase use_case,
setMultiStaUseCase_cb hidl_status_cb) override;
+ Return<void> setCoexUnsafeChannels(
+ const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
+ hidl_bitfield<IfaceType> restrictions,
+ setCoexUnsafeChannels_cb hidl_status_cb) override;
private:
void invalidateAndRemoveAllIfaces();
@@ -192,11 +201,17 @@
requestDriverDebugDumpInternal();
std::pair<WifiStatus, std::vector<uint8_t>>
requestFirmwareDebugDumpInternal();
- std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
+ sp<WifiApIface> newWifiApIface(std::string& ifname);
+ WifiStatus createVirtualApInterface(const std::string& apVirtIf);
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createApIfaceInternal();
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
+ createBridgedApIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>> getApIfaceInternal(
const std::string& ifname);
WifiStatus removeApIfaceInternal(const std::string& ifname);
+ WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(
+ const std::string& brIfaceName, const std::string& ifInstanceName);
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(
@@ -241,6 +256,8 @@
const sp<V1_4::IWifiChipEventCallback>& event_callback);
WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
+ WifiStatus setCoexUnsafeChannelsInternal(
+ std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions);
WifiStatus handleChipConfiguration(
std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
@@ -265,13 +282,18 @@
bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
bool isValidModeId(ChipModeId mode_id);
bool isStaApConcurrencyAllowedInCurrentMode();
- bool isDualApAllowedInCurrentMode();
+ bool isDualStaConcurrencyAllowedInCurrentMode();
+ uint32_t startIdxOfApIface();
std::string getFirstActiveWlanIfaceName();
std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
std::string allocateApIfaceName();
+ std::vector<std::string> allocateBridgedApInstanceNames();
std::string allocateStaIfaceName();
bool writeRingbufferFilesInternal();
std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
+ void invalidateAndClearBridgedApAll();
+ void invalidateAndClearBridgedAp(const std::string& br_name);
+ bool findUsingNameFromBridgedApInstances(const std::string& name);
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
@@ -296,7 +318,7 @@
event_cb_handler_;
const std::function<void(const std::string&)> subsystemCallbackHandler_;
-
+ std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
DISALLOW_COPY_AND_ASSIGN(WifiChip);
};
diff --git a/wifi/1.5/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
index 9f91bd7..124ba32 100644
--- a/wifi/1.5/default/wifi_feature_flags.cpp
+++ b/wifi/1.5/default/wifi_feature_flags.cpp
@@ -14,6 +14,11 @@
* limitations under the License.
*/
+#include <string>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
#include "wifi_feature_flags.h"
namespace android {
@@ -131,7 +136,7 @@
#define AP IfaceType::AP
#define P2P IfaceType::P2P
#define NAN IfaceType::NAN
-static const std::vector<IWifiChip::ChipMode> kChipModes{
+static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
{kMainModeId,
ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
@@ -146,6 +151,50 @@
{WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
#endif
};
+
+constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
+ "persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
+// List of pre-defined interface combinations that can be enabled at runtime via
+// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
+// corresponding index value.
+static const std::vector<
+ std::pair<std::string, std::vector<IWifiChip::ChipMode>>>
+ kDebugChipModes{
+ // Legacy combination - No STA/AP concurrencies.
+ // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
+ {"No STA/AP Concurrency",
+ {{kMainModeId,
+ ChipIfaceCombination::make_vec(
+ {{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + AP concurrency
+ // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+ {"STA + AP Concurrency",
+ {{kMainModeId,
+ ChipIfaceCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + STA concurrency
+ // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
+ {"Dual STA Concurrency",
+ {{kMainModeId,
+ ChipIfaceCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+ // AP + AP + STA concurrency
+ // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
+ {"Dual AP Concurrency",
+ {{kMainModeId,
+ ChipIfaceCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + STA concurrency and AP + AP + STA concurrency
+ // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
+ {"Dual STA & Dual AP Concurrency",
+ {{kMainModeId,
+ ChipIfaceCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}}};
+
#undef STA
#undef AP
#undef P2P
@@ -161,9 +210,31 @@
WifiFeatureFlags::WifiFeatureFlags() {}
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty,
+ buffer.data(), nullptr);
+ // Debug propety not set, use the device preset interface combination.
+ if (res <= 0) return kChipModesPrimary;
+
+ // Debug propety set, use one of the debug preset interface combination.
+ unsigned long idx = std::stoul(buffer.data());
+ if (idx >= kDebugChipModes.size()) {
+ LOG(ERROR) << "Invalid index set in property: "
+ << kDebugPresetInterfaceCombinationIdxProperty;
+ return kChipModesPrimary;
+ }
+ std::string name;
+ std::vector<IWifiChip::ChipMode> chip_modes;
+ std::tie(name, chip_modes) = kDebugChipModes[idx];
+ LOG(INFO) << "Using debug chip mode: <" << name << "> set via property: "
+ << kDebugPresetInterfaceCombinationIdxProperty;
+ return chip_modes;
+}
+
std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(
bool is_primary) {
- return (is_primary) ? kChipModes : kChipModesSecondary;
+ return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
}
} // namespace feature_flags
diff --git a/wifi/1.5/default/wifi_feature_flags.h b/wifi/1.5/default/wifi_feature_flags.h
index cb68b8c..7d561fc 100644
--- a/wifi/1.5/default/wifi_feature_flags.h
+++ b/wifi/1.5/default/wifi_feature_flags.h
@@ -44,6 +44,9 @@
virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(
bool is_primary);
+
+ private:
+ std::vector<V1_0::IWifiChip::ChipMode> getChipModesForPrimary();
};
} // namespace feature_flags
diff --git a/wifi/1.5/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
index 07175e4..2a0aef8 100644
--- a/wifi/1.5/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -127,6 +127,36 @@
unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
return if_nametoindex(iface_name.c_str());
}
+
+bool WifiIfaceUtil::createBridge(const std::string& br_name) {
+ if (!iface_tool_.lock()->createBridge(br_name)) {
+ return false;
+ }
+
+ if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
+ LOG(ERROR) << "bridge SetUpState(true) failed.";
+ }
+ return true;
+}
+
+bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
+ if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
+ LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
+ }
+
+ return iface_tool_.lock()->deleteBridge(br_name);
+}
+
+bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name,
+ const std::string& if_name) {
+ return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
+}
+
+bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name,
+ const std::string& if_name) {
+ return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
+}
+
} // namespace iface_util
} // namespace implementation
} // namespace V1_5
diff --git a/wifi/1.5/default/wifi_iface_util.h b/wifi/1.5/default/wifi_iface_util.h
index 7b812fa..296d182 100644
--- a/wifi/1.5/default/wifi_iface_util.h
+++ b/wifi/1.5/default/wifi_iface_util.h
@@ -59,6 +59,16 @@
virtual bool setUpState(const std::string& iface_name, bool request_up);
virtual unsigned ifNameToIndex(const std::string& iface_name);
+ virtual bool createBridge(const std::string& br_name);
+
+ virtual bool deleteBridge(const std::string& br_name);
+
+ virtual bool addIfaceToBridge(const std::string& br_name,
+ const std::string& if_name);
+
+ virtual bool removeIfaceFromBridge(const std::string& br_name,
+ const std::string& if_name);
+
private:
std::array<uint8_t, 6> createRandomMacAddress();
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 76e718b..773dd9b 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -1521,6 +1521,14 @@
use_case);
}
+wifi_error WifiLegacyHal::setCoexUnsafeChannels(
+ std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+ uint32_t restrictions) {
+ return global_func_table_.wifi_set_coex_unsafe_channels(
+ global_handle_, unsafe_channels.size(), unsafe_channels.data(),
+ restrictions);
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 555c540..6266cf6 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -386,6 +386,11 @@
virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
+ // Coex functions.
+ virtual wifi_error setCoexUnsafeChannels(
+ std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+ uint32_t restrictions);
+
private:
// Retrieve interface handles for all the available interfaces.
wifi_error retrieveIfaceHandles();
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 71d2ddf..b6c908b 100644
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -149,6 +149,7 @@
populateStubFor(&hal_fn->wifi_get_chip_feature_set);
populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
+ populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
return true;
}
diff --git a/wifi/1.5/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp
index f3dcfc5..82bfcf1 100644
--- a/wifi/1.5/default/wifi_sta_iface.cpp
+++ b/wifi/1.5/default/wifi_sta_iface.cpp
@@ -648,6 +648,10 @@
WifiStaIface::getFactoryMacAddressInternal() {
std::array<uint8_t, 6> mac =
iface_util_.lock()->getFactoryMacAddress(ifname_);
+ if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
+ mac[4] == 0 && mac[5] == 0) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+ }
return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
}
diff --git a/wifi/1.5/vts/functional/Android.bp b/wifi/1.5/vts/functional/Android.bp
index eb595c9..2d8b412 100644
--- a/wifi/1.5/vts/functional/Android.bp
+++ b/wifi/1.5/vts/functional/Android.bp
@@ -60,3 +60,26 @@
"vts",
],
}
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+ name: "VtsHalWifiApV1_5TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "wifi_chip_hidl_ap_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/wifi/1.5/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.5/vts/functional/wifi_chip_hidl_ap_test.cpp
new file mode 100644
index 0000000..395d317
--- /dev/null
+++ b/wifi/1.5/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.5/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifiApIface.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiChipEventCallback;
+using ::android::hardware::wifi::V1_5::IWifiApIface;
+using ::android::hardware::wifi::V1_5::IWifiChip;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on SoftAP support.
+ */
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+ ASSERT_NE(nullptr, wifi_chip_.get());
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ protected:
+ // Helper function to configure the Chip in one of the supported modes.
+ // Most of the non-mode-configuration-related methods require chip
+ // to be first configured.
+ ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+ ChipModeId mode_id;
+ EXPECT_EQ(expectSuccess,
+ configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+ return mode_id;
+ }
+
+ WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
+ configureChipForIfaceType(IfaceType::AP, true);
+ const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
+ *ap_iface = IWifiApIface::castFrom(status_and_iface.second);
+ return status_and_iface.first.code;
+ }
+
+ WifiStatusCode createBridgedApIface(sp<IWifiApIface>* ap_iface) {
+ configureChipForIfaceType(IfaceType::AP, true);
+ const auto& status_and_iface =
+ HIDL_INVOKE(wifi_chip_, createBridgedApIface);
+ *ap_iface = status_and_iface.second;
+ return status_and_iface.first.code;
+ }
+
+ sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+// TODO: b/173999527. Add test for bridged API.
+
+/*
+ * resetToFactoryMacAddress
+ */
+TEST_P(WifiChipHidlTest, resetToFactoryMacAddressTest) {
+ sp<IWifiApIface> wifi_ap_iface;
+ const auto& status_code = createApIface(&wifi_ap_iface);
+ if (status_code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status_code);
+ }
+ const auto& status = HIDL_INVOKE(wifi_ap_iface, resetToFactoryMacAddress);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_5::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 1c3141e..b9c7b30 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -22,7 +22,7 @@
#include <VtsCoreUtil.h>
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
#include "supplicant_hidl_call_util.h"
#include "supplicant_hidl_test_utils.h"
@@ -74,7 +74,7 @@
sta_iface_ = getSupplicantStaIface(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
- v1_1 = ::android::hardware::wifi::supplicant::V1_1::
+ v1_4 = ::android::hardware::wifi::supplicant::V1_4::
ISupplicantStaIface::castFrom(sta_iface_);
memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
@@ -82,7 +82,7 @@
protected:
bool isP2pOn_ = false;
- sp<::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface> v1_1 =
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface> v1_4 =
nullptr;
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
@@ -181,8 +181,9 @@
* RegisterCallback
*/
TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback) {
+ // This API is deprecated from v1.4 HAL.
SupplicantStatusCode expectedCode =
- (nullptr != v1_1) ? SupplicantStatusCode::FAILURE_UNKNOWN
+ (nullptr != v1_4) ? SupplicantStatusCode::FAILURE_UNKNOWN
: SupplicantStatusCode::SUCCESS;
sta_iface_->registerCallback(new IfaceCallback(),
[&](const SupplicantStatus& status) {
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index ee80628..d9ae3e0 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -48,6 +48,8 @@
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi.supplicant@1.4",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"libgmock",
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
index 8d7ea54..a8e72b8 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -75,7 +75,7 @@
* AddP2pInterface
*/
TEST_P(SupplicantHidlTest, AddP2pInterface) {
- if (isP2pOn_) return;
+ if (!isP2pOn_) return;
ISupplicant::IfaceInfo iface_info;
iface_info.name = getP2pIfaceName();
iface_info.type = IfaceType::P2P;
@@ -115,7 +115,7 @@
* RemoveP2pInterface
*/
TEST_P(SupplicantHidlTest, RemoveP2pInterface) {
- if (isP2pOn_) return;
+ if (!isP2pOn_) return;
ISupplicant::IfaceInfo iface_info;
iface_info.name = getP2pIfaceName();
iface_info.type = IfaceType::P2P;
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 418def2..7e6e3e4 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -20,7 +20,7 @@
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -47,14 +47,14 @@
sta_iface_ = getSupplicantStaIface_1_1(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
- v1_2 = ::android::hardware::wifi::supplicant::V1_2::
+ v1_4 = ::android::hardware::wifi::supplicant::V1_4::
ISupplicantStaIface::castFrom(sta_iface_);
}
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
- sp<::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface> v1_2 =
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface> v1_4 =
nullptr;
};
@@ -139,8 +139,9 @@
* RegisterCallback_1_1
*/
TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
+ // This API is deprecated from v1.4 HAL.
SupplicantStatusCode expectedCode =
- (nullptr != v1_2) ? SupplicantStatusCode::FAILURE_UNKNOWN
+ (nullptr != v1_4) ? SupplicantStatusCode::FAILURE_UNKNOWN
: SupplicantStatusCode::SUCCESS;
sta_iface_->registerCallback_1_1(new IfaceCallback(),
[&](const SupplicantStatus& status) {
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index c23585a..2592a2b 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -51,6 +51,7 @@
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant@1.2",
"android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi.supplicant@1.4",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"libgmock",
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 7799390..7f81206 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/wifi/supplicant/1.2/types.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.3/types.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/ServiceManagement.h>
@@ -63,6 +64,8 @@
v1_3 = ::android::hardware::wifi::supplicant::V1_3::
ISupplicantStaIface::castFrom(sta_iface_);
+ v1_4 = ::android::hardware::wifi::supplicant::V1_4::
+ ISupplicantStaIface::castFrom(sta_iface_);
}
enum DppCallbackType {
@@ -106,6 +109,7 @@
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3;
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface> v1_4;
bool isDppSupported() {
uint32_t keyMgmtMask = 0;
@@ -266,8 +270,9 @@
* RegisterCallback_1_2
*/
TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) {
+ // This API is deprecated from v1.4 HAL.
SupplicantStatusCode expectedCode =
- (nullptr != v1_3) ? SupplicantStatusCode::FAILURE_UNKNOWN
+ (nullptr != v1_4) ? SupplicantStatusCode::FAILURE_UNKNOWN
: SupplicantStatusCode::SUCCESS;
sta_iface_->registerCallback_1_2(new IfaceCallback(),
[&](const SupplicantStatus& status) {
diff --git a/wifi/supplicant/1.4/ISupplicantStaIface.hal b/wifi/supplicant/1.4/ISupplicantStaIface.hal
index f9e4c9b..7441ba5 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIface.hal
@@ -71,8 +71,7 @@
* |SupplicantStatusCode.FAILURE_UNKNOWN|,
* |SupplicantStatusCode.FAILURE_IFACE_INVALID|
*/
- initiateVenueUrlAnqpQuery(MacAddress macAddress)
- generates (SupplicantStatus status);
+ initiateVenueUrlAnqpQuery(MacAddress macAddress) generates (SupplicantStatus status);
/**
* Get wpa driver capabilities.
@@ -84,4 +83,55 @@
*/
getWpaDriverCapabilities_1_4() generates (SupplicantStatus status,
bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
+
+ /**
+ * Generates DPP bootstrap information: Bootstrap ID, DPP URI and listen
+ * channel for responder mode.
+ *
+ * @param MacAddress MAC address of the interface for the DPP operation.
+ * @param deviceInfo Device specific information.
+ * As per DPP Specification V1.0 section 5.2,
+ * allowed Range of ASCII characters in deviceInfo - %x20-7E
+ * semicolon is not allowed.
+ * @param DppCurve Elliptic curve cryptography type used to generate DPP
+ * public/private key pair.
+ * @return status of operation and bootstrap info.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ generateDppBootstrapInfoForResponder(MacAddress macAddress, string deviceInfo, DppCurve curve)
+ generates (SupplicantStatus status, DppResponderBootstrapInfo bootstrapInfo);
+
+ /**
+ * Start DPP in Enrollee-Responder mode.
+ * Framework must first call |generateDppBootstrapInfoForResponder| to generate
+ * the bootstrapping information: Bootstrap ID, DPP URI and the listen channel.
+ * Then call this API with derived listen channel to start listening for
+ * authentication request from Peer initiator.
+ *
+ * @param listenChannel DPP listen channel.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ startDppEnrolleeResponder(uint32_t listenChannel) generates (SupplicantStatus status);
+
+ /**
+ * Stop DPP Responder operation - Remove the bootstrap code and stop listening.
+ *
+ * @param ownBootstrapId Local device's URI ID obtained through
+ * |generateDppBootstrapInfoForResponder| call.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ stopDppResponder(uint32_t ownBootstrapId) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
index 852696d..efcebda 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
@@ -40,8 +40,12 @@
/**
* Baseline information as defined in HAL 1.0.
*/
- @1.0::ISupplicantStaIfaceCallback.AnqpData V1_0; /* Container for v1.0 of this struct */
- vec<uint8_t> venueUrl; /* Venue URL ANQP-element */
+ @1.0::ISupplicantStaIfaceCallback.AnqpData V1_0;
+
+ /*
+ * Container for v1.0 of this struct
+ */
+ vec<uint8_t> venueUrl;
};
/**
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
index 80beedf..6bed5ab 100644
--- a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
@@ -17,7 +17,7 @@
package android.hardware.wifi.supplicant@1.4;
import @1.3::ISupplicantStaNetwork;
-import @1.4::ISupplicantStaNetworkCallback;
+import ISupplicantStaNetworkCallback;
/**
* Interface exposed by the supplicant for each station mode network
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
index 18af8fe..aec61c4 100644
--- a/wifi/supplicant/1.4/types.hal
+++ b/wifi/supplicant/1.4/types.hal
@@ -18,6 +18,7 @@
import @1.0::SupplicantStatusCode;
import @1.3::ConnectionCapabilities;
+import @1.3::DppFailureCode;
import @1.3::WpaDriverCapabilitiesMask;
/**
@@ -40,6 +41,29 @@
};
/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+enum DppFailureCode : @1.3::DppFailureCode {
+ /**
+ * Failure to generate a DPP URI.
+ */
+ URI_GENERATION,
+};
+
+/**
+ * DppCurve: Elliptic curve cryptography type used to generate DPP
+ * public/private key pair.
+ */
+enum DppCurve : uint32_t {
+ PRIME256V1,
+ SECP384R1,
+ SECP521R1,
+ BRAINPOOLP256R1,
+ BRAINPOOLP384R1,
+ BRAINPOOLP512R1,
+};
+
+/**
* Connection Capabilities supported by current network and device
*/
struct ConnectionCapabilities {
@@ -47,6 +71,7 @@
* Baseline information as defined in HAL 1.3.
*/
@1.3::ConnectionCapabilities V1_3;
+
/**
* detailed network mode for legacy network
*/
@@ -64,13 +89,14 @@
* Generic structure to return the status of any supplicant operation.
*/
struct SupplicantStatus {
- SupplicantStatusCode code;
- /**
- * A vendor specific error message to provide more information beyond the
- * status code.
- * This will be used for debbuging purposes only.
- */
- string debugMessage;
+ SupplicantStatusCode code;
+
+ /**
+ * A vendor specific error message to provide more information beyond the
+ * status code.
+ * This will be used for debbuging purposes only.
+ */
+ string debugMessage;
};
/**
@@ -78,7 +104,27 @@
*/
enum WpaDriverCapabilitiesMask : @1.3::WpaDriverCapabilitiesMask {
/**
- *
*/
SAE_PK = 1 << 2,
};
+
+/**
+ * DPP bootstrap info generated for responder mode operation
+ */
+struct DppResponderBootstrapInfo {
+ /**
+ * Generated bootstrap identifier
+ */
+ uint32_t bootstrapId;
+
+ /**
+ * The Wi-Fi channel that the DPP responder is listening on.
+ */
+ uint32_t listenChannel;
+
+ /**
+ * Bootstrapping URI per DPP specification, "section 5.2 Bootstrapping
+ * information", may contain listen channel, MAC address, public key, or other information.
+ */
+ string uri;
+};
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
index c0b5a70..ccd469d 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -19,6 +19,7 @@
#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.2/types.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.3/types.h>
#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
@@ -45,7 +46,10 @@
using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_4::DppCurve;
+using ::android::hardware::wifi::supplicant::V1_4::DppResponderBootstrapInfo;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIfaceCallback;
@@ -74,6 +78,24 @@
sp<ISupplicantStaIface> sta_iface_;
// MAC address to use for various tests.
std::array<uint8_t, 6> mac_addr_;
+
+ bool isDppSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
+ // DPP not supported
+ return false;
+ }
+ return true;
+ }
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -255,6 +277,48 @@
});
}
+/*
+ * StartDppEnrolleeResponder
+ */
+TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeResponder) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string deviceInfo = "DPP_Responder_Mode_VTS_Test";
+ uint32_t bootstrap_id = 0;
+ uint32_t listen_channel = 0;
+ uint8_t mac_address[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+ // Generate DPP bootstrap information
+ sta_iface_->generateDppBootstrapInfoForResponder(
+ mac_address, deviceInfo, DppCurve::PRIME256V1,
+ [&](const SupplicantStatusV1_4& status,
+ DppResponderBootstrapInfo bootstrapInfo) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ EXPECT_NE(-1, bootstrapInfo.bootstrapId);
+ EXPECT_NE(0, bootstrapInfo.bootstrapId);
+ bootstrap_id = bootstrapInfo.bootstrapId;
+ listen_channel = bootstrapInfo.listenChannel;
+ EXPECT_NE(0, bootstrapInfo.listenChannel);
+ });
+
+ // Start DPP as Enrollee-Responder.
+ sta_iface_->startDppEnrolleeResponder(
+ listen_channel, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ });
+
+ // Stop DPP Enrollee-Responder mode, ie remove the URI and stop listen.
+ sta_iface_->stopDppResponder(
+ bootstrap_id, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ });
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceHidlTest);
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaIfaceHidlTest,