[automerger skipped] Add audio V7 to compatility matrix. am: 00df90125c am: 8dc380a8a0 am: ed35d0c471 am: 687a5061e1 -s ours
am skip reason: Change-Id I98a0798cc08761e8aa6a9ca920c67aa6f8155de4 with SHA-1 6446c735a6 is in history
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1476656
Change-Id: I0283b1e0427a84552603897a4cd0092e51a87895
diff --git a/audio/7.0/IDevice.hal b/audio/7.0/IDevice.hal
index 7082d6b..e30e545 100644
--- a/audio/7.0/IDevice.hal
+++ b/audio/7.0/IDevice.hal
@@ -117,7 +117,7 @@
AudioIoHandle ioHandle,
DeviceAddress device,
AudioConfig config,
- bitfield<AudioOutputFlag> flags,
+ vec<AudioInOutFlag> flags,
SourceMetadata sourceMetadata) generates (
Result retval,
IStreamOut outStream,
@@ -142,7 +142,7 @@
AudioIoHandle ioHandle,
DeviceAddress device,
AudioConfig config,
- bitfield<AudioInputFlag> flags,
+ vec<AudioInOutFlag> flags,
SinkMetadata sinkMetadata) generates (
Result retval,
IStreamIn inStream,
@@ -315,7 +315,6 @@
* INVALID_STATE if the device was already closed
* or there are streams currently opened.
*/
- @exit
close() generates (Result retval);
/**
diff --git a/audio/7.0/IStream.hal b/audio/7.0/IStream.hal
index dacd3fd..4fe8218 100644
--- a/audio/7.0/IStream.hal
+++ b/audio/7.0/IStream.hal
@@ -44,111 +44,42 @@
getBufferSize() generates (uint64_t bufferSize);
/**
- * Return the sampling rate in Hz.
+ * Return supported audio profiles for this particular stream. This method
+ * is normally called for streams opened on devices that use dynamic
+ * profiles, e.g. HDMI and USB interfaces. Please note that supported
+ * profiles of the stream may differ from the capabilities of the connected
+ * physical device.
*
- * @return sampleRateHz sample rate in Hz.
- */
- getSampleRate() generates (uint32_t sampleRateHz);
-
- /**
- * Return supported native sampling rates of the stream for a given format.
- * A supported native sample rate is a sample rate that can be efficiently
- * played by the hardware (typically without sample-rate conversions).
- *
- * This function is only called for dynamic profile. If called for
- * non-dynamic profile is should return NOT_SUPPORTED or the same list
- * as in audio_policy_configuration.xml.
- *
- * Calling this method is equivalent to getting
- * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL.
- *
- *
- * @param format audio format for which the sample rates are supported.
- * @return retval operation completion status.
- * Must be OK if the format is supported.
- * @return sampleRateHz supported sample rates.
- */
- getSupportedSampleRates(AudioFormat format)
- generates (Result retval, vec<uint32_t> sampleRates);
-
- /**
- * Sets the sampling rate of the stream. Calling this method is equivalent
- * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
- * Optional method. If implemented, only called on a stopped stream.
- *
- * @param sampleRateHz sample rate in Hz.
- * @return retval operation completion status.
- */
- setSampleRate(uint32_t sampleRateHz) generates (Result retval);
-
- /**
- * Return the channel mask of the stream.
- *
- * @return mask channel mask.
- */
- getChannelMask() generates (bitfield<AudioChannelMask> mask);
-
- /**
- * Return supported channel masks of the stream. Calling this method is
- * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
- * HAL.
- *
- * @param format audio format for which the channel masks are supported.
- * @return retval operation completion status.
- * Must be OK if the format is supported.
- * @return masks supported audio masks.
- */
- getSupportedChannelMasks(AudioFormat format)
- generates (Result retval, vec<bitfield<AudioChannelMask>> masks);
-
- /**
- * Sets the channel mask of the stream. Calling this method is equivalent to
- * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
- * Optional method
- *
- * @param format audio format.
- * @return retval operation completion status.
- */
- setChannelMask(bitfield<AudioChannelMask> mask) generates (Result retval);
-
- /**
- * Return the audio format of the stream.
- *
- * @return format audio format.
- */
- getFormat() generates (AudioFormat format);
-
- /**
- * Return supported audio formats of the stream. Calling this method is
- * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
- * HAL.
+ * For devices with fixed configurations, e.g. built-in audio devices, all
+ * the profiles are specified in the audio_policy_configuration.xml
+ * file. For such devices, this method must return the configuration from
+ * the config file, or NOT_SUPPORTED retval.
*
* @return retval operation completion status.
- * @return formats supported audio formats.
+ * @return formats supported audio profiles.
* Must be non empty if retval is OK.
*/
- getSupportedFormats() generates (Result retval, vec<AudioFormat> formats);
+ getSupportedProfiles()
+ generates (Result retval, vec<AudioProfile> profiles);
/**
- * Sets the audio format of the stream. Calling this method is equivalent to
- * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
- * Optional method
+ * Retrieves basic stream configuration: sample rate, audio format,
+ * channel mask.
*
- * @param format audio format.
+ * @return config basic stream configuration.
+ */
+ getAudioProperties() generates (AudioConfigBase config);
+
+ /**
+ * Sets stream parameters. Only sets parameters that are specified.
+ * See the description of AudioConfigBase for the details.
+ *
+ * Optional method. If implemented, only called on a stopped stream.
+ *
+ * @param config basic stream configuration.
* @return retval operation completion status.
*/
- setFormat(AudioFormat format) generates (Result retval);
-
- /**
- * Convenience method for retrieving several stream parameters in
- * one transaction.
- *
- * @return sampleRateHz sample rate in Hz.
- * @return mask channel mask.
- * @return format audio format.
- */
- getAudioProperties() generates (
- uint32_t sampleRateHz, bitfield<AudioChannelMask> mask, AudioFormat format);
+ setAudioProperties(AudioConfigBase config) generates (Result retval);
/**
* Applies audio effect to the stream.
@@ -312,6 +243,5 @@
* output stream interface.
* INVALID_STATE if the stream was already closed.
*/
- @exit
close() generates (Result retval);
};
diff --git a/audio/7.0/IStreamIn.hal b/audio/7.0/IStreamIn.hal
index 15e4363..0a3f24b 100644
--- a/audio/7.0/IStreamIn.hal
+++ b/audio/7.0/IStreamIn.hal
@@ -100,7 +100,7 @@
*
* The driver operates on a dedicated thread. The client must ensure that
* the thread is given an appropriate priority and assigned to correct
- * scheduler and cgroup. For this purpose, the method returns identifiers
+ * scheduler and cgroup. For this purpose, the method returns the identifier
* of the driver thread.
*
* @param frameSize the size of a single frame, in bytes.
@@ -115,7 +115,9 @@
* specified at the stream opening.
* @return statusMQ a message queue used for passing status from the driver
* using ReadStatus structures.
- * @return threadInfo identifiers of the driver's dedicated thread.
+ * @return threadId identifier of the driver's dedicated thread; the caller
+ * may adjust the thread priority to match the priority
+ * of the thread that provides audio data.
*/
prepareForReading(uint32_t frameSize, uint32_t framesCount)
generates (
@@ -123,7 +125,7 @@
fmq_sync<ReadParameters> commandMQ,
fmq_sync<uint8_t> dataMQ,
fmq_sync<ReadStatus> statusMQ,
- ThreadInfo threadInfo);
+ int32_t threadId);
/**
* Return the amount of input frames lost in the audio driver since the last
diff --git a/audio/7.0/IStreamOut.hal b/audio/7.0/IStreamOut.hal
index 208beb6..0951a9e 100644
--- a/audio/7.0/IStreamOut.hal
+++ b/audio/7.0/IStreamOut.hal
@@ -95,7 +95,7 @@
*
* The driver operates on a dedicated thread. The client must ensure that
* the thread is given an appropriate priority and assigned to correct
- * scheduler and cgroup. For this purpose, the method returns identifiers
+ * scheduler and cgroup. For this purpose, the method returns the identifier
* of the driver thread.
*
* @param frameSize the size of a single frame, in bytes.
@@ -109,7 +109,9 @@
* specified at the stream opening.
* @return statusMQ a message queue used for passing status from the driver
* using WriteStatus structures.
- * @return threadInfo identifiers of the driver's dedicated thread.
+ * @return threadId identifier of the driver's dedicated thread; the caller
+ * may adjust the thread priority to match the priority
+ * of the thread that provides audio data.
*/
prepareForWriting(uint32_t frameSize, uint32_t framesCount)
generates (
@@ -117,7 +119,7 @@
fmq_sync<WriteCommand> commandMQ,
fmq_sync<uint8_t> dataMQ,
fmq_sync<WriteStatus> statusMQ,
- ThreadInfo threadInfo);
+ int32_t threadId);
/**
* Return the number of audio frames written by the audio DSP to DAC since
@@ -269,8 +271,6 @@
* timestamp must correspond to N rather than N+M. The terms 'recent' and
* 'small' are not defined. They reflect the quality of the implementation.
*
- * Optional method
- *
* @return retval operation completion status.
* @return frames count of presented audio frames.
* @return timeStamp associated clock time.
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
index 98c5eac..453ed16 100644
--- a/audio/7.0/config/api/current.txt
+++ b/audio/7.0/config/api/current.txt
@@ -6,12 +6,92 @@
method 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;
+ }
+
+ 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;
+ }
+
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;
@@ -42,6 +122,8 @@
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;
@@ -130,9 +212,11 @@
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;
@@ -152,6 +236,42 @@
enum_constant public static final 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;
+ }
+
+ 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;
+ }
+
public class AudioPolicyConfiguration {
ctor public AudioPolicyConfiguration();
method public audio.policy.configuration.V7_0.GlobalConfiguration getGlobalConfiguration();
@@ -164,18 +284,60 @@
method public void setVersion(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;
+ }
+
+ 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;
+ }
+
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;
@@ -220,13 +382,6 @@
enum_constant public static final audio.policy.configuration.V7_0.EngineSuffix configurable;
}
- public enum GainMode {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
- enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_JOINT;
- enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_RAMP;
- }
-
public class Gains {
ctor public Gains();
method public java.util.List<audio.policy.configuration.V7_0.Gains.Gain> getGain();
@@ -234,23 +389,23 @@
public static class Gains.Gain {
ctor public Gains.Gain();
- method public String getChannel_mask();
+ 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 audio.policy.configuration.V7_0.GainMode getMode();
+ 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(String);
+ 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(audio.policy.configuration.V7_0.GainMode);
+ 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);
@@ -279,7 +434,7 @@
public static class MixPorts.MixPort {
ctor public MixPorts.MixPort();
- method public String getFlags();
+ 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();
@@ -287,7 +442,7 @@
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(String);
+ 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);
@@ -327,14 +482,14 @@
public class Profile {
ctor public Profile();
- method public String getChannelMasks();
+ method public java.util.List<audio.policy.configuration.V7_0.AudioChannelMask> getChannelMasks();
method public String getFormat();
method public String getName();
- method public String getSamplingRates();
- method public void setChannelMasks(String);
+ 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(String);
+ method public void setSamplingRates(java.util.List<java.math.BigInteger>);
}
public class Reference {
@@ -365,24 +520,6 @@
method public void setType(audio.policy.configuration.V7_0.MixType);
}
- public enum Stream {
- method public String getRawName();
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_ACCESSIBILITY;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_ALARM;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_ASSISTANT;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_DTMF;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_MUSIC;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_NOTIFICATION;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_PATCH;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_REROUTING;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_RING;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_SYSTEM;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_TTS;
- enum_constant public static final audio.policy.configuration.V7_0.Stream AUDIO_STREAM_VOICE_CALL;
- }
-
public class SurroundFormats {
ctor public SurroundFormats();
method public java.util.List<audio.policy.configuration.V7_0.SurroundFormats.Format> getFormat();
@@ -412,10 +549,10 @@
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.Stream getStream();
+ 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.Stream);
+ method public void setStream(audio.policy.configuration.V7_0.AudioStreamType);
}
public class Volumes {
diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd
index 19c6f70..6784828 100644
--- a/audio/7.0/config/audio_policy_configuration.xsd
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
<xs:schema version="2.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
@@ -27,7 +26,9 @@
<xs:simpleType name="halVersion">
<xs:annotation>
<xs:documentation xml:lang="en">
- Version of the interface the hal implements.
+ Version of the interface the hal implements. Note that this
+ relates to legacy HAL API versions since HIDL APIs are versioned
+ using other mechanisms.
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:decimal">
@@ -154,17 +155,46 @@
<xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
- <!-- TODO: separate values by space for better xsd validations. -->
- <xs:simpleType name="audioInOutFlags">
+ <xs:simpleType name="audioInOutFlag">
<xs:annotation>
<xs:documentation xml:lang="en">
- "|" separated list of audio_output_flags_t or audio_input_flags_t.
+ The flags indicate suggested stream attributes supported by the profile.
+ Use of AUDIO_{INPUT|OUTPUT}_FLAG_NONE in the XML file isn't required
+ as empty flag lists are allowed. However these constants are useful for
+ representing an empty enum value.
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
- <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_NONE" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DEEP_BUFFER" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_NON_BLOCKING" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_TTS" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT_PCM" />
+ <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_INPUT_FLAG_NONE" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_MMAP_NOIRQ" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_VOIP_TX" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
</xs:restriction>
</xs:simpleType>
+ <xs:simpleType name="audioInOutFlags">
+ <xs:list itemType="audioInOutFlag" />
+ </xs:simpleType>
<xs:simpleType name="role">
<xs:restriction base="xs:string">
<xs:enumeration value="sink"/>
@@ -212,9 +242,6 @@
</xs:element>
</xs:sequence>
</xs:complexType>
- <!-- Enum values of audio_device_t in audio.h
- TODO: generate from hidl to avoid manual sync.
- TODO: separate source and sink in the xml for better xsd validations. -->
<xs:simpleType name="audioDevice">
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_DEVICE_NONE"/>
@@ -229,8 +256,8 @@
<xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
- <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
@@ -249,17 +276,18 @@
<xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
<xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
- <!-- Due to the xml format, IN types can not be a separated from OUT types -->
<xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
<xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
<xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
<xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
<xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
- <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
<xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
<xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
<xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
<xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
@@ -281,6 +309,7 @@
<xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
<xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
<xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
<xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
<xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
</xs:restriction>
@@ -298,8 +327,6 @@
<xs:simpleType name="extendableAudioDevice">
<xs:union memberTypes="audioDevice vendorExtension"/>
</xs:simpleType>
- <!-- Enum values of audio_format_t in audio.h
- TODO: generate from hidl to avoid manual sync. -->
<xs:simpleType name="audioFormat">
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
@@ -322,22 +349,14 @@
<xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
- <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
<xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
<xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
<xs:enumeration value="AUDIO_FORMAT_OPUS"/>
<xs:enumeration value="AUDIO_FORMAT_AC3"/>
<xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
<xs:enumeration value="AUDIO_FORMAT_DTS"/>
<xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
<xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
@@ -357,17 +376,26 @@
<xs:enumeration value="AUDIO_FORMAT_ALAC"/>
<xs:enumeration value="AUDIO_FORMAT_APE"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
<xs:enumeration value="AUDIO_FORMAT_SBC"/>
<xs:enumeration value="AUDIO_FORMAT_APTX"/>
<xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
<xs:enumeration value="AUDIO_FORMAT_AC4"/>
<xs:enumeration value="AUDIO_FORMAT_LDAC"/>
- <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT"/>
<xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
<xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
<xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
- <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
<xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
@@ -377,14 +405,20 @@
<xs:enumeration value="AUDIO_FORMAT_LHDC"/>
<xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
<xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+ <xs:enumeration value="AUDIO_FORMAT_LC3"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="extendableAudioFormat">
<xs:union memberTypes="audioFormat vendorExtension"/>
</xs:simpleType>
- <!-- Enum values of audio::common::4_0::AudioUsage
- TODO: generate from HIDL to avoid manual sync. -->
<xs:simpleType name="audioUsage">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio usage specifies the intended use case for the sound being played.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
<xs:enumeration value="AUDIO_USAGE_MEDIA" />
@@ -399,49 +433,146 @@
<xs:enumeration value="AUDIO_USAGE_GAME" />
<xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
<xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+ <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+ <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+ <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="audioUsageList">
<xs:list itemType="audioUsage"/>
</xs:simpleType>
- <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
- <xs:simpleType name="samplingRates">
- <xs:restriction base="xs:string">
- <xs:pattern value="[0-9]+(,[0-9]+)*"/>
- </xs:restriction>
- </xs:simpleType>
- <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
- <xs:simpleType name="channelMask">
+ <xs:simpleType name="audioContentType">
<xs:annotation>
<xs:documentation xml:lang="en">
- Comma (",") separated list of channel flags
- from audio_channel_mask_t.
+ Audio content type expresses the general category of the content.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
- <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
</xs:restriction>
</xs:simpleType>
+ <xs:simpleType name="samplingRates">
+ <xs:list itemType="xs:nonNegativeInteger" />
+ </xs:simpleType>
+ <xs:simpleType name="audioChannelMask">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio channel mask specifies presence of particular channels.
+ There are two representations:
+ - representation position (traditional discrete channel specification,
+ e.g. "left", "right");
+ - indexed (this is similar to "tracks" in audio mixing, channels
+ are represented using numbers).
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CHANNEL_NONE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_SURROUND"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_PENTA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_6POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_CALL_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_3"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_5"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_7"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_8"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_9"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_10"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_11"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_12"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_13"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_14"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_15"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_16"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_17"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_18"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_19"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_20"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_21"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_22"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_23"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_24"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="channelMasks">
+ <xs:list itemType="audioChannelMask" />
+ </xs:simpleType>
<xs:complexType name="profile">
<xs:attribute name="name" type="xs:token" use="optional"/>
<xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
<xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
- <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+ <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
</xs:complexType>
- <xs:simpleType name="gainMode">
+ <xs:simpleType name="audioGainMode">
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
<xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
<xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
</xs:restriction>
</xs:simpleType>
+ <xs:simpleType name="audioGainModeMaskUnrestricted">
+ <xs:list itemType="audioGainMode" />
+ </xs:simpleType>
+ <xs:simpleType name='audioGainModeMask'>
+ <xs:restriction base='audioGainModeMaskUnrestricted'>
+ <xs:minLength value='1' />
+ </xs:restriction>
+ </xs:simpleType>
<xs:complexType name="gains">
<xs:sequence>
<xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:token" use="required"/>
- <xs:attribute name="mode" type="gainMode" use="required"/>
- <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+ <xs:attribute name="mode" type="audioGainModeMask" use="required"/>
+ <xs:attribute name="channel_mask" type="audioChannelMask" use="optional"/>
<xs:attribute name="minValueMB" type="xs:int" use="optional"/>
<xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
<xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
@@ -537,9 +668,14 @@
<xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
</xs:restriction>
</xs:simpleType>
- <!-- Enum values of audio_stream_type_t in audio-base.h
- TODO: generate from hidl to avoid manual sync. -->
- <xs:simpleType name="stream">
+ <xs:simpleType name="audioStreamType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio stream type describing the intended use case of a stream.
+ Please consult frameworks/base/media/java/android/media/AudioSystem.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
<xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
@@ -555,10 +691,35 @@
<xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
<xs:enumeration value="AUDIO_STREAM_REROUTING"/>
<xs:enumeration value="AUDIO_STREAM_PATCH"/>
+ <xs:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
</xs:restriction>
</xs:simpleType>
- <!-- Enum values of device_category from Volume.h.
- TODO: generate from hidl to avoid manual sync. -->
+ <xs:simpleType name="audioSource">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ An audio source defines the intended use case for the sound being recorded.
+ Please consult frameworks/base/media/java/android/media/MediaRecorder.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+ <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of device_category from Volume.h. -->
<xs:simpleType name="deviceCategory">
<xs:restriction base="xs:string">
<xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
@@ -591,7 +752,7 @@
<xs:sequence>
<xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
- <xs:attribute name="stream" type="stream"/>
+ <xs:attribute name="stream" type="audioStreamType"/>
<xs:attribute name="deviceCategory" type="deviceCategory"/>
<xs:attribute name="ref" type="xs:token" use="optional"/>
</xs:complexType>
diff --git a/audio/7.0/config/update_audio_policy_config.sh b/audio/7.0/config/update_audio_policy_config.sh
new file mode 100755
index 0000000..051a0df
--- /dev/null
+++ b/audio/7.0/config/update_audio_policy_config.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+
+# 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 script is used to update audio policy configuration files
+# to comply with the updated audio_policy_configuration.xsd from V7.0.
+#
+# The main difference is the separator used in lists for attributes.
+# Since the XML Schema Definition standard only allows space to be
+# used as a separator (see https://www.w3.org/TR/xmlschema11-2/#list-datatypes)
+# the previous versions used a regular expression to validate lists
+# in attribute values. E.g. the channel masks were validated using
+# the following regexp: [_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*
+# This has an obvious drawback of missing typos in the config file.
+#
+# The V7.0 has shifted to defining most of the frequently changed
+# types in the XSD schema only. This allows for verifying all the values
+# in lists, but in order to comply with XML Schema requirements
+# list elements must be separated by space.
+#
+# Since the APM config files typically use include directives,
+# the script must be pointed to the main APM config file and will
+# take care all the included files automatically.
+# If the included file is a shared version from 'frameworks/av',
+# instead of updating it the script checks if there is a newer
+# version with the corresponding name suffix (e.g.
+# 'a2dp_audio_policy_configuration_7_0.xml') and updates the include
+# path instead.
+
+set -euo pipefail
+
+if (echo "$@" | grep -qe -h); then
+ echo "This script will update Audio Policy Manager config file"
+ echo "to the format required by V7.0 XSD schema from a previous"
+ echo "version."
+ echo
+ echo "USAGE: $0 [APM_XML_FILE] [OLD_VERSION]"
+ echo " APM_XML_FILE specifies the path to audio_policy_configuration.xml"
+ echo " relative to Android repository root"
+ echo " OLD_VERSION specifies the version of schema currently used"
+ echo
+ echo "Example: $0 device/generic/goldfish/audio/policy/audio_policy_configuration.xml 6.0"
+ exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly SHARED_CONFIGS_DIRECTORY=frameworks/av/services/audiopolicy/config
+readonly OLD_VERSION=${2:-$(ls ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY} | grep -E '[0-9]+\.[0-9]+' |
+ sort -n | tail -n1)}
+readonly NEW_VERSION=7.0
+readonly NEW_VERSION_UNDERSCORE=7_0
+
+readonly SOURCE_CONFIG=${ANDROID_BUILD_TOP}/$1
+
+# First, validate the input using the schema of the current version
+
+echo Validating the source against the $OLD_VERSION schema
+xmllint --noout --xinclude \
+ --nofixup-base-uris --path "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY" \
+ --schema ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY}/${OLD_VERSION}/config/audio_policy_configuration.xsd \
+ ${SOURCE_CONFIG}
+if [ $? -ne 0 ]; then
+ echo
+ echo "Config file fails validation for the specified version $OLD_VERSION--unsafe to update"
+ exit 1
+fi
+
+# Find all the source files recursively
+
+SOURCE_FILES=${SOURCE_CONFIG}
+SHARED_FILES=
+findIncludes() {
+ local FILES_TO_CHECK=
+ for F in $1; do
+ local FOUND_INCLUDES=$(grep -Po '<xi:include href="\K[^"]+(?="\/>)' ${F})
+ for I in ${FOUND_INCLUDES}; do
+ SOURCE_FULL_PATH=$(dirname ${F})/${I}
+ SHARED_FULL_PATH=${ANDROID_BUILD_TOP}/${SHARED_CONFIGS_DIRECTORY}/${I}
+ if [ -f "$SOURCE_FULL_PATH" ]; then
+ # Device-specific file.
+ SOURCE_FILES+=$'\n'${SOURCE_FULL_PATH}
+ FILES_TO_CHECK+=$'\n'${SOURCE_FULL_PATH}
+ elif [ -f "$SHARED_FULL_PATH" ]; then
+ # Shared file from the frameworks repo.
+ SHARED_FILES+=$'\n'${I}
+ FILES_TO_CHECK+=$'\n'${SHARED_FULL_PATH}
+ else
+ echo
+ echo "Include file not found: $I"
+ exit 1
+ fi
+ done
+ done
+ if [ "$FILES_TO_CHECK" ]; then
+ findIncludes "$FILES_TO_CHECK"
+ fi
+}
+findIncludes ${SOURCE_FILES}
+
+echo "Will update $1 and included device-specific files in place."
+echo "Will update paths to shared included files."
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+updateFile() {
+ FILE=$1
+ ATTR=$2
+ SEPARATOR=$3
+ SRC_LINES=$(grep -nPo "$ATTR=\"[^\"]+\"" ${FILE} || true)
+ for S in $SRC_LINES; do
+ # Prepare instruction for 'sed' for in-place editing of specified line
+ R=$(echo ${S} | sed -e 's/^[0-9]\+:/\//' | sed -e "s/$SEPARATOR/ /g")
+ S=$(echo ${S} | sed -e 's/:/s\//')${R}/
+ echo ${S} | sed -i -f - ${FILE}
+ done
+}
+for F in $SOURCE_FILES; do
+ updateFile ${F} "channelMasks" ","
+ updateFile ${F} "samplingRates" ","
+ updateFile ${F} "flags" "|"
+done;
+
+updateIncludes() {
+ FILE=$1
+ for I in $SHARED_FILES; do
+ NEW_VERSION_I=${I%.*}_${NEW_VERSION_UNDERSCORE}.${I##*.}
+ if [ -e "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY/$NEW_VERSION_I" ]; then
+ echo "s/$I/$NEW_VERSION_I/g" | sed -i -f - ${FILE}
+ fi
+ done
+}
+for F in $SOURCE_FILES; do
+ updateIncludes ${F}
+done
+
+# Validate the results against the new schema
+
+echo Validating the result against the $NEW_VERSION schema
+xmllint --noout --xinclude \
+ --nofixup-base-uris --path "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY" \
+ --schema ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY}/${NEW_VERSION}/config/audio_policy_configuration.xsd \
+ ${SOURCE_CONFIG}
+if [ $? -ne 0 ]; then
+ echo
+ echo "Config file fails validation for the specified version $NEW_VERSION--please check the changes"
+ exit 1
+fi
+echo
+echo "Please check the diff and update path to APM shared files in the device makefile!"
diff --git a/audio/7.0/types.hal b/audio/7.0/types.hal
index b0b0843..4a9e289 100644
--- a/audio/7.0/types.hal
+++ b/audio/7.0/types.hal
@@ -355,3 +355,17 @@
*/
TimestretchFallbackMode fallbackMode;
};
+
+/**
+ * The audio flags serve two purposes:
+ *
+ * - when a stream is created they indicate its attributes;
+ *
+ * - when present in a profile descriptor listed for a particular audio
+ * hardware module, they indicate that a stream can be opened that
+ * supports the attributes indicated by the flags.
+ *
+ * See 'audioIoFlag' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioInOutFlag;
diff --git a/audio/README b/audio/README
deleted file mode 100644
index afafbe3..0000000
--- a/audio/README
+++ /dev/null
@@ -1,36 +0,0 @@
-Directory structure of the audio HIDL related code.
-
-Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
-based on an existing one.
-
-audio
-|-- 2.0 <== core 2.0 HIDL API. .hal can not be moved into the core directory
-| because that would change its namespace and include path
-|-- 4.0 <== Version 4.0 of the core API
-|
-|-- ...
-|
-|-- common <== code common to audio core and effect API
-| |-- 2.0 <== HIDL API of V2
-| |-- 4.0
-| |-- ...
-| `-- all-versions <== code common to all version of both core and effect API
-| |-- default <== implementation shared code between core and effect impl
-| |-- test <== utilities used by tests
-| `-- util <== utilities used by both implementation and tests
-|
-|-- core <== VTS and default implementation of the core API (not HIDL, see /audio/2.0))
-| `-- all-versions <== Code is version independent through #if and separate files
-| |-- default <== code that wraps the legacy API
-| `-- vts <== vts of core API
-| |-- 2.0 <== 2.0 specific tests and helpers
-| |-- 4.0
-| |-- ...
-|
-`-- effect <== idem for the effect API
- |-- 2.0
- |-- 4.0
- |-- ...
- `-- all-versions
- |-- default
- `-- vts
diff --git a/audio/README.md b/audio/README.md
new file mode 100644
index 0000000..b77b9ba
--- /dev/null
+++ b/audio/README.md
@@ -0,0 +1,53 @@
+# Audio HAL
+
+Directory structure of the audio HAL related code.
+
+Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
+based on an existing one.
+
+## Directory Structure
+
+* `2.0` -- version 2.0 of the core HIDL API. Note that `.hal` files
+ can not be moved into the `core` directory because that would change
+ its namespace and include path.
+ - `config` -- the XSD schema for the Audio Policy Manager
+ configuration file.
+* `4.0` -- version 4.0 of the core HIDL API.
+* ...
+* `common` -- common types for audio core and effect HIDL API.
+ - `2.0` -- version 2.0 of the common types HIDL API.
+ - `4.0` -- version 4.0.
+ - ...
+ - `7.0` -- version 7.0.
+ - `example` -- example implementation of the core and effect
+ V7.0 API. It represents a "fake" audio HAL that doesn't
+ actually communicate with hardware.
+ - `all-versions` -- code common to all version of both core and effect API.
+ - `default` -- shared code of the default implementation.
+ - `service` -- vendor HAL service for hosting the default
+ implementation.
+ - `test` -- utilities used by tests.
+ - `util` -- utilities used by both implementation and tests.
+* `core` -- VTS tests and the default implementation of the core API
+ (not HIDL API, it's in `audio/N.M`).
+ - `7.0` -- code specific to version V7.0 of the core HIDL API
+ - `all-versions` -- the code is common between all versions,
+ version-specific parts are enclosed into conditional directives
+ of preprocessor or reside in dedicated files.
+ - `default` -- code that wraps the legacy API (from
+ `hardware/libhardware`).
+ - `vts` VTS tests for the core HIDL API.
+* `effect` -- same for the effect HIDL API.
+ - `2.0`
+ - `config` -- the XSD schema for the Audio Effects configuration
+ file.
+ - `4.0`
+ - ...
+ - `all-versions`
+ - `default`
+ - `vts`
+* `policy` -- Configurable Audio Policy schemes.
+ - `1.0` -- note that versions of CAP are not linked to the versions
+ of audio HAL.
+ - `vts` -- VTS tests for validating actual configuration files.
+ - `xml` -- XSD schemas for CAP configuration files.
diff --git a/audio/common/7.0/Android.bp b/audio/common/7.0/Android.bp
index e24871c..1c016b4 100644
--- a/audio/common/7.0/Android.bp
+++ b/audio/common/7.0/Android.bp
@@ -16,9 +16,12 @@
cc_library {
name: "android.hardware.audio.common@7.0-enums",
vendor_available: true,
- generated_sources: ["audio_policy_configuration_V7_0"],
generated_headers: ["audio_policy_configuration_V7_0"],
+ generated_sources: ["audio_policy_configuration_V7_0"],
header_libs: ["libxsdc-utils"],
+ export_generated_headers: ["audio_policy_configuration_V7_0"],
+ export_header_lib_headers: ["libxsdc-utils"],
+ export_include_dirs: ["enums/include"],
shared_libs: [
"libbase",
"liblog",
diff --git a/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
new file mode 100644
index 0000000..cedcab3
--- /dev/null
+++ b/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
@@ -0,0 +1,215 @@
+/*
+ * 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 AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+#define AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+
+#include <sys/types.h>
+
+#include <audio_policy_configuration_V7_0.h>
+
+namespace audio::policy::configuration::V7_0 {
+
+static inline size_t getChannelCount(AudioChannelMask mask) {
+ switch (mask) {
+ case AudioChannelMask::AUDIO_CHANNEL_NONE:
+ return 0;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_MONO:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_1:
+ return 1;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO_HAPTIC_A:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_HAPTIC_AB:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_STEREO:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_CALL_MONO:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_2:
+ return 2;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_TRI:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_TRI_BACK:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_3:
+ return 3;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT0POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_3POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD_BACK:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD_SIDE:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_SURROUND:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_2POINT0POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_4:
+ return 4;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_3POINT0POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_PENTA:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_2POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_3POINT0POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_5:
+ return 5;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_3POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1_BACK:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1_SIDE:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_6:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_3POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_IN_5POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_6:
+ return 6;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_6POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_7:
+ return 7;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_8:
+ return 8;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_9:
+ return 9;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1POINT4:
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT2:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_10:
+ return 10;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_11:
+ return 11;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT4:
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_12:
+ return 12;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_13:
+ return 13;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_14:
+ return 14;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_15:
+ return 15;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_16:
+ return 16;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_17:
+ return 17;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_18:
+ return 18;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_19:
+ return 19;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_20:
+ return 20;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_21:
+ return 21;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_22:
+ return 22;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_23:
+ return 23;
+ case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_24:
+ return 24;
+ case AudioChannelMask::UNKNOWN:
+ return 0;
+ // No default to make sure all cases are covered.
+ }
+ // This is to avoid undefined behavior if 'mask' isn't a valid enum value.
+ return 0;
+}
+
+static inline ssize_t getChannelCount(const std::string& mask) {
+ return getChannelCount(stringToAudioChannelMask(mask));
+}
+
+static inline bool isOutputDevice(AudioDevice device) {
+ switch (device) {
+ case AudioDevice::UNKNOWN:
+ case AudioDevice::AUDIO_DEVICE_NONE:
+ return false;
+ case AudioDevice::AUDIO_DEVICE_OUT_EARPIECE:
+ case AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
+ case AudioDevice::AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AudioDevice::AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ case AudioDevice::AUDIO_DEVICE_OUT_HDMI:
+ case AudioDevice::AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AudioDevice::AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AudioDevice::AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+ case AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
+ case AudioDevice::AUDIO_DEVICE_OUT_LINE:
+ case AudioDevice::AUDIO_DEVICE_OUT_HDMI_ARC:
+ case AudioDevice::AUDIO_DEVICE_OUT_SPDIF:
+ case AudioDevice::AUDIO_DEVICE_OUT_FM:
+ case AudioDevice::AUDIO_DEVICE_OUT_AUX_LINE:
+ case AudioDevice::AUDIO_DEVICE_OUT_SPEAKER_SAFE:
+ case AudioDevice::AUDIO_DEVICE_OUT_IP:
+ case AudioDevice::AUDIO_DEVICE_OUT_BUS:
+ case AudioDevice::AUDIO_DEVICE_OUT_PROXY:
+ case AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_HEARING_AID:
+ case AudioDevice::AUDIO_DEVICE_OUT_ECHO_CANCELLER:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLE_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_OUT_BLE_SPEAKER:
+ case AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
+ case AudioDevice::AUDIO_DEVICE_OUT_STUB:
+ return true;
+ case AudioDevice::AUDIO_DEVICE_IN_COMMUNICATION:
+ case AudioDevice::AUDIO_DEVICE_IN_AMBIENT:
+ case AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC:
+ case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_WIRED_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_AUX_DIGITAL:
+ case AudioDevice::AUDIO_DEVICE_IN_HDMI:
+ case AudioDevice::AUDIO_DEVICE_IN_VOICE_CALL:
+ case AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX:
+ case AudioDevice::AUDIO_DEVICE_IN_BACK_MIC:
+ case AudioDevice::AUDIO_DEVICE_IN_REMOTE_SUBMIX:
+ case AudioDevice::AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_USB_ACCESSORY:
+ case AudioDevice::AUDIO_DEVICE_IN_USB_DEVICE:
+ case AudioDevice::AUDIO_DEVICE_IN_FM_TUNER:
+ case AudioDevice::AUDIO_DEVICE_IN_TV_TUNER:
+ case AudioDevice::AUDIO_DEVICE_IN_LINE:
+ case AudioDevice::AUDIO_DEVICE_IN_SPDIF:
+ case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_A2DP:
+ case AudioDevice::AUDIO_DEVICE_IN_LOOPBACK:
+ case AudioDevice::AUDIO_DEVICE_IN_IP:
+ case AudioDevice::AUDIO_DEVICE_IN_BUS:
+ case AudioDevice::AUDIO_DEVICE_IN_PROXY:
+ case AudioDevice::AUDIO_DEVICE_IN_USB_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_BLE:
+ case AudioDevice::AUDIO_DEVICE_IN_HDMI_ARC:
+ case AudioDevice::AUDIO_DEVICE_IN_ECHO_REFERENCE:
+ case AudioDevice::AUDIO_DEVICE_IN_BLE_HEADSET:
+ case AudioDevice::AUDIO_DEVICE_IN_DEFAULT:
+ case AudioDevice::AUDIO_DEVICE_IN_STUB:
+ return false;
+ // No default to make sure all cases are covered.
+ }
+ // This is to avoid undefined behavior if 'device' isn't a valid enum value.
+ return false;
+}
+
+static inline bool isOutputDevice(const std::string& device) {
+ return isOutputDevice(stringToAudioDevice(device));
+}
+
+} // namespace audio::policy::configuration::V7_0
+
+#endif // AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
diff --git a/audio/common/7.0/example/Android.bp b/audio/common/7.0/example/Android.bp
new file mode 100644
index 0000000..03c1cd8
--- /dev/null
+++ b/audio/common/7.0/example/Android.bp
@@ -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.
+
+cc_binary {
+ name: "android.hardware.audio@7.0-service.example",
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.audio@7.0-service.example.rc"],
+ vintf_fragments: ["android.hardware.audio@7.0-service.example.xml"],
+ srcs: [
+ "DevicesFactory.cpp",
+ "Effect.cpp",
+ "EffectsFactory.cpp",
+ "EqualizerEffect.cpp",
+ "LoudnessEnhancerEffect.cpp",
+ "service.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libxml2",
+ "libutils",
+ "android.hardware.audio@7.0",
+ "android.hardware.audio.common@7.0",
+ "android.hardware.audio.common@7.0-enums",
+ "android.hardware.audio.effect@7.0",
+ ],
+}
diff --git a/audio/common/7.0/example/DevicesFactory.cpp b/audio/common/7.0/example/DevicesFactory.cpp
new file mode 100644
index 0000000..ddd5fef
--- /dev/null
+++ b/audio/common/7.0/example/DevicesFactory.cpp
@@ -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.
+ */
+
+#define LOG_TAG "DevicesFactory7.0"
+#include <log/log.h>
+
+#include "DevicesFactory.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+namespace android::hardware::audio::V7_0::implementation {
+
+Return<void> DevicesFactory::openDevice(const hidl_string& device, openDevice_cb _hidl_cb) {
+ (void)device;
+ _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+ return Void();
+}
+
+Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+ return Void();
+}
+
+} // namespace android::hardware::audio::V7_0::implementation
diff --git a/audio/common/7.0/example/DevicesFactory.h b/audio/common/7.0/example/DevicesFactory.h
new file mode 100644
index 0000000..00f665c
--- /dev/null
+++ b/audio/common/7.0/example/DevicesFactory.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/audio/7.0/IDevicesFactory.h>
+
+namespace android::hardware::audio::V7_0::implementation {
+
+class DevicesFactory : public IDevicesFactory {
+ public:
+ DevicesFactory() = default;
+
+ ::android::hardware::Return<void> openDevice(const ::android::hardware::hidl_string& device,
+ openDevice_cb _hidl_cb) override;
+
+ ::android::hardware::Return<void> openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override;
+};
+
+} // namespace android::hardware::audio::V7_0::implementation
diff --git a/audio/common/7.0/example/Effect.cpp b/audio/common/7.0/example/Effect.cpp
new file mode 100644
index 0000000..423754d
--- /dev/null
+++ b/audio/common/7.0/example/Effect.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "EffectsFactory7.0"
+#include <log/log.h>
+
+#include <audio_policy_configuration_V7_0.h>
+
+#include "Effect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+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;
+}
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+Return<Result> Effect::init() {
+ return Result::OK;
+}
+
+Return<Result> Effect::setConfig(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ (void)config;
+ (void)inputBufferProvider;
+ (void)outputBufferProvider;
+ return Result::OK;
+}
+
+Return<Result> Effect::reset() {
+ return Result::OK;
+}
+
+Return<Result> Effect::enable() {
+ if (!mEnabled) {
+ mEnabled = true;
+ return Result::OK;
+ } else {
+ return Result::NOT_SUPPORTED;
+ }
+}
+
+Return<Result> Effect::disable() {
+ if (mEnabled) {
+ mEnabled = false;
+ return Result::OK;
+ } else {
+ return Result::NOT_SUPPORTED;
+ }
+}
+
+Return<Result> Effect::setDevice(const DeviceAddress& device) {
+ (void)device;
+ return Result::OK;
+}
+
+Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+ setAndGetVolume_cb _hidl_cb) {
+ (void)volumes;
+ _hidl_cb(Result::OK, hidl_vec<uint32_t>{});
+ return Void();
+}
+
+Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+ (void)volumes;
+ return Result::OK;
+}
+
+Return<Result> Effect::setAudioMode(AudioMode mode) {
+ (void)mode;
+ return Result::OK;
+}
+
+Return<Result> Effect::setConfigReverse(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ (void)config;
+ (void)inputBufferProvider;
+ (void)outputBufferProvider;
+ return Result::OK;
+}
+
+Return<Result> Effect::setInputDevice(const DeviceAddress& device) {
+ (void)device;
+ return Result::OK;
+}
+
+Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
+ const EffectConfig config = {{} /* inputCfg */,
+ // outputCfg
+ {{} /* buffer */,
+ 48000 /* samplingRateHz */,
+ toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
+ toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT),
+ EffectBufferAccess::ACCESS_ACCUMULATE,
+ 0 /* mask */}};
+ _hidl_cb(Result::OK, config);
+ return Void();
+}
+
+Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ _hidl_cb(Result::OK, EffectConfig{});
+ return Void();
+}
+
+Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
+ getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ (void)maxConfigs;
+ _hidl_cb(Result::OK, hidl_vec<EffectAuxChannelsConfig>{});
+ return Void();
+}
+
+Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ _hidl_cb(Result::OK, EffectAuxChannelsConfig{});
+ return Void();
+}
+
+Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+ (void)config;
+ return Result::OK;
+}
+
+Return<Result> Effect::setAudioSource(const hidl_string& source) {
+ (void)source;
+ return Result::OK;
+}
+
+Return<Result> Effect::offload(const EffectOffloadParameter& param) {
+ (void)param;
+ return Result::OK;
+}
+
+Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ _hidl_cb(Result::OK, mDescriptor);
+ return Void();
+}
+
+Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+ _hidl_cb(Result::OK, MQDescriptor<Result, kSynchronizedReadWrite>{});
+ return Void();
+}
+
+Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
+ const AudioBuffer& outBuffer) {
+ (void)inBuffer;
+ (void)outBuffer;
+ return Result::OK;
+}
+
+Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize, command_cb _hidl_cb) {
+ (void)commandId;
+ (void)data;
+ (void)resultMaxSize;
+ _hidl_cb(-EINVAL, hidl_vec<uint8_t>{});
+ return Void();
+}
+
+Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
+ const hidl_vec<uint8_t>& value) {
+ (void)parameter;
+ (void)value;
+ return Result::OK;
+}
+
+Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ (void)parameter;
+ (void)valueMaxSize;
+ _hidl_cb(Result::OK, hidl_vec<uint8_t>{});
+ return Void();
+}
+
+Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ (void)featureId;
+ (void)maxConfigs;
+ (void)configSize;
+ _hidl_cb(Result::OK, 0, hidl_vec<uint8_t>{});
+ return Void();
+}
+
+Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ (void)featureId;
+ (void)configSize;
+ _hidl_cb(Result::OK, hidl_vec<uint8_t>{});
+ return Void();
+}
+
+Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
+ const hidl_vec<uint8_t>& configData) {
+ (void)featureId;
+ (void)configData;
+ return Result::OK;
+}
+
+Return<Result> Effect::close() {
+ return Result::OK;
+}
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/Effect.h b/audio/common/7.0/example/Effect.h
new file mode 100644
index 0000000..fa7f41b
--- /dev/null
+++ b/audio/common/7.0/example/Effect.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.
+ */
+
+#pragma once
+
+#include <android/hardware/audio/effect/7.0/IEffect.h>
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class Effect : public IEffect {
+ public:
+ explicit Effect(const EffectDescriptor& descriptor) : mDescriptor(descriptor) {}
+
+ ::android::hardware::Return<Result> init() override;
+ ::android::hardware::Return<Result> setConfig(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ ::android::hardware::Return<Result> reset() override;
+ ::android::hardware::Return<Result> enable() override;
+ ::android::hardware::Return<Result> disable() override;
+ ::android::hardware::Return<Result> setDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override;
+ ::android::hardware::Return<void> setAndGetVolume(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes,
+ setAndGetVolume_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> volumeChangeNotification(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes) override;
+ ::android::hardware::Return<Result> setAudioMode(
+ ::android::hardware::audio::common::V7_0::AudioMode mode) override;
+ ::android::hardware::Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ ::android::hardware::Return<Result> setInputDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override;
+ ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getAuxChannelsConfig(
+ getAuxChannelsConfig_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) override;
+ ::android::hardware::Return<Result> setAudioSource(
+ const ::android::hardware::hidl_string& source) override;
+ ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override;
+ ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ ::android::hardware::Return<void> prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+ const AudioBuffer& outBuffer) override;
+ ::android::hardware::Return<void> command(uint32_t commandId,
+ const ::android::hardware::hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize, command_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter,
+ const ::android::hardware::hidl_vec<uint8_t>& value) override;
+ ::android::hardware::Return<void> getParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getCurrentConfigForFeature(
+ uint32_t featureId, uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override;
+ ::android::hardware::Return<Result> close() override;
+
+ private:
+ const EffectDescriptor mDescriptor;
+ bool mEnabled = false;
+};
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EffectsFactory.cpp b/audio/common/7.0/example/EffectsFactory.cpp
new file mode 100644
index 0000000..7d333ae
--- /dev/null
+++ b/audio/common/7.0/example/EffectsFactory.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.
+ */
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "EffectsFactory.h"
+#include "EqualizerEffect.h"
+#include "LoudnessEnhancerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) {
+ hidl_vec<EffectDescriptor> descriptors;
+ descriptors.resize(2);
+ descriptors[0] = EqualizerEffect::getDescriptor();
+ descriptors[1] = LoudnessEnhancerEffect::getDescriptor();
+ _hidl_cb(Result::OK, descriptors);
+ return Void();
+}
+
+Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) {
+ if (auto desc = EqualizerEffect::getDescriptor(); uuid == desc.type || uuid == desc.uuid) {
+ _hidl_cb(Result::OK, desc);
+ } else if (auto desc = LoudnessEnhancerEffect::getDescriptor();
+ uuid == desc.type || uuid == desc.uuid) {
+ _hidl_cb(Result::OK, desc);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, EffectDescriptor{});
+ }
+ return Void();
+}
+
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+ int32_t device, createEffect_cb _hidl_cb) {
+ (void)session;
+ (void)ioHandle;
+ (void)device;
+ if (auto desc = EqualizerEffect::getDescriptor(); uuid == desc.type || uuid == desc.uuid) {
+ _hidl_cb(Result::OK, new EqualizerEffect(), 0);
+ } else if (auto desc = LoudnessEnhancerEffect::getDescriptor();
+ uuid == desc.type || uuid == desc.uuid) {
+ _hidl_cb(Result::OK, new LoudnessEnhancerEffect(), 0);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, 0);
+ }
+ return Void();
+}
+
+Return<void> EffectsFactory::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+ (void)fd;
+ (void)options;
+ return Void();
+}
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EffectsFactory.h b/audio/common/7.0/example/EffectsFactory.h
new file mode 100644
index 0000000..8fec70c
--- /dev/null
+++ b/audio/common/7.0/example/EffectsFactory.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 <android/hardware/audio/effect/7.0/IEffectsFactory.h>
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class EffectsFactory : public IEffectsFactory {
+ public:
+ EffectsFactory() = default;
+
+ ::android::hardware::Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getDescriptor(
+ const ::android::hardware::audio::common::V7_0::Uuid& uuid,
+ getDescriptor_cb _hidl_cb) override;
+ ::android::hardware::Return<void> createEffect(
+ const ::android::hardware::audio::common::V7_0::Uuid& uuid, int32_t session,
+ int32_t ioHandle, int32_t device, createEffect_cb _hidl_cb) override;
+ ::android::hardware::Return<void>
+ debug(const ::android::hardware::hidl_handle& fd,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options) override;
+};
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EqualizerEffect.cpp b/audio/common/7.0/example/EqualizerEffect.cpp
new file mode 100644
index 0000000..c93c5a9
--- /dev/null
+++ b/audio/common/7.0/example/EqualizerEffect.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 <limits>
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "EqualizerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+const EffectDescriptor& EqualizerEffect::getDescriptor() {
+ // Note: for VTS tests only 'type' and 'uuid' fields are required.
+ // The actual implementation must provide meaningful values
+ // for all fields of the descriptor.
+ static const EffectDescriptor descriptor = {
+ .type =
+ {// Same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java.
+ 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+ std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}},
+ .uuid = {0, 0, 0, 1, std::array<uint8_t, 6>{{0, 0, 0, 0, 0, 0}}}};
+ return descriptor;
+}
+
+EqualizerEffect::EqualizerEffect() : mEffect(new Effect(getDescriptor())) {
+ mProperties.bandLevels.resize(kNumBands);
+}
+
+Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) {
+ _hidl_cb(Result::OK, kNumBands);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) {
+ _hidl_cb(Result::OK, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
+ return Void();
+}
+
+Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) {
+ if (band < kNumBands) {
+ mProperties.bandLevels[band] = level;
+ return Result::OK;
+ } else {
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) {
+ if (band < kNumBands) {
+ _hidl_cb(Result::OK, mProperties.bandLevels[band]);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, 0);
+ }
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandCenterFrequency(uint16_t band,
+ getBandCenterFrequency_cb _hidl_cb) {
+ (void)band;
+ _hidl_cb(Result::OK, 0);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandFrequencyRange(uint16_t band,
+ getBandFrequencyRange_cb _hidl_cb) {
+ (void)band;
+ _hidl_cb(Result::OK, 0, 1);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) {
+ (void)freq;
+ _hidl_cb(Result::OK, 0);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb) {
+ hidl_vec<hidl_string> presetNames;
+ presetNames.resize(kNumPresets);
+ presetNames[0] = "default";
+ _hidl_cb(Result::OK, presetNames);
+ return Void();
+}
+
+Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset) {
+ if (preset < kNumPresets) {
+ mProperties.curPreset = preset;
+ return Result::OK;
+ } else {
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb) {
+ _hidl_cb(Result::OK, mProperties.curPreset);
+ return Void();
+}
+
+Return<Result> EqualizerEffect::setAllProperties(
+ const IEqualizerEffect::AllProperties& properties) {
+ mProperties = properties;
+ return Result::OK;
+}
+
+Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+ _hidl_cb(Result::OK, mProperties);
+ return Void();
+}
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EqualizerEffect.h b/audio/common/7.0/example/EqualizerEffect.h
new file mode 100644
index 0000000..11853c3
--- /dev/null
+++ b/audio/common/7.0/example/EqualizerEffect.h
@@ -0,0 +1,163 @@
+/*
+ * 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/audio/effect/7.0/IEqualizerEffect.h>
+
+#include "Effect.h"
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class EqualizerEffect : public IEqualizerEffect {
+ public:
+ static const EffectDescriptor& getDescriptor();
+
+ EqualizerEffect();
+
+ // Methods from IEffect interface.
+ ::android::hardware::Return<Result> init() override { return mEffect->init(); }
+ ::android::hardware::Return<Result> setConfig(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+ }
+ ::android::hardware::Return<Result> reset() override { return mEffect->reset(); }
+ ::android::hardware::Return<Result> enable() override { return mEffect->enable(); }
+ ::android::hardware::Return<Result> disable() override { return mEffect->disable(); }
+ ::android::hardware::Return<Result> setDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+ return mEffect->setDevice(device);
+ }
+ ::android::hardware::Return<void> setAndGetVolume(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes,
+ setAndGetVolume_cb _hidl_cb) override {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> volumeChangeNotification(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes) override {
+ return mEffect->volumeChangeNotification(volumes);
+ }
+ ::android::hardware::Return<Result> setAudioMode(
+ ::android::hardware::audio::common::V7_0::AudioMode mode) override {
+ return mEffect->setAudioMode(mode);
+ }
+ ::android::hardware::Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+ }
+ ::android::hardware::Return<Result> setInputDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+ return mEffect->setInputDevice(device);
+ }
+ ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override {
+ return mEffect->getConfig(_hidl_cb);
+ }
+ ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override {
+ return mEffect->getConfigReverse(_hidl_cb);
+ }
+ ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getAuxChannelsConfig(
+ getAuxChannelsConfig_cb _hidl_cb) override {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+ }
+ ::android::hardware::Return<Result> setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) override {
+ return mEffect->setAuxChannelsConfig(config);
+ }
+ ::android::hardware::Return<Result> setAudioSource(
+ const ::android::hardware::hidl_string& source) override {
+ return mEffect->setAudioSource(source);
+ }
+ ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override {
+ return mEffect->offload(param);
+ }
+ ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override {
+ return mEffect->getDescriptor(_hidl_cb);
+ }
+ ::android::hardware::Return<void> prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) override {
+ return mEffect->prepareForProcessing(_hidl_cb);
+ }
+ ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+ const AudioBuffer& outBuffer) override {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+ }
+ ::android::hardware::Return<void> command(uint32_t commandId,
+ const ::android::hardware::hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> setParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter,
+ const ::android::hardware::hidl_vec<uint8_t>& value) override {
+ return mEffect->setParameter(parameter, value);
+ }
+ ::android::hardware::Return<void> getParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getCurrentConfigForFeature(
+ uint32_t featureId, uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+ }
+ ::android::hardware::Return<Result> close() override { return mEffect->close(); }
+
+ // Methods from IEqualizerEffect interface.
+ ::android::hardware::Return<void> getNumBands(getNumBands_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setBandLevel(uint16_t band, int16_t level) override;
+ ::android::hardware::Return<void> getBandLevel(uint16_t band,
+ getBandLevel_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getBandCenterFrequency(
+ uint16_t band, getBandCenterFrequency_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getBandFrequencyRange(
+ uint16_t band, getBandFrequencyRange_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getBandForFrequency(uint32_t freq,
+ getBandForFrequency_cb _hidl_cb) override;
+ ::android::hardware::Return<void> getPresetNames(getPresetNames_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setCurrentPreset(uint16_t preset) override;
+ ::android::hardware::Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb) override;
+ ::android::hardware::Return<Result> setAllProperties(
+ const IEqualizerEffect::AllProperties& properties) override;
+ ::android::hardware::Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+ private:
+ static constexpr size_t kNumBands = 1;
+ static constexpr size_t kNumPresets = 1;
+ sp<Effect> mEffect;
+ IEqualizerEffect::AllProperties mProperties{};
+};
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/LoudnessEnhancerEffect.cpp b/audio/common/7.0/example/LoudnessEnhancerEffect.cpp
new file mode 100644
index 0000000..38269b3
--- /dev/null
+++ b/audio/common/7.0/example/LoudnessEnhancerEffect.cpp
@@ -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.
+ */
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "LoudnessEnhancerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+const EffectDescriptor& LoudnessEnhancerEffect::getDescriptor() {
+ // Note: for VTS tests only 'type' and 'uuid' fields are required.
+ // The actual implementation must provide meaningful values
+ // for all fields of the descriptor.
+ static const EffectDescriptor descriptor = {
+ .type =
+ {// Same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java.
+ 0xfe3199be, 0xaed0, 0x413f, 0x87bb,
+ std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}},
+ .uuid = {0, 0, 0, 2, std::array<uint8_t, 6>{{0, 0, 0, 0, 0, 0}}}};
+ return descriptor;
+} // namespace android::hardware::audio::effect::V7_0::implementation
+
+LoudnessEnhancerEffect::LoudnessEnhancerEffect() : mEffect(new Effect(getDescriptor())) {}
+
+Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) {
+ mTargetGainMb = targetGainMb;
+ return Result::OK;
+}
+
+Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) {
+ _hidl_cb(Result::OK, mTargetGainMb);
+ return Void();
+}
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/LoudnessEnhancerEffect.h b/audio/common/7.0/example/LoudnessEnhancerEffect.h
new file mode 100644
index 0000000..1af0d9f
--- /dev/null
+++ b/audio/common/7.0/example/LoudnessEnhancerEffect.h
@@ -0,0 +1,146 @@
+/*
+ * 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/audio/effect/7.0/ILoudnessEnhancerEffect.h>
+
+#include "Effect.h"
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class LoudnessEnhancerEffect : public ILoudnessEnhancerEffect {
+ public:
+ static const EffectDescriptor& getDescriptor();
+
+ LoudnessEnhancerEffect();
+
+ // Methods from IEffect interface.
+ ::android::hardware::Return<Result> init() override { return mEffect->init(); }
+ ::android::hardware::Return<Result> setConfig(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+ }
+ ::android::hardware::Return<Result> reset() override { return mEffect->reset(); }
+ ::android::hardware::Return<Result> enable() override { return mEffect->enable(); }
+ ::android::hardware::Return<Result> disable() override { return mEffect->disable(); }
+ ::android::hardware::Return<Result> setDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+ return mEffect->setDevice(device);
+ }
+ ::android::hardware::Return<void> setAndGetVolume(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes,
+ setAndGetVolume_cb _hidl_cb) override {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> volumeChangeNotification(
+ const ::android::hardware::hidl_vec<uint32_t>& volumes) override {
+ return mEffect->volumeChangeNotification(volumes);
+ }
+ ::android::hardware::Return<Result> setAudioMode(
+ ::android::hardware::audio::common::V7_0::AudioMode mode) override {
+ return mEffect->setAudioMode(mode);
+ }
+ ::android::hardware::Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+ }
+ ::android::hardware::Return<Result> setInputDevice(
+ const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+ return mEffect->setInputDevice(device);
+ }
+ ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override {
+ return mEffect->getConfig(_hidl_cb);
+ }
+ ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override {
+ return mEffect->getConfigReverse(_hidl_cb);
+ }
+ ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getAuxChannelsConfig(
+ getAuxChannelsConfig_cb _hidl_cb) override {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+ }
+ ::android::hardware::Return<Result> setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) override {
+ return mEffect->setAuxChannelsConfig(config);
+ }
+ ::android::hardware::Return<Result> setAudioSource(
+ const ::android::hardware::hidl_string& source) override {
+ return mEffect->setAudioSource(source);
+ }
+ ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override {
+ return mEffect->offload(param);
+ }
+ ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override {
+ return mEffect->getDescriptor(_hidl_cb);
+ }
+ ::android::hardware::Return<void> prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) override {
+ return mEffect->prepareForProcessing(_hidl_cb);
+ }
+ ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+ const AudioBuffer& outBuffer) override {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+ }
+ ::android::hardware::Return<void> command(uint32_t commandId,
+ const ::android::hardware::hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> setParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter,
+ const ::android::hardware::hidl_vec<uint8_t>& value) override {
+ return mEffect->setParameter(parameter, value);
+ }
+ ::android::hardware::Return<void> getParameter(
+ const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+ }
+ ::android::hardware::Return<void> getCurrentConfigForFeature(
+ uint32_t featureId, uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+ }
+ ::android::hardware::Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+ }
+ ::android::hardware::Return<Result> close() override { return mEffect->close(); }
+
+ // Methods from ILoudnessEnhancerEffect interface.
+ ::android::hardware::Return<Result> setTargetGain(int32_t targetGainMb) override;
+ ::android::hardware::Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+ int32_t mTargetGainMb = 0;
+};
+
+} // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc
new file mode 100644
index 0000000..cf8b51f
--- /dev/null
+++ b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc
@@ -0,0 +1,7 @@
+service vendor.audio-hal-7-0 /vendor/bin/hw/android.hardware.audio@7.0-service.example
+ class hal
+ user audioserver
+ group audio
+ capabilities BLOCK_SUSPEND
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh HighPerformance
diff --git a/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml
new file mode 100644
index 0000000..b91b061
--- /dev/null
+++ b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml
@@ -0,0 +1,20 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.audio</name>
+ <transport>hwbinder</transport>
+ <version>7.0</version>
+ <interface>
+ <name>IDevicesFactory</name>
+ <instance>example</instance>
+ </interface>
+ </hal>
+ <hal format="hidl">
+ <name>android.hardware.audio.effect</name>
+ <transport>hwbinder</transport>
+ <version>7.0</version>
+ <interface>
+ <name>IEffectsFactory</name>
+ <instance>example</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/audio/common/7.0/example/service.cpp b/audio/common/7.0/example/service.cpp
new file mode 100644
index 0000000..641e2c9
--- /dev/null
+++ b/audio/common/7.0/example/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.audio@7.0-service.example"
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+
+#include "DevicesFactory.h"
+#include "EffectsFactory.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using namespace android;
+
+status_t registerDevicesFactoryService() {
+ sp<::android::hardware::audio::V7_0::IDevicesFactory> devicesFactory =
+ new ::android::hardware::audio::V7_0::implementation::DevicesFactory();
+ status_t status = devicesFactory->registerAsService("example");
+ ALOGE_IF(status != OK, "Error registering devices factory as service: %d", status);
+ return status;
+}
+
+status_t registerEffectsFactoryService() {
+ sp<::android::hardware::audio::effect::V7_0::IEffectsFactory> devicesFactory =
+ new ::android::hardware::audio::effect::V7_0::implementation::EffectsFactory();
+ status_t status = devicesFactory->registerAsService("example");
+ ALOGE_IF(status != OK, "Error registering effects factory as service: %d", status);
+ return status;
+}
+
+int main() {
+ configureRpcThreadpool(1, true);
+ status_t status = registerDevicesFactoryService();
+ if (status != OK) {
+ return status;
+ }
+ status = registerEffectsFactoryService();
+ if (status != OK) {
+ return status;
+ }
+ joinRpcThreadpool();
+
+ return 1;
+}
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
index 2288eb1..0d0fa7e 100644
--- a/audio/common/7.0/types.hal
+++ b/audio/common/7.0/types.hal
@@ -18,34 +18,18 @@
import android.hidl.safe_union@1.0;
-/*
- *
- * IDs and Handles
- *
- */
-
/**
- * Handle type for identifying audio sources and sinks.
+ * Handle type for identifying audio resources. Handles are allocated by the framework.
*/
typedef int32_t AudioIoHandle;
/**
- * Audio hw module handle functions or structures referencing a module.
- */
-typedef int32_t AudioModuleHandle;
-
-/**
* Each port has a unique ID or handle allocated by policy manager.
*/
typedef int32_t AudioPortHandle;
/**
- * Each patch is identified by a handle at the interface used to create that
- * patch. For instance, when a patch is created by the audio HAL, the HAL
- * allocates and returns a handle. This handle is unique to a given audio HAL
- * hardware module. But the same patch receives another system wide unique
- * handle allocated by the framework. This unique handle is used for all
- * transactions inside the framework.
+ * Each patch is identified by a handle allocated by the HAL.
*/
typedef int32_t AudioPatchHandle;
@@ -55,17 +39,6 @@
typedef uint32_t AudioHwSync;
/**
- * Each port has a unique ID or handle allocated by policy manager.
- */
-@export(name="")
-enum AudioHandleConsts : int32_t {
- AUDIO_IO_HANDLE_NONE = 0,
- AUDIO_MODULE_HANDLE_NONE = 0,
- AUDIO_PORT_HANDLE_NONE = 0,
- AUDIO_PATCH_HANDLE_NONE = 0,
-};
-
-/**
* Commonly used structure for passing unique identifieds (UUID).
* For the definition of UUID, refer to ITU-T X.667 spec.
*/
@@ -86,116 +59,25 @@
/**
* Audio stream type describing the intended use case of a stream.
+ * See 'audioStreamType' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
-enum AudioStreamType : int32_t {
- // These values must kept in sync with
- // frameworks/base/media/java/android/media/AudioSystem.java
- /** Used to identify the default audio stream volume. */
- DEFAULT = -1,
- /** Specifies the minimum value for use in checks and loops. */
- MIN = 0,
- /** Used to identify the volume of audio streams for phone calls. */
- VOICE_CALL = 0,
- /** Used to identify the volume of audio streams for system sounds. */
- SYSTEM = 1,
- /**
- * Used to identify the volume of audio streams for the phone ring
- * and message alerts.
- */
- RING = 2,
- /** Used to identify the volume of audio streams for music playback. */
- MUSIC = 3,
- /** Used to identify the volume of audio streams for alarms. */
- ALARM = 4,
- /** Used to identify the volume of audio streams for notifications. */
- NOTIFICATION = 5,
- /**
- * Used to identify the volume of audio streams for phone calls
- * when connected on bluetooth.
- */
- BLUETOOTH_SCO = 6,
- /**
- * Used to identify the volume of audio streams for enforced system
- * sounds in certain countries (e.g camera in Japan). */
- ENFORCED_AUDIBLE = 7,
- /** Used to identify the volume of audio streams for DTMF tones. */
- DTMF = 8,
- /**
- * Used to identify the volume of audio streams exclusively transmitted
- * through the speaker (TTS) of the device.
- */
- TTS = 9,
- /**
- * Used to identify the volume of audio streams for accessibility prompts.
- */
- ACCESSIBILITY = 10,
- /** Used to identify the volume of audio streams for virtual assistant. */
- ASSISTANT = 11,
-};
+typedef string AudioStreamType;
-@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
-enum AudioSource : int32_t {
- // These values must kept in sync with
- // frameworks/base/media/java/android/media/MediaRecorder.java,
- // system/media/audio_effects/include/audio_effects/audio_effects_conf.h
- /** Default audio source. */
- DEFAULT = 0,
- /** Microphone audio source. */
- MIC = 1,
- /** Voice call uplink (Tx) audio source. */
- VOICE_UPLINK = 2,
- /** Voice call downlink (Rx) audio source. */
- VOICE_DOWNLINK = 3,
- /** Voice call uplink + downlink audio source. */
- VOICE_CALL = 4,
- /**
- * Microphone audio source tuned for video recording, with the same
- * orientation as the camera if available.
- */
- CAMCORDER = 5,
- /** Microphone audio source tuned for voice recognition. */
- VOICE_RECOGNITION = 6,
- /**
- * Microphone audio source tuned for voice communications such as VoIP. It
- * will for instance take advantage of echo cancellation or automatic gain
- * control if available.
- */
- VOICE_COMMUNICATION = 7,
- /**
- * Source for the mix to be presented remotely. An example of remote
- * presentation is Wifi Display where a dongle attached to a TV can be used
- * to play the mix captured by this audio source.
- */
- REMOTE_SUBMIX = 8,
- /**
- * Source for unprocessed sound. Usage examples include level measurement
- * and raw signal analysis.
- */
- UNPROCESSED = 9,
- /**
- * Source for capturing audio meant to be processed in real time and played back for live
- * performance (e.g karaoke). The capture path will minimize latency and coupling with
- * playback path.
- */
- VOICE_PERFORMANCE = 10,
- /**
- * Source for an echo canceller to capture the reference signal to be cancelled.
- * The echo reference signal will be captured as close as possible to the DAC in order
- * to include all post processing applied to the playback path.
- */
- ECHO_REFERENCE = 1997,
- /** Virtual source for the built-in FM tuner. */
- FM_TUNER = 1998,
- /** Virtual source for the last captured hotword. */
- HOTWORD = 1999,
-};
-
-typedef int32_t AudioSession;
/**
- * Special audio session values.
+ * An audio source defines the intended use case for the sound being recorded.
+ * See 'audioSource' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+typedef string AudioSource;
+
+/**
+ * An audio session identifier is used to designate the particular
+ * playback or recording session (e.g. playback performed by a certain
+ * application).
+ */
+typedef int32_t AudioSession;
+
enum AudioSessionConsts : int32_t {
/**
* Session for effects attached to a particular sink or source audio device
@@ -213,382 +95,42 @@
* (value must be 0)
*/
OUTPUT_MIX = 0,
- /**
- * Application does not specify an explicit session ID to be used, and
- * requests a new session ID to be allocated. Corresponds to
- * AudioManager.AUDIO_SESSION_ID_GENERATE and
- * AudioSystem.AUDIO_SESSION_ALLOCATE.
- */
- ALLOCATE = 0,
- /**
- * For use with AudioRecord::start(), this indicates no trigger session.
- * It is also used with output tracks and patch tracks, which never have a
- * session.
- */
- NONE = 0
};
/**
- * Audio format is a 32-bit word that consists of:
- * main format field (upper 8 bits)
- * sub format field (lower 24 bits).
- *
- * The main format indicates the main codec type. The sub format field indicates
- * options and parameters for each format. The sub format is mainly used for
- * record to indicate for instance the requested bitrate or profile. It can
- * also be used for certain formats to give informations not present in the
- * encoded audio stream (e.g. octet alignement for AMR).
+ * Audio format indicates audio codec type.
+ * See 'audioFormat' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
-enum AudioFormat : uint32_t {
- INVALID = 0xFFFFFFFFUL,
- DEFAULT = 0,
- PCM = 0x00000000UL,
- MP3 = 0x01000000UL,
- AMR_NB = 0x02000000UL,
- AMR_WB = 0x03000000UL,
- AAC = 0x04000000UL,
- /** Deprecated, Use AAC_HE_V1 */
- HE_AAC_V1 = 0x05000000UL,
- /** Deprecated, Use AAC_HE_V2 */
- HE_AAC_V2 = 0x06000000UL,
- VORBIS = 0x07000000UL,
- OPUS = 0x08000000UL,
- AC3 = 0x09000000UL,
- E_AC3 = 0x0A000000UL,
- DTS = 0x0B000000UL,
- DTS_HD = 0x0C000000UL,
- /** IEC61937 is encoded audio wrapped in 16-bit PCM. */
- IEC61937 = 0x0D000000UL,
- DOLBY_TRUEHD = 0x0E000000UL,
- EVRC = 0x10000000UL,
- EVRCB = 0x11000000UL,
- EVRCWB = 0x12000000UL,
- EVRCNW = 0x13000000UL,
- AAC_ADIF = 0x14000000UL,
- WMA = 0x15000000UL,
- WMA_PRO = 0x16000000UL,
- AMR_WB_PLUS = 0x17000000UL,
- MP2 = 0x18000000UL,
- QCELP = 0x19000000UL,
- DSD = 0x1A000000UL,
- FLAC = 0x1B000000UL,
- ALAC = 0x1C000000UL,
- APE = 0x1D000000UL,
- AAC_ADTS = 0x1E000000UL,
- SBC = 0x1F000000UL,
- APTX = 0x20000000UL,
- APTX_HD = 0x21000000UL,
- AC4 = 0x22000000UL,
- LDAC = 0x23000000UL,
- /** Dolby Metadata-enhanced Audio Transmission */
- MAT = 0x24000000UL,
- AAC_LATM = 0x25000000UL,
- CELT = 0x26000000UL,
- APTX_ADAPTIVE = 0x27000000UL,
- LHDC = 0x28000000UL,
- LHDC_LL = 0x29000000UL,
- APTX_TWSP = 0x2A000000UL,
+typedef string AudioFormat;
- /** Deprecated */
- MAIN_MASK = 0xFF000000UL,
- SUB_MASK = 0x00FFFFFFUL,
+/**
+ * Audio channel mask indicates presence of particular channels.
+ * Note that every value is already a mask comprised of individual
+ * channels.
+ * See 'audioChannelMask' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioChannelMask;
- /* Subformats */
- PCM_SUB_16_BIT = 0x1, // PCM signed 16 bits
- PCM_SUB_8_BIT = 0x2, // PCM unsigned 8 bits
- PCM_SUB_32_BIT = 0x3, // PCM signed .31 fixed point
- PCM_SUB_8_24_BIT = 0x4, // PCM signed 8.23 fixed point
- PCM_SUB_FLOAT = 0x5, // PCM single-precision float pt
- PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
-
- MP3_SUB_NONE = 0x0,
-
- AMR_SUB_NONE = 0x0,
-
- AAC_SUB_MAIN = 0x1,
- AAC_SUB_LC = 0x2,
- AAC_SUB_SSR = 0x4,
- AAC_SUB_LTP = 0x8,
- AAC_SUB_HE_V1 = 0x10,
- AAC_SUB_SCALABLE = 0x20,
- AAC_SUB_ERLC = 0x40,
- AAC_SUB_LD = 0x80,
- AAC_SUB_HE_V2 = 0x100,
- AAC_SUB_ELD = 0x200,
- AAC_SUB_XHE = 0x300,
-
- VORBIS_SUB_NONE = 0x0,
-
- E_AC3_SUB_JOC = 0x1,
-
- MAT_SUB_1_0 = 0x1,
- MAT_SUB_2_0 = 0x2,
- MAT_SUB_2_1 = 0x3,
-
- /* Aliases */
- /** note != AudioFormat.ENCODING_PCM_16BIT */
- PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
- /** note != AudioFormat.ENCODING_PCM_8BIT */
- PCM_8_BIT = (PCM | PCM_SUB_8_BIT),
- PCM_32_BIT = (PCM | PCM_SUB_32_BIT),
- PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT),
- PCM_FLOAT = (PCM | PCM_SUB_FLOAT),
- PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED),
- AAC_MAIN = (AAC | AAC_SUB_MAIN),
- AAC_LC = (AAC | AAC_SUB_LC),
- AAC_SSR = (AAC | AAC_SUB_SSR),
- AAC_LTP = (AAC | AAC_SUB_LTP),
- AAC_HE_V1 = (AAC | AAC_SUB_HE_V1),
- AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE),
- AAC_ERLC = (AAC | AAC_SUB_ERLC),
- AAC_LD = (AAC | AAC_SUB_LD),
- AAC_HE_V2 = (AAC | AAC_SUB_HE_V2),
- AAC_ELD = (AAC | AAC_SUB_ELD),
- AAC_XHE = (AAC | AAC_SUB_XHE),
- AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN),
- AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC),
- AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR),
- AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP),
- AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1),
- AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE),
- AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC),
- AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD),
- AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2),
- AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD),
- AAC_ADTS_XHE = (AAC_ADTS | AAC_SUB_XHE),
- E_AC3_JOC = (E_AC3 | E_AC3_SUB_JOC),
- MAT_1_0 = (MAT | MAT_SUB_1_0),
- MAT_2_0 = (MAT | MAT_SUB_2_0),
- MAT_2_1 = (MAT | MAT_SUB_2_1),
- AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC),
- AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1),
- AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2),
+/**
+ * Base configuration attributes applicable to any stream of audio.
+ */
+struct AudioConfigBase {
+ AudioFormat format; // 'DEFAULT' means 'unspecified'
+ uint32_t sampleRateHz; // 0 means 'unspecified'
+ vec<AudioChannelMask> channelMask; // empty means 'unspecified'
};
/**
- * Usage of these values highlights places in the code that use 2- or 8- channel
- * assumptions.
+ * Configurations supported for a certain audio format.
*/
-@export(name="")
-enum FixedChannelCount : int32_t {
- FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
- FCC_8 = 8 // This is typically due to audio mixer and resampler limitations
-};
-
-/**
- * A channel mask per se only defines the presence or absence of a channel, not
- * the order.
- *
- * The channel order convention is that channels are interleaved in order from
- * least significant channel mask bit to most significant channel mask bit,
- * with unused bits skipped. For example for stereo, LEFT would be first,
- * followed by RIGHT.
- * Any exceptions to this convention are noted at the appropriate API.
- *
- * AudioChannelMask is an opaque type and its internal layout should not be
- * assumed as it may change in the future. Instead, always use functions
- * to examine it.
- *
- * These are the current representations:
- *
- * REPRESENTATION_POSITION
- * is a channel mask representation for position assignment. Each low-order
- * bit corresponds to the spatial position of a transducer (output), or
- * interpretation of channel (input). The user of a channel mask needs to
- * know the context of whether it is for output or input. The constants
- * OUT_* or IN_* apply to the bits portion. It is not permitted for no bits
- * to be set.
- *
- * REPRESENTATION_INDEX
- * is a channel mask representation for index assignment. Each low-order
- * bit corresponds to a selected channel. There is no platform
- * interpretation of the various bits. There is no concept of output or
- * input. It is not permitted for no bits to be set.
- *
- * All other representations are reserved for future use.
- *
- * Warning: current representation distinguishes between input and output, but
- * this will not the be case in future revisions of the platform. Wherever there
- * is an ambiguity between input and output that is currently resolved by
- * checking the channel mask, the implementer should look for ways to fix it
- * with additional information outside of the mask.
- */
-@export(name="", value_prefix="AUDIO_CHANNEL_")
-enum AudioChannelMask : uint32_t {
- /** must be 0 for compatibility */
- REPRESENTATION_POSITION = 0,
- /** 1 is reserved for future use */
- REPRESENTATION_INDEX = 2,
- /* 3 is reserved for future use */
-
- /** These can be a complete value of AudioChannelMask */
- NONE = 0x0,
- INVALID = 0xC0000000,
-
- /*
- * These can be the bits portion of an AudioChannelMask
- * with representation REPRESENTATION_POSITION.
- */
-
- /** output channels */
- OUT_FRONT_LEFT = 0x1,
- OUT_FRONT_RIGHT = 0x2,
- OUT_FRONT_CENTER = 0x4,
- OUT_LOW_FREQUENCY = 0x8,
- OUT_BACK_LEFT = 0x10,
- OUT_BACK_RIGHT = 0x20,
- OUT_FRONT_LEFT_OF_CENTER = 0x40,
- OUT_FRONT_RIGHT_OF_CENTER = 0x80,
- OUT_BACK_CENTER = 0x100,
- OUT_SIDE_LEFT = 0x200,
- OUT_SIDE_RIGHT = 0x400,
- OUT_TOP_CENTER = 0x800,
- OUT_TOP_FRONT_LEFT = 0x1000,
- OUT_TOP_FRONT_CENTER = 0x2000,
- OUT_TOP_FRONT_RIGHT = 0x4000,
- OUT_TOP_BACK_LEFT = 0x8000,
- OUT_TOP_BACK_CENTER = 0x10000,
- OUT_TOP_BACK_RIGHT = 0x20000,
- OUT_TOP_SIDE_LEFT = 0x40000,
- OUT_TOP_SIDE_RIGHT = 0x80000,
-
- /**
- * Haptic channel characteristics are specific to a device and
- * only used to play device specific resources (eg: ringtones).
- * The HAL can freely map A and B to haptic controllers, the
- * framework shall not interpret those values and forward them
- * from the device audio assets.
- */
- OUT_HAPTIC_A = 0x20000000,
- OUT_HAPTIC_B = 0x10000000,
-
- OUT_MONO = OUT_FRONT_LEFT,
- OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
- OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
- OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
- OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
- OUT_LOW_FREQUENCY),
- OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
- OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
- OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
- OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
- OUT_LOW_FREQUENCY),
- OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_BACK_LEFT | OUT_BACK_RIGHT),
- OUT_QUAD_BACK = OUT_QUAD,
- /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
- OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
- OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_FRONT_CENTER | OUT_BACK_CENTER),
- OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
- OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
- OUT_BACK_LEFT | OUT_BACK_RIGHT),
- OUT_5POINT1_BACK = OUT_5POINT1,
- /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
- OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
- OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
- OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
- OUT_5POINT1POINT4 = (OUT_5POINT1 |
- OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
- OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
- OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
- OUT_BACK_LEFT | OUT_BACK_RIGHT |
- OUT_BACK_CENTER),
- /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
- OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
- OUT_BACK_LEFT | OUT_BACK_RIGHT |
- OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
- OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
- OUT_7POINT1POINT4 = (OUT_7POINT1 |
- OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
- OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
- OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
- OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
- OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
- OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
- OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_HAPTIC_A | OUT_HAPTIC_B),
- // Note that the 2.0 OUT_ALL* have been moved to helper functions
-
- /* These are bits only, not complete values */
-
- /** input channels */
- IN_LEFT = 0x4,
- IN_RIGHT = 0x8,
- IN_FRONT = 0x10,
- IN_BACK = 0x20,
- IN_LEFT_PROCESSED = 0x40,
- IN_RIGHT_PROCESSED = 0x80,
- IN_FRONT_PROCESSED = 0x100,
- IN_BACK_PROCESSED = 0x200,
- IN_PRESSURE = 0x400,
- IN_X_AXIS = 0x800,
- IN_Y_AXIS = 0x1000,
- IN_Z_AXIS = 0x2000,
- IN_BACK_LEFT = 0x10000,
- IN_BACK_RIGHT = 0x20000,
- IN_CENTER = 0x40000,
- IN_LOW_FREQUENCY = 0x100000,
- IN_TOP_LEFT = 0x200000,
- IN_TOP_RIGHT = 0x400000,
-
- IN_VOICE_UPLINK = 0x4000,
- IN_VOICE_DNLINK = 0x8000,
-
- IN_MONO = IN_FRONT,
- IN_STEREO = (IN_LEFT | IN_RIGHT),
- IN_FRONT_BACK = (IN_FRONT | IN_BACK),
- IN_6 = (IN_LEFT | IN_RIGHT |
- IN_FRONT | IN_BACK |
- IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
- IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
- IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT |
- IN_LOW_FREQUENCY),
- IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
- IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT |
- IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
- IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT |
- IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
- IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
- IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
- IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO |
- IN_VOICE_DNLINK_MONO),
- // Note that the 2.0 IN_ALL* have been moved to helper functions
-
- COUNT_MAX = 30,
- INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX,
- INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
- INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
- INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
- INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
- INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
- INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
- INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
- INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1),
- INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1),
- INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1),
- INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1),
- INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1),
- INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1),
- INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1),
- INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1),
- INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1),
- INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1),
- INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1),
- INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1),
- INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1),
- INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1),
- INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1),
- INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1),
- INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1),
+struct AudioProfile {
+ AudioFormat format;
+ /** List of the sample rates (in Hz) supported by the profile. */
+ vec<uint32_t> sampleRates;
+ /** List of channel masks supported by the profile. */
+ vec<AudioChannelMask> channelMasks;
};
/**
@@ -607,301 +149,58 @@
CALL_SCREEN = 4,
};
-@export(name="", value_prefix="AUDIO_DEVICE_")
-enum AudioDevice : uint32_t {
- NONE = 0x0,
- /** reserved bits */
- BIT_IN = 0x80000000,
- BIT_DEFAULT = 0x40000000,
- /** output devices */
- OUT_EARPIECE = 0x1,
- OUT_SPEAKER = 0x2,
- OUT_WIRED_HEADSET = 0x4,
- OUT_WIRED_HEADPHONE = 0x8,
- OUT_BLUETOOTH_SCO = 0x10,
- OUT_BLUETOOTH_SCO_HEADSET = 0x20,
- OUT_BLUETOOTH_SCO_CARKIT = 0x40,
- OUT_BLUETOOTH_A2DP = 0x80,
- OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
- OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
- OUT_AUX_DIGITAL = 0x400,
- OUT_HDMI = OUT_AUX_DIGITAL,
- /** uses an analog connection (multiplexed over the USB pins for instance) */
- OUT_ANLG_DOCK_HEADSET = 0x800,
- OUT_DGTL_DOCK_HEADSET = 0x1000,
- /** USB accessory mode: Android device is USB device and dock is USB host */
- OUT_USB_ACCESSORY = 0x2000,
- /** USB host mode: Android device is USB host and dock is USB device */
- OUT_USB_DEVICE = 0x4000,
- OUT_REMOTE_SUBMIX = 0x8000,
- /** Telephony voice TX path */
- OUT_TELEPHONY_TX = 0x10000,
- /** Analog jack with line impedance detected */
- OUT_LINE = 0x20000,
- /** HDMI Audio Return Channel */
- OUT_HDMI_ARC = 0x40000,
- /** S/PDIF out */
- OUT_SPDIF = 0x80000,
- /** FM transmitter out */
- OUT_FM = 0x100000,
- /** Line out for av devices */
- OUT_AUX_LINE = 0x200000,
- /** limited-output speaker device for acoustic safety */
- OUT_SPEAKER_SAFE = 0x400000,
- OUT_IP = 0x800000,
- /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
- OUT_BUS = 0x1000000,
- OUT_PROXY = 0x2000000,
- OUT_USB_HEADSET = 0x4000000,
- OUT_HEARING_AID = 0x8000000,
- OUT_ECHO_CANCELLER = 0x10000000,
- OUT_DEFAULT = BIT_DEFAULT,
- // Note that the 2.0 OUT_ALL* have been moved to helper functions
-
- /** input devices */
- IN_COMMUNICATION = BIT_IN | 0x1,
- IN_AMBIENT = BIT_IN | 0x2,
- IN_BUILTIN_MIC = BIT_IN | 0x4,
- IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
- IN_WIRED_HEADSET = BIT_IN | 0x10,
- IN_AUX_DIGITAL = BIT_IN | 0x20,
- IN_HDMI = IN_AUX_DIGITAL,
- /** Telephony voice RX path */
- IN_VOICE_CALL = BIT_IN | 0x40,
- IN_TELEPHONY_RX = IN_VOICE_CALL,
- IN_BACK_MIC = BIT_IN | 0x80,
- IN_REMOTE_SUBMIX = BIT_IN | 0x100,
- IN_ANLG_DOCK_HEADSET = BIT_IN | 0x200,
- IN_DGTL_DOCK_HEADSET = BIT_IN | 0x400,
- IN_USB_ACCESSORY = BIT_IN | 0x800,
- IN_USB_DEVICE = BIT_IN | 0x1000,
- /** FM tuner input */
- IN_FM_TUNER = BIT_IN | 0x2000,
- /** TV tuner input */
- IN_TV_TUNER = BIT_IN | 0x4000,
- /** Analog jack with line impedance detected */
- IN_LINE = BIT_IN | 0x8000,
- /** S/PDIF in */
- IN_SPDIF = BIT_IN | 0x10000,
- IN_BLUETOOTH_A2DP = BIT_IN | 0x20000,
- IN_LOOPBACK = BIT_IN | 0x40000,
- IN_IP = BIT_IN | 0x80000,
- /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
- IN_BUS = BIT_IN | 0x100000,
- IN_PROXY = BIT_IN | 0x1000000,
- IN_USB_HEADSET = BIT_IN | 0x2000000,
- IN_BLUETOOTH_BLE = BIT_IN | 0x4000000,
- IN_ECHO_REFERENCE = BIT_IN | 0x10000000,
- IN_DEFAULT = BIT_IN | BIT_DEFAULT,
-
- // Note that the 2.0 IN_ALL* have been moved to helper functions
-};
-
/**
- * IEEE 802 MAC address.
+ * Audio device specifies type (or category) of audio I/O device
+ * (e.g. speaker or headphones).
+ * See 'audioDevice' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-typedef uint8_t[6] MacAddress;
+typedef string AudioDevice;
/**
* Specifies a device address in case when several devices of the same type
* can be connected (e.g. BT A2DP, USB).
*/
struct DeviceAddress {
- AudioDevice device; // discriminator
- union Address {
- MacAddress mac; // used for BLUETOOTH_A2DP_*
- uint8_t[4] ipv4; // used for IP
+ /** The type of the device. */
+ AudioDevice deviceType;
+ safe_union Address {
+ /**
+ * The address may be left unspecified if 'device' specifies
+ * a physical device unambiguously.
+ */
+ Monostate unspecified;
+ /** IEEE 802 MAC address. Set for Bluetooth devices. */
+ uint8_t[6] mac;
+ /** IPv4 Address. Set for IPv4 devices. */
+ uint8_t[4] ipv4;
+ /** IPv6 Address. Set for IPv6 devices. */
+ uint16_t[8] ipv6;
+ /** PCI bus Address. Set for USB devices. */
struct Alsa {
int32_t card;
int32_t device;
- } alsa; // used for USB_*
+ } 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;
- /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */
- string busAddress;
- /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */
- string rSubmixAddress;
};
/**
- * The audio output flags serve two purposes:
- *
- * - when an AudioTrack is created they indicate a "wish" to be connected to an
- * output stream with attributes corresponding to the specified flags;
- *
- * - when present in an output profile descriptor listed for a particular audio
- * hardware module, they indicate that an output stream can be opened that
- * supports the attributes indicated by the flags.
- *
- * The audio policy manager will try to match the flags in the request
- * (when getOuput() is called) to an available output stream.
+ * Audio usage specifies the intended use case for the sound being played.
+ * See 'audioUsage' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
-enum AudioOutputFlag : int32_t {
- NONE = 0x0, // no attributes
- DIRECT = 0x1, // this output directly connects a track
- // to one output stream: no software mixer
- PRIMARY = 0x2, // this output is the primary output of the device. It is
- // unique and must be present. It is opened by default and
- // receives routing, audio mode and volume controls related
- // to voice calls.
- FAST = 0x4, // output supports "fast tracks", defined elsewhere
- DEEP_BUFFER = 0x8, // use deep audio buffers
- COMPRESS_OFFLOAD = 0x10, // offload playback of compressed streams to
- // hardware codec
- NON_BLOCKING = 0x20, // use non-blocking write
- HW_AV_SYNC = 0x40, // output uses a hardware A/V sync
- TTS = 0x80, // output for streams transmitted through speaker at a
- // sample rate high enough to accommodate lower-range
- // ultrasonic p/b
- RAW = 0x100, // minimize signal processing
- SYNC = 0x200, // synchronize I/O streams
- IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
- // data bursts, not PCM.
- DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs
- // to pass through compress path for DSP post proc.
- MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
- VOIP_RX = 0x8000, // preferred output for VoIP calls.
- /** preferred output for call music */
- INCALL_MUSIC = 0x10000,
-};
+typedef string AudioUsage;
/**
- * The audio input flags are analogous to audio output flags.
- * Currently they are used only when an AudioRecord is created,
- * to indicate a preference to be connected to an input stream with
- * attributes corresponding to the specified flags.
+ * Audio content type expresses the general category of the content.
+ * See 'audioContentType' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
-enum AudioInputFlag : int32_t {
- NONE = 0x0, // no attributes
- FAST = 0x1, // prefer an input that supports "fast tracks"
- HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
- RAW = 0x4, // minimize signal processing
- SYNC = 0x8, // synchronize I/O streams
- MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
- VOIP_TX = 0x20, // preferred input for VoIP calls.
- HW_AV_SYNC = 0x40, // input connected to an output that uses a hardware A/V sync
- DIRECT = 0x80, // for acquiring encoded streams
-};
-
-@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
-enum AudioUsage : int32_t {
- // These values must kept in sync with
- // frameworks/base/media/java/android/media/AudioAttributes.java
- // Note that not all framework values are exposed
- /**
- * Usage value to use when the usage is unknown.
- */
- UNKNOWN = 0,
- /**
- * Usage value to use when the usage is media, such as music, or movie
- * soundtracks.
- */
- MEDIA = 1,
- /**
- * Usage value to use when the usage is voice communications, such as
- * telephony or VoIP.
- */
- VOICE_COMMUNICATION = 2,
- /**
- * Usage value to use when the usage is in-call signalling, such as with
- * a "busy" beep, or DTMF tones.
- */
- VOICE_COMMUNICATION_SIGNALLING = 3,
- /**
- * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
- */
- ALARM = 4,
- /**
- * Usage value to use when the usage is a generic notification.
- */
- NOTIFICATION = 5,
- /**
- * Usage value to use when the usage is telephony ringtone.
- */
- NOTIFICATION_TELEPHONY_RINGTONE = 6,
- /**
- * Usage value to use when the usage is for accessibility, such as with
- * a screen reader.
- */
- ASSISTANCE_ACCESSIBILITY = 11,
- /**
- * Usage value to use when the usage is driving or navigation directions.
- */
- ASSISTANCE_NAVIGATION_GUIDANCE = 12,
- /**
- * Usage value to use when the usage is sonification, such as with user
- * interface sounds.
- */
- ASSISTANCE_SONIFICATION = 13,
- /**
- * Usage value to use when the usage is for game audio.
- */
- GAME = 14,
- /**
- * Usage value to use when feeding audio to the platform and replacing
- * "traditional" audio source, such as audio capture devices.
- */
- VIRTUAL_SOURCE = 15,
- /**
- * Usage value to use for audio responses to user queries, audio
- * instructions or help utterances.
- */
- ASSISTANT = 16,
- /**
- * Usage value to use for assistant voice interaction with remote caller
- * on Cell and VoIP calls.
- */
- CALL_ASSISTANT = 17,
- /**
- * Usage value to use when the usage is an emergency.
- */
- EMERGENCY = 1000,
- /**
- * Usage value to use when the usage is a safety sound.
- */
- SAFETY = 1001,
- /**
- * Usage value to use when the usage is a vehicle status.
- */
- VEHICLE_STATUS = 1002,
- /**
- * Usage value to use when the usage is an announcement.
- */
- ANNOUNCEMENT = 1003,
-};
-
-/** Type of audio generated by an application. */
-@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_")
-enum AudioContentType : uint32_t {
- // Do not change these values without updating their counterparts
- // in frameworks/base/media/java/android/media/AudioAttributes.java
- /**
- * Content type value to use when the content type is unknown, or other than
- * the ones defined.
- */
- UNKNOWN = 0,
- /**
- * Content type value to use when the content type is speech.
- */
- SPEECH = 1,
- /**
- * Content type value to use when the content type is music.
- */
- MUSIC = 2,
- /**
- * Content type value to use when the content type is a soundtrack,
- * typically accompanying a movie or TV program.
- */
- MOVIE = 3,
- /**
- * Content type value to use when the content type is a sound used to
- * accompany a user action, such as a beep or sound effect expressing a key
- * click, or event, such as the type of a sound for a bonus being received
- * in a game. These sounds are mostly synthesized or short Foley sounds.
- */
- SONIFICATION = 4,
-};
+typedef string AudioContentType;
/** Encapsulation mode used for sending audio compressed data. */
@export(name="audio_encapsulation_mode_t", value_prefix="AUDIO_ENCAPSULATION_MODE_")
@@ -926,9 +225,7 @@
* Additional information about the stream passed to hardware decoders.
*/
struct AudioOffloadInfo {
- uint32_t sampleRateHz;
- bitfield<AudioChannelMask> channelMask;
- AudioFormat format;
+ AudioConfigBase base;
AudioStreamType streamType;
uint32_t bitRatePerSecond;
int64_t durationMicroseconds; // -1 if unknown
@@ -946,9 +243,7 @@
* Commonly used audio stream configuration parameters.
*/
struct AudioConfig {
- uint32_t sampleRateHz;
- bitfield<AudioChannelMask> channelMask;
- AudioFormat format;
+ AudioConfigBase base;
AudioOffloadInfo offloadInfo;
uint64_t frameCount;
};
@@ -985,8 +280,7 @@
safe_union Destination {
Monostate unspecified;
DeviceAddress device;
- };
- Destination destination;
+ } destination;
};
/** Metadatas of the sink of a StreamIn. */
@@ -994,7 +288,6 @@
vec<RecordTrackMetadata> tracks;
};
-
/*
*
* Volume control
@@ -1003,21 +296,18 @@
/**
* Type of gain control exposed by an audio port.
+ * See 'audioGainMode' in audio_policy_configuration.xsd for the
+ * list of allowed values.
*/
-@export(name="", value_prefix="AUDIO_GAIN_MODE_")
-enum AudioGainMode : uint32_t {
- JOINT = 0x1, // supports joint channel gain control
- CHANNELS = 0x2, // supports separate channel gain control
- RAMP = 0x4 // supports gain ramps
-};
+typedef string AudioGainMode;
/**
* An audio_gain struct is a representation of a gain stage.
* A gain stage is always attached to an audio port.
*/
struct AudioGain {
- bitfield<AudioGainMode> mode;
- bitfield<AudioChannelMask> channelMask; // channels which gain an be controlled
+ 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
@@ -1032,11 +322,9 @@
*/
struct AudioGainConfig {
int32_t index; // index of the corresponding AudioGain in AudioPort.gains
- AudioGainMode mode;
+ vec<AudioGainMode> mode; // modes of operation
AudioChannelMask channelMask; // channels which gain value follows
/**
- * 4 = sizeof(AudioChannelMask),
- * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
* 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).
@@ -1060,132 +348,78 @@
* the interface.
*/
-/** Audio port role: either source or sink */
-@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
-enum AudioPortRole : int32_t {
- NONE,
- SOURCE,
- SINK,
-};
-
/**
- * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
- * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ * A helper aggregate structure providing parameters that depend on the
+ * port role.
*/
-@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
-enum AudioPortType : int32_t {
- NONE,
- DEVICE,
- MIX,
- SESSION,
-};
-
-/**
- * Extension for audio port configuration structure when the audio port is a
- * hardware device.
- */
-struct AudioPortConfigDeviceExt {
- AudioModuleHandle hwModule; // module the device is attached to
- AudioDevice type; // device type (e.g OUT_SPEAKER)
- uint8_t[32] address; // device address. "" if N/A
-};
-
-/**
- * Extension for audio port configuration structure when the audio port is an
- * audio session.
- */
-struct AudioPortConfigSessionExt {
+safe_union AudioPortExtendedInfo {
+ /** Set when no information is provided. */
+ Monostate unspecified;
+ /** Set when the audio port is an audio device. */
+ DeviceAddress device;
+ /** Set when the audio port is a mix. The handle is of a stream. */
+ struct AudioPortMixExt {
+ /** I/O handle of the input/output stream. */
+ AudioIoHandle ioHandle;
+ safe_union UseCase {
+ /** Specified when the port is in the SOURCE role. */
+ AudioStreamType stream;
+ /** Specified when the port is in the SINK role. */
+ AudioSource source;
+ } useCase;
+ } mix;
+ /** Set when the audio port is an audio session. */
AudioSession session;
};
/**
- * Flags indicating which fields are to be considered in AudioPortConfig.
- */
-@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
-enum AudioPortConfigMask : uint32_t {
- SAMPLE_RATE = 0x1,
- CHANNEL_MASK = 0x2,
- FORMAT = 0x4,
- GAIN = 0x8,
-};
-
-/**
* Audio port configuration structure used to specify a particular configuration
* of an audio port.
*/
struct AudioPortConfig {
+ /**
+ * The 'id' field is set when it is needed to select the port and
+ * apply new configuration for it.
+ */
AudioPortHandle id;
- bitfield<AudioPortConfigMask> configMask;
- uint32_t sampleRateHz;
- bitfield<AudioChannelMask> channelMask;
- AudioFormat format;
- AudioGainConfig gain;
- AudioPortType type; // type is used as a discriminator for Ext union
- AudioPortRole role; // role is used as a discriminator for UseCase union
- union Ext {
- AudioPortConfigDeviceExt device;
- struct AudioPortConfigMixExt {
- AudioModuleHandle hwModule; // module the stream is attached to
- AudioIoHandle ioHandle; // I/O handle of the input/output stream
- union UseCase {
- AudioStreamType stream;
- AudioSource source;
- } useCase;
- } mix;
- AudioPortConfigSessionExt session;
- } ext;
+ /**
+ * Basic parameters: sampling rate, format, channel mask. Only some of the
+ * parameters (or none) may be set. See the documentation of the
+ * AudioConfigBase struct.
+ */
+ AudioConfigBase config;
+ /** Associated gain control. */
+ safe_union OptionalGain {
+ Monostate unspecified;
+ AudioGainConfig config;
+ } gain;
+ /** Parameters that depend on the actual port role. */
+ AudioPortExtendedInfo ext;
};
/**
- * Extension for audio port structure when the audio port is a hardware device.
+ * Audio port structure describes the capabilities of an audio port
+ * as well as its current configuration.
*/
-struct AudioPortDeviceExt {
- AudioModuleHandle hwModule; // module the device is attached to
- AudioDevice type;
- /** 32 byte string identifying the port. */
- uint8_t[32] address;
-};
-
-/**
- * Latency class of the audio mix.
- */
-@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
-enum AudioMixLatencyClass : int32_t {
- LOW,
- NORMAL
-};
-
-struct AudioPortMixExt {
- AudioModuleHandle hwModule; // module the stream is attached to
- AudioIoHandle ioHandle; // I/O handle of the stream
- AudioMixLatencyClass latencyClass;
-};
-
-/**
- * Extension for audio port structure when the audio port is an audio session.
- */
-struct AudioPortSessionExt {
- AudioSession session;
-};
-
struct AudioPort {
+ /**
+ * Unique identifier of the port within this HAL service. When calling
+ * from the client side functions like IDevice.getAudioPort is it allowed
+ * to only specify the 'id' and leave the other fields unspecified.
+ */
AudioPortHandle id;
- AudioPortRole role;
+ /**
+ * Human-readable name describing the function of the port.
+ * E.g. "telephony_tx" or "fm_tuner".
+ */
string name;
- vec<uint32_t> sampleRates;
- vec<bitfield<AudioChannelMask>> channelMasks;
- vec<AudioFormat> formats;
+ /** List of audio profiles supported by the port. */
+ vec<AudioProfile> profiles;
+ /** List of gain controls attached to the port. */
vec<AudioGain> gains;
- AudioPortConfig activeConfig; // current audio port configuration
- AudioPortType type; // type is used as a discriminator
- union Ext {
- AudioPortDeviceExt device;
- AudioPortMixExt mix;
- AudioPortSessionExt session;
- } ext;
-};
-
-struct ThreadInfo {
- int64_t pid;
- int64_t tid;
+ /**
+ * Current configuration of the audio port, may have all the fields left
+ * unspecified.
+ */
+ AudioPortConfig activeConfig;
};
diff --git a/audio/common/all-versions/default/VersionUtils.h b/audio/common/all-versions/default/VersionUtils.h
index e7755b1..9bfca0c 100644
--- a/audio/common/all-versions/default/VersionUtils.h
+++ b/audio/common/all-versions/default/VersionUtils.h
@@ -31,7 +31,7 @@
typedef common::CPP_VERSION::AudioChannelMask AudioChannelBitfield;
typedef common::CPP_VERSION::AudioOutputFlag AudioOutputFlagBitfield;
typedef common::CPP_VERSION::AudioInputFlag AudioInputFlagBitfield;
-#elif MAJOR_VERSION >= 4
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
typedef hidl_bitfield<common::CPP_VERSION::AudioDevice> AudioDeviceBitfield;
typedef hidl_bitfield<common::CPP_VERSION::AudioChannelMask> AudioChannelBitfield;
typedef hidl_bitfield<common::CPP_VERSION::AudioOutputFlag> AudioOutputFlagBitfield;
diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index eddff55..0b6ad80 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -31,7 +31,7 @@
// HAL assumes that the address is NUL-terminated.
char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
memset(halAddress, 0, sizeof(halAddress));
- uint32_t halDevice = static_cast<uint32_t>(address.device);
+ audio_devices_t halDevice = static_cast<audio_devices_t>(address.device);
if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index b0e72d9..907acd7 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -43,8 +43,10 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
+#if MAJOR_VERSION <= 6
using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield;
using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield;
+#endif
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::CPP_VERSION;
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 b0eb2e0..2466fd1 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,6 +16,13 @@
#include "AudioPrimaryHidlHalTest.h"
+#if MAJOR_VERSION >= 7
+#include <audio_policy_configuration_V7_0.h>
+#include <xsdc/XsdcSupport.h>
+
+using android::xsdc_enum_range;
+#endif
+
TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
doc::test("Calling openDevice(\"primary\") should return the primary device.");
if (getDeviceName() != DeviceManager::kPrimaryDevice) {
@@ -53,14 +60,29 @@
"Make sure getMicrophones always succeeds"
"and getActiveMicrophones always succeeds when recording from these microphones.");
AudioConfig config{};
+#if MAJOR_VERSION <= 6
config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO);
config.sampleRateHz = 8000;
config.format = AudioFormat::PCM_16_BIT;
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.sampleRateHz = 8000;
+ config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+ hidl_vec<hidl_string> flags;
+ const SinkMetadata initMetadata = {
+ {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_MIC), .gain = 1}}};
+#endif
EventFlag* efGroup;
for (auto microphone : microphones) {
+#if MAJOR_VERSION <= 6
if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) {
+#elif MAJOR_VERSION >= 7
+ if (xsd::stringToAudioDevice(microphone.deviceAddress.deviceType) !=
+ xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC) {
+#endif
continue;
}
sp<IStreamIn> stream;
@@ -81,16 +103,16 @@
size_t frameSize = stream->getFrameSize();
size_t frameCount = stream->getBufferSize() / frameSize;
ASSERT_OK(stream->prepareForReading(
- frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto&) {
- readRes = r;
- if (readRes == Result::OK) {
- commandMQ.reset(new CommandMQ(c));
- dataMQ.reset(new DataMQ(d));
- if (dataMQ->isValid() && dataMQ->getEventFlagWord()) {
- EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup);
+ frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto) {
+ readRes = r;
+ if (readRes == Result::OK) {
+ commandMQ.reset(new CommandMQ(c));
+ dataMQ.reset(new DataMQ(d));
+ if (dataMQ->isValid() && dataMQ->getEventFlagWord()) {
+ EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup);
+ }
}
- }
- }));
+ }));
ASSERT_OK(readRes);
IStreamIn::ReadParameters params;
params.command = IStreamIn::ReadCommand::READ;
@@ -116,13 +138,24 @@
TEST_P(AudioHidlDeviceTest, SetConnectedState) {
doc::test("Check that the HAL can be notified of device connection and deconnection");
+#if MAJOR_VERSION <= 6
using AD = AudioDevice;
for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+#elif MAJOR_VERSION >= 7
+ using AD = xsd::AudioDevice;
+ for (auto deviceType :
+ {toString(AD::AUDIO_DEVICE_OUT_HDMI), toString(AD::AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ toString(AD::AUDIO_DEVICE_IN_USB_HEADSET)}) {
+#endif
SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType));
for (bool state : {true, false}) {
SCOPED_TRACE("state=" + ::testing::PrintToString(state));
DeviceAddress address = {};
+#if MAJOR_VERSION <= 6
address.device = deviceType;
+#elif MAJOR_VERSION >= 7
+ address.deviceType = deviceType;
+#endif
auto ret = getDevice()->setConnectedState(address, state);
ASSERT_TRUE(ret.isOk());
if (ret == Result::NOT_SUPPORTED) {
@@ -148,7 +181,11 @@
}
// The stream was constructed with one device, thus getDevices must only return one
ASSERT_EQ(1U, devices.size());
+#if MAJOR_VERSION <= 6
AudioDevice device = devices[0].device;
+#elif MAJOR_VERSION >= 7
+ auto device = devices[0].deviceType;
+#endif
ASSERT_TRUE(device == expectedDevice)
<< "Expected: " << ::testing::PrintToString(expectedDevice)
<< "\n Actual: " << ::testing::PrintToString(device);
@@ -156,12 +193,22 @@
TEST_IO_STREAM(GetDevices, "Check that the stream device == the one it was opened with",
areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+#if MAJOR_VERSION <= 6
: testGetDevices(stream.get(), address.device))
+#elif MAJOR_VERSION >= 7
+ : testGetDevices(stream.get(), address.deviceType))
+#endif
static void testSetDevices(IStream* stream, const DeviceAddress& address) {
DeviceAddress otherAddress = address;
+#if MAJOR_VERSION <= 6
otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
: AudioDevice::IN_BUILTIN_MIC;
+#elif MAJOR_VERSION >= 7
+ otherAddress.deviceType = xsd::isOutputDevice(address.deviceType)
+ ? toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER)
+ : toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC);
+#endif
EXPECT_RESULT(okOrNotSupported, stream->setDevices({otherAddress}));
ASSERT_RESULT(okOrNotSupported,
@@ -186,11 +233,19 @@
TEST_P(InputStreamTest, updateSinkMetadata) {
doc::test("The HAL should not crash on metadata change");
+#if MAJOR_VERSION <= 6
hidl_enum_range<AudioSource> range;
+#elif MAJOR_VERSION >= 7
+ xsdc_enum_range<audio::policy::configuration::V7_0::AudioSource> range;
+#endif
// Test all possible track configuration
- for (AudioSource source : range) {
+ for (auto source : range) {
for (float volume : {0.0, 0.5, 1.0}) {
+#if MAJOR_VERSION <= 6
const SinkMetadata metadata = {{{.source = source, .gain = volume}}};
+#elif MAJOR_VERSION >= 7
+ const SinkMetadata metadata = {{{.source = toString(source), .gain = volume}}};
+#endif
ASSERT_OK(stream->updateSinkMetadata(metadata))
<< "source=" << toString(source) << ", volume=" << volume;
}
@@ -213,13 +268,22 @@
TEST_P(OutputStreamTest, updateSourceMetadata) {
doc::test("The HAL should not crash on metadata change");
+#if MAJOR_VERSION <= 6
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;
+#endif
// Test all possible track configuration
for (auto usage : usageRange) {
for (auto content : contentRange) {
for (float volume : {0.0, 0.5, 1.0}) {
+#if MAJOR_VERSION <= 6
const SourceMetadata metadata = {{{usage, content, volume}}};
+#elif MAJOR_VERSION >= 7
+ const SourceMetadata metadata = {{{toString(usage), toString(content), volume}}};
+#endif
ASSERT_OK(stream->updateSourceMetadata(metadata))
<< "usage=" << toString(usage) << ", content=" << toString(content)
<< ", volume=" << volume;
@@ -227,12 +291,26 @@
}
}
+ // clang-format off
// Set many track of different configuration
ASSERT_OK(stream->updateSourceMetadata(
+#if MAJOR_VERSION <= 6
{{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1},
{AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0},
{AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0},
- {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}));
+ {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}
+#elif MAJOR_VERSION >= 7
+ {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), 0.1},
+ {toString(xsd::AudioUsage::AUDIO_USAGE_VOICE_COMMUNICATION),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SPEECH), 1.0},
+ {toString(xsd::AudioUsage::AUDIO_USAGE_ALARM),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SONIFICATION), 0.0},
+ {toString(xsd::AudioUsage::AUDIO_USAGE_ASSISTANT),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_UNKNOWN), 0.3}}}
+#endif
+ ));
+ // clang-format on
// Set no metadata as if all stream track had stopped
ASSERT_OK(stream->updateSourceMetadata({}));
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
index 7a52d0e..81a1f7b 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
@@ -56,6 +56,7 @@
}
};
+#if MAJOR_VERSION <= 6
struct GetSupported {
static auto getFormat(IStream* stream) {
auto ret = stream->getFormat();
@@ -80,7 +81,7 @@
EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
return Result::OK;
}
-#elif MAJOR_VERSION >= 6
+#else // MAJOR_VERSION == 6
static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
Result res;
EXPECT_OK(stream->getSupportedFormats(returnIn(res, capabilities)));
@@ -88,6 +89,7 @@
}
#endif
};
+#endif // MAJOR_VERSION <= 6
template <class T>
auto dump(T t, hidl_handle handle) {
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 54d4bbd..bd8de2d 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -17,6 +17,7 @@
// pull in all the <= 5.0 tests
#include "5.0/AudioPrimaryHidlHalTest.cpp"
+#if MAJOR_VERSION <= 6
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
static std::vector<DeviceConfigParameter> parameters = [] {
std::vector<DeviceConfigParameter> result;
@@ -28,8 +29,8 @@
const auto& channels = profile->getChannels();
const auto& sampleRates = profile->getSampleRates();
auto configs = ConfigHelper::combineAudioConfig(
- vector<audio_channel_mask_t>(channels.begin(), channels.end()),
- vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+ std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+ std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
profile->getFormat());
auto flags = ioProfile->getFlags();
for (auto& config : configs) {
@@ -46,8 +47,8 @@
config.offloadInfo.bufferSize = 256; // arbitrary value
config.offloadInfo.usage = AudioUsage::MEDIA;
result.emplace_back(device, config,
- AudioOutputFlag(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
- AUDIO_OUTPUT_FLAG_DIRECT));
+ AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
+ AudioOutputFlag::DIRECT));
} else {
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag
flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
@@ -74,8 +75,8 @@
const auto& channels = profile->getChannels();
const auto& sampleRates = profile->getSampleRates();
auto configs = ConfigHelper::combineAudioConfig(
- vector<audio_channel_mask_t>(channels.begin(), channels.end()),
- vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+ std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+ std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
profile->getFormat());
for (const auto& config : configs) {
result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
@@ -87,13 +88,22 @@
}();
return parameters;
}
+#endif // MAJOR_VERSION <= 6
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
doc::test("Verify that a device can't be closed if there are streams opened");
+#if MAJOR_VERSION <= 6
DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
- AudioConfig config{};
- auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
+ auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+#elif MAJOR_VERSION >= 7
+ DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
+ SourceMetadata initMetadata = {
+ {{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), 1 /* gain */}}};
+ hidl_vec<AudioInOutFlag> flags;
+#endif
+ AudioConfig config{};
sp<IStreamOut> stream;
StreamHelper<IStreamOut> helper(stream);
AudioConfig suggestedConfig{};
@@ -111,14 +121,20 @@
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
doc::test("Verify that a device can't be closed if there are streams opened");
- auto module = getCachedPolicyConfig().getModuleFromName(getDeviceName());
- if (module->getInputProfiles().empty()) {
+ if (!getCachedPolicyConfig().haveInputProfilesInModule(getDeviceName())) {
GTEST_SKIP() << "Device doesn't have input profiles";
}
+#if MAJOR_VERSION <= 6
DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
- AudioConfig config{};
- auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
+ auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+#elif MAJOR_VERSION >= 7
+ DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
+ SinkMetadata initMetadata = {
+ {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_MIC), .gain = 1}}};
+ hidl_vec<AudioInOutFlag> flags;
+#endif
+ AudioConfig config{};
sp<IStreamIn> stream;
StreamHelper<IStreamIn> helper(stream);
AudioConfig suggestedConfig{};
@@ -137,9 +153,8 @@
TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
AudioPatchHandle ignored;
- ASSERT_OK(getDevice()->updateAudioPatch(
- static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE),
- hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
+ ASSERT_OK(getDevice()->updateAudioPatch(AudioPatchHandle{}, hidl_vec<AudioPortConfig>(),
+ hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
}
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 33efa6f..63eaea8 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -16,3 +16,101 @@
// pull in all the <= 6.0 tests
#include "6.0/AudioPrimaryHidlHalTest.cpp"
+
+static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannelMask> channelMasks,
+ std::vector<int64_t> sampleRates,
+ const std::string& format) {
+ std::vector<AudioConfig> configs;
+ configs.reserve(channelMasks.size() * sampleRates.size());
+ for (auto channelMask : channelMasks) {
+ for (auto sampleRate : sampleRates) {
+ AudioConfig config{};
+ // leave offloadInfo to 0
+ config.base.channelMask.resize(1);
+ config.base.channelMask[0] = toString(channelMask);
+ config.base.sampleRateHz = sampleRate;
+ config.base.format = format;
+ configs.push_back(config);
+ }
+ }
+ return configs;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
+ static std::vector<DeviceConfigParameter> parameters = [] {
+ std::vector<DeviceConfigParameter> result;
+ const std::vector<AudioInOutFlag> offloadFlags = {
+ toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
+ for (const auto& device : getDeviceParameters()) {
+ auto module =
+ getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+ for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+ if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
+ auto xsdFlags = mixPort.getFlags();
+ const bool isOffload =
+ std::find(xsdFlags.begin(), xsdFlags.end(),
+ xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
+ xsdFlags.end();
+ std::vector<AudioInOutFlag> flags;
+ if (!isOffload) {
+ for (auto flag : xsdFlags) {
+ if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
+ flags.push_back(toString(flag));
+ }
+ }
+ } else {
+ flags = offloadFlags;
+ }
+ for (const auto& profile : mixPort.getProfile()) {
+ auto configs =
+ combineAudioConfig(profile.getChannelMasks(),
+ profile.getSamplingRates(), profile.getFormat());
+ for (auto& config : configs) {
+ // Some combinations of flags declared in the config file require special
+ // treatment.
+ if (isOffload) {
+ config.offloadInfo.base = config.base;
+ config.offloadInfo.streamType =
+ toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
+ config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
+ config.offloadInfo.bitRatePerSecond = 320;
+ config.offloadInfo.durationMicroseconds = -1;
+ config.offloadInfo.bitWidth = 16;
+ config.offloadInfo.bufferSize = 256; // arbitrary value
+ }
+ result.emplace_back(device, config, flags);
+ }
+ }
+ }
+ }
+ return result;
+ }();
+ return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
+ static std::vector<DeviceConfigParameter> parameters = [] {
+ std::vector<DeviceConfigParameter> result;
+ for (const auto& device : getDeviceParameters()) {
+ auto module =
+ getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+ for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+ if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
+ std::vector<AudioInOutFlag> flags;
+ std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), flags.begin(),
+ [](auto flag) { return toString(flag); });
+ for (const auto& profile : mixPort.getProfile()) {
+ auto configs =
+ combineAudioConfig(profile.getChannelMasks(),
+ profile.getSamplingRates(), profile.getFormat());
+ for (const auto& config : configs) {
+ result.emplace_back(device, config, flags);
+ }
+ }
+ }
+ }
+ return result;
+ }();
+ return parameters;
+}
diff --git a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
new file mode 100644
index 0000000..d790b34
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.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.
+ */
+
+#pragma once
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
+
+namespace xsd {
+using Module = Modules::Module;
+}
+
+class PolicyConfig {
+ public:
+ explicit PolicyConfig(const std::string& configFileName)
+ : mConfigFileName{configFileName},
+ mFilePath{findExistingConfigurationFile(mConfigFileName)},
+ mConfig{xsd::read(mFilePath.c_str())} {
+ if (mConfig) {
+ mStatus = OK;
+ mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice);
+ for (const auto& module : mConfig->getFirstModules()->get_module()) {
+ auto attachedDevices = module.getFirstAttachedDevices()->getItem();
+ if (!attachedDevices.empty()) {
+ mModulesWithDevicesNames.insert(module.getName());
+ }
+ }
+ }
+ }
+ status_t getStatus() const { return mStatus; }
+ std::string getError() const {
+ if (mFilePath.empty()) {
+ return std::string{"Could not find "} + mConfigFileName +
+ " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
+ } else {
+ return "Invalid config file: " + mFilePath;
+ }
+ }
+ const std::string& getFilePath() const { return mFilePath; }
+ const xsd::Module* getModuleFromName(const std::string& name) const {
+ if (mConfig) {
+ for (const auto& module : mConfig->getFirstModules()->get_module()) {
+ if (module.getName() == name) return &module;
+ }
+ }
+ return nullptr;
+ }
+ const xsd::Module* getPrimaryModule() const { return mPrimaryModule; }
+ const std::set<std::string>& getModulesWithDevicesNames() const {
+ return mModulesWithDevicesNames;
+ }
+ bool haveInputProfilesInModule(const std::string& name) const {
+ auto module = getModuleFromName(name);
+ for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+ if (mixPort.getRole() == xsd::Role::sink) return true;
+ }
+ return false;
+ }
+
+ private:
+ static std::string findExistingConfigurationFile(const std::string& fileName) {
+ for (const auto& location : android::audio_get_configuration_paths()) {
+ std::string path = location + '/' + fileName;
+ if (access(path.c_str(), F_OK) == 0) {
+ return path;
+ }
+ }
+ return std::string{};
+ }
+
+ const std::string mConfigFileName;
+ const std::string mFilePath;
+ std::optional<xsd::AudioPolicyConfiguration> mConfig;
+ status_t mStatus = NO_INIT;
+ const xsd::Module* mPrimaryModule;
+ std::set<std::string> mModulesWithDevicesNames;
+};
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 6ac9b20..c7bfe08 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,9 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"android.hardware.audio.common.test.utility",
- "libaudiofoundation",
- "libaudiopolicycomponents",
- "libmedia_helper",
"libxml2",
],
shared_libs: [
@@ -44,6 +41,9 @@
"2.0/AudioPrimaryHidlHalTest.cpp",
],
static_libs: [
+ "libaudiofoundation",
+ "libaudiopolicycomponents",
+ "libmedia_helper",
"android.hardware.audio@2.0",
"android.hardware.audio.common@2.0",
],
@@ -67,6 +67,9 @@
"4.0/AudioPrimaryHidlHalTest.cpp",
],
static_libs: [
+ "libaudiofoundation",
+ "libaudiopolicycomponents",
+ "libmedia_helper",
"android.hardware.audio@4.0",
"android.hardware.audio.common@4.0",
],
@@ -90,6 +93,9 @@
"5.0/AudioPrimaryHidlHalTest.cpp",
],
static_libs: [
+ "libaudiofoundation",
+ "libaudiopolicycomponents",
+ "libmedia_helper",
"android.hardware.audio@5.0",
"android.hardware.audio.common@5.0",
],
@@ -113,6 +119,9 @@
"6.0/AudioPrimaryHidlHalTest.cpp",
],
static_libs: [
+ "libaudiofoundation",
+ "libaudiopolicycomponents",
+ "libmedia_helper",
"android.hardware.audio@6.0",
"android.hardware.audio.common@6.0",
],
@@ -130,7 +139,6 @@
}
cc_test {
- enabled: false,
name: "VtsHalAudioV7_0TargetTest",
defaults: ["VtsHalAudioTargetTest_defaults"],
srcs: [
@@ -139,6 +147,7 @@
static_libs: [
"android.hardware.audio@7.0",
"android.hardware.audio.common@7.0",
+ "android.hardware.audio.common@7.0-enums",
],
cflags: [
"-DMAJOR_VERSION=7",
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 01bdd69..0a9d5ee 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -42,8 +42,11 @@
#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
#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>
+#endif
-#include <Serializer.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
#include <hidl/GtestPrinter.h>
@@ -63,14 +66,6 @@
#include "4.0/AudioPrimaryHidlHalUtils.h"
#endif
-using std::initializer_list;
-using std::list;
-using std::string;
-using std::to_string;
-using std::vector;
-
-using ::android::AudioPolicyConfig;
-using ::android::HwModule;
using ::android::NO_INIT;
using ::android::OK;
using ::android::sp;
@@ -93,6 +88,12 @@
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::common::test::utility;
using namespace ::android::hardware::audio::CPP_VERSION;
+#if MAJOR_VERSION >= 7
+// Make an alias for enumerations generated from the APM config XSD.
+namespace xsd {
+using namespace ::audio::policy::configuration::CPP_VERSION;
+}
+#endif
// Typical accepted results from interface methods
static auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
@@ -103,8 +104,12 @@
static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
-#define AUDIO_PRIMARY_HIDL_HAL_TEST
#include "DeviceManager.h"
+#if MAJOR_VERSION <= 6
+#include "PolicyConfig.h"
+#elif MAJOR_VERSION >= 7
+#include "7.0/PolicyConfig.h"
+#endif
class HidlTest : public ::testing::Test {
public:
@@ -136,83 +141,16 @@
////////////////////////// Audio policy configuration ////////////////////////
//////////////////////////////////////////////////////////////////////////////
-static constexpr char kConfigFileName[] = "audio_policy_configuration.xml";
-
// Stringify the argument.
#define QUOTE(x) #x
#define STRINGIFY(x) QUOTE(x)
-struct PolicyConfigData {
- android::HwModuleCollection hwModules;
- android::DeviceVector availableOutputDevices;
- android::DeviceVector availableInputDevices;
- sp<android::DeviceDescriptor> defaultOutputDevice;
-};
-
-class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig {
- public:
- PolicyConfig()
- : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
- defaultOutputDevice) {
- for (const auto& location : android::audio_get_configuration_paths()) {
- std::string path = location + '/' + kConfigFileName;
- if (access(path.c_str(), F_OK) == 0) {
- mFilePath = path;
- break;
- }
- }
- mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
- if (mStatus == OK) {
- mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice);
- // Available devices are not 'attached' to modules at this moment.
- // Need to go over available devices and find their module.
- for (const auto& device : availableOutputDevices) {
- for (const auto& module : hwModules) {
- if (module->getDeclaredDevices().indexOf(device) >= 0) {
- mModulesWithDevicesNames.insert(module->getName());
- break;
- }
- }
- }
- for (const auto& device : availableInputDevices) {
- for (const auto& module : hwModules) {
- if (module->getDeclaredDevices().indexOf(device) >= 0) {
- mModulesWithDevicesNames.insert(module->getName());
- break;
- }
- }
- }
- }
- }
- status_t getStatus() const { return mStatus; }
- std::string getError() const {
- if (mFilePath.empty()) {
- return std::string{"Could not find "} + kConfigFileName +
- " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
- } else {
- return "Invalid config file: " + mFilePath;
- }
- }
- const std::string& getFilePath() const { return mFilePath; }
- sp<const HwModule> getModuleFromName(const std::string& name) const {
- return getHwModules().getModuleFromName(name.c_str());
- }
- sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; }
- const std::set<std::string>& getModulesWithDevicesNames() const {
- return mModulesWithDevicesNames;
- }
-
- private:
- status_t mStatus = NO_INIT;
- std::string mFilePath;
- sp<HwModule> mPrimaryModule = nullptr;
- std::set<std::string> mModulesWithDevicesNames;
-};
+static constexpr char kConfigFileName[] = "audio_policy_configuration.xml";
// Cached policy config after parsing for faster test startup
const PolicyConfig& getCachedPolicyConfig() {
static std::unique_ptr<PolicyConfig> policyConfig = [] {
- auto config = std::make_unique<PolicyConfig>();
+ auto config = std::make_unique<PolicyConfig>(kConfigFileName);
return config;
}();
return *policyConfig;
@@ -449,9 +387,10 @@
* The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
*/
template <Optionality optionality = REQUIRED, class IUTGetter, class Getter, class Setter>
- void testAccessors(IUTGetter iutGetter, const string& propertyName,
- const Initial expectedInitial, list<Property> valuesToTest, Setter setter,
- Getter getter, const vector<Property>& invalidValues = {}) {
+ void testAccessors(IUTGetter iutGetter, const std::string& propertyName,
+ const Initial expectedInitial, std::list<Property> valuesToTest,
+ Setter setter, Getter getter,
+ const std::vector<Property>& invalidValues = {}) {
const auto expectedResults = {Result::OK,
optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
@@ -495,9 +434,9 @@
EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue));
}
template <Optionality optionality = REQUIRED, class Getter, class Setter>
- void testAccessors(const string& propertyName, const Initial expectedInitial,
- list<Property> valuesToTest, Setter setter, Getter getter,
- const vector<Property>& invalidValues = {}) {
+ void testAccessors(const std::string& propertyName, const Initial expectedInitial,
+ std::list<Property> valuesToTest, Setter setter, Getter getter,
+ const std::vector<Property>& invalidValues = {}) {
testAccessors<optionality>(&BaseTestClass::getDevice, propertyName, expectedInitial,
valuesToTest, setter, getter, invalidValues);
}
@@ -573,9 +512,13 @@
// Nesting a tuple in another tuple allows to use GTest Combine function to generate
// all combinations of devices and configs.
enum { PARAM_DEVICE, PARAM_CONFIG, PARAM_FLAGS };
+#if MAJOR_VERSION <= 6
enum { INDEX_INPUT, INDEX_OUTPUT };
using DeviceConfigParameter =
std::tuple<DeviceParameter, AudioConfig, std::variant<AudioInputFlag, AudioOutputFlag>>;
+#elif MAJOR_VERSION >= 7
+using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig, std::vector<AudioInOutFlag>>;
+#endif
#if MAJOR_VERSION >= 6
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters();
@@ -583,8 +526,8 @@
#endif
#if MAJOR_VERSION >= 4
-static string SanitizeStringForGTestName(const string& s) {
- string result = s;
+static std::string SanitizeStringForGTestName(const std::string& s) {
+ std::string result = s;
for (size_t i = 0; i < result.size(); i++) {
// gtest test names must only contain alphanumeric characters
if (!std::isalnum(result[i])) result[i] = '_';
@@ -598,43 +541,57 @@
* As the only parameter changing are channel mask and sample rate,
* only print those ones in the test name.
*/
-static string DeviceConfigParameterToString(
+static std::string DeviceConfigParameterToString(
const testing::TestParamInfo<DeviceConfigParameter>& info) {
const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
std::get<PARAM_DEVICE>(info.param), info.index});
- return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
- to_string(config.sampleRateHz) + "_" +
- // "MONO" is more clear than "FRONT_LEFT"
- ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
- config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
- ? "MONO"
+ const auto devicePart =
+ (deviceName.empty() ? "" : deviceName + "_") + std::to_string(info.index);
+ // The types had changed a lot between versions 2, 4..6 and 7. Use separate
+ // code sections for easier understanding.
#if MAJOR_VERSION == 2
- : ::testing::PrintToString(config.channelMask)
-#elif MAJOR_VERSION >= 4
- // In V4 and above the channel mask is a bitfield.
- // Printing its value using HIDL's toString for a bitfield emits a lot of extra
- // text due to overlapping constant values. Instead, we print the bitfield value
- // as if it was a single value + its hex representation
- : SanitizeStringForGTestName(
- ::testing::PrintToString(AudioChannelMask(config.channelMask)) + "_" +
- toHexString(config.channelMask))
+ const auto configPart =
+ std::to_string(config.sampleRateHz) + "_" +
+ // "MONO" is more clear than "FRONT_LEFT"
+ (config.channelMask == AudioChannelMask::OUT_MONO ||
+ config.channelMask == AudioChannelMask::IN_MONO
+ ? "MONO"
+ : ::testing::PrintToString(config.channelMask)) +
+ "_" +
+ std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
+ std::get<PARAM_FLAGS>(info.param));
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
+ const auto configPart =
+ std::to_string(config.sampleRateHz) + "_" +
+ // "MONO" is more clear than "FRONT_LEFT"
+ (config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
+ config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)
+ ? "MONO"
+ // In V4 and above the channel mask is a bitfield.
+ // Printing its value using HIDL's toString for a bitfield emits a lot of extra
+ // text due to overlapping constant values. Instead, we print the bitfield
+ // value as if it was a single value + its hex representation
+ : SanitizeStringForGTestName(
+ ::testing::PrintToString(AudioChannelMask(config.channelMask)) +
+ "_" + toHexString(config.channelMask))) +
+ "_" +
+ SanitizeStringForGTestName(std::visit(
+ [](auto&& arg) -> std::string {
+ using T = std::decay_t<decltype(arg)>;
+ // Need to use FQN of toString to avoid confusing the compiler
+ return ::android::hardware::audio::common::CPP_VERSION::toString<T>(
+ hidl_bitfield<T>(arg));
+ },
+ std::get<PARAM_FLAGS>(info.param)));
+#elif MAJOR_VERSION >= 7
+ const auto configPart =
+ std::to_string(config.base.sampleRateHz) + "_" +
+ // The channel masks and flags are vectors of strings, just need to sanitize them.
+ SanitizeStringForGTestName(::testing::PrintToString(config.base.channelMask)) + "_" +
+ SanitizeStringForGTestName(::testing::PrintToString(std::get<PARAM_FLAGS>(info.param)));
#endif
- ) +
- "_" +
-#if MAJOR_VERSION == 2
- std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
- std::get<PARAM_FLAGS>(info.param));
-#elif MAJOR_VERSION >= 4
- SanitizeStringForGTestName(std::visit(
- [](auto&& arg) -> std::string {
- using T = std::decay_t<decltype(arg)>;
- // Need to use FQN of toString to avoid confusing the compiler
- return ::android::hardware::audio::common::CPP_VERSION::toString<T>(
- hidl_bitfield<T>(arg));
- },
- std::get<PARAM_FLAGS>(info.param)));
-#endif
+ return devicePart + "__" + configPart;
}
class AudioHidlTestWithDeviceConfigParameter
@@ -660,7 +617,7 @@
AudioOutputFlag getOutputFlags() const {
return std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam()));
}
-#elif MAJOR_VERSION >= 4
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
hidl_bitfield<AudioInputFlag> getInputFlags() const {
return hidl_bitfield<AudioInputFlag>(
std::get<INDEX_INPUT>(std::get<PARAM_FLAGS>(GetParam())));
@@ -669,10 +626,17 @@
return hidl_bitfield<AudioOutputFlag>(
std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
}
+#elif MAJOR_VERSION >= 7
+ hidl_vec<AudioInOutFlag> getInputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
+ hidl_vec<AudioInOutFlag> getOutputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
#endif
};
+#if MAJOR_VERSION <= 6
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
#include "ConfigHelper.h"
+#undef AUDIO_PRIMARY_HIDL_HAL_TEST
+#endif
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// getInputBufferSize /////////////////////////////
@@ -839,7 +803,7 @@
AudioConfig* suggestedConfigPtr) {
// FIXME: Open a stream without an IOHandle
// This is not required to be accepted by hal implementations
- AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+ AudioIoHandle ioHandle{};
AudioConfig suggestedConfig{};
bool retryWithSuggestedConfig = true;
if (suggestedConfigPtr == nullptr) {
@@ -932,7 +896,11 @@
class OutputStreamTest : public OpenStreamTest<IStreamOut> {
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+#if MAJOR_VERSION <= 6
address.device = AudioDevice::OUT_DEFAULT;
+#elif MAJOR_VERSION >= 7
+ address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT);
+#endif
const AudioConfig& config = getConfig();
auto flags = getOutputFlags();
testOpen(
@@ -946,13 +914,19 @@
},
config);
}
-#if MAJOR_VERSION >= 4
+#if MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
- protected:
+ protected:
const SourceMetadata initMetadata = {
{ { AudioUsage::MEDIA,
AudioContentType::MUSIC,
1 /* gain */ } }};
+#elif MAJOR_VERSION >= 7
+ protected:
+ const SourceMetadata initMetadata = {
+ { { toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+ toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
+ 1 /* gain */ } }};
#endif
};
TEST_P(OutputStreamTest, OpenOutputStreamTest) {
@@ -995,7 +969,11 @@
class InputStreamTest : public OpenStreamTest<IStreamIn> {
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+#if MAJOR_VERSION <= 6
address.device = AudioDevice::IN_DEFAULT;
+#elif MAJOR_VERSION <= 7
+ address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+#endif
const AudioConfig& config = getConfig();
auto flags = getInputFlags();
testOpen(
@@ -1009,8 +987,11 @@
protected:
#if MAJOR_VERSION == 2
const AudioSource initMetadata = AudioSource::DEFAULT;
-#elif MAJOR_VERSION >= 4
- const SinkMetadata initMetadata = {{{.source = AudioSource::DEFAULT, .gain = 1}}};
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
+ const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
+#elif MAJOR_VERSION >= 7
+ const SinkMetadata initMetadata = {
+ {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1}}};
#endif
};
@@ -1067,6 +1048,7 @@
TEST_IO_STREAM(GetFrameCount, "Check that getting stream frame count does not crash the HAL.",
ASSERT_TRUE(stream->getFrameCount().isOk()))
+#if MAJOR_VERSION <= 6
TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
@@ -1075,6 +1057,7 @@
TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+#endif
// TODO: for now only check that the framesize is not incoherent
TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
@@ -1084,7 +1067,7 @@
ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize())));
template <class Property, class CapabilityGetter>
-static void testCapabilityGetter(const string& name, IStream* stream,
+static void testCapabilityGetter(const std::string& name, IStream* stream,
CapabilityGetter capabilityGetter,
Return<Property> (IStream::*getter)(),
Return<Result> (IStream::*setter)(Property),
@@ -1120,6 +1103,7 @@
}
}
+#if MAJOR_VERSION <= 6
TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
testCapabilityGetter("getSupportedSampleRate", stream.get(),
&GetSupported::sampleRates, &IStream::getSampleRate,
@@ -1137,19 +1121,71 @@
TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
testCapabilityGetter("getSupportedFormat", stream.get(), &GetSupported::formats,
&IStream::getFormat, &IStream::setFormat))
+#else
+static void testGetSupportedProfiles(IStream* stream) {
+ Result res;
+ hidl_vec<AudioProfile> profiles;
+ auto ret = stream->getSupportedProfiles(returnIn(res, profiles));
+ EXPECT_TRUE(ret.isOk());
+ if (res == Result::OK) {
+ EXPECT_GT(profiles.size(), 0);
+ } else {
+ EXPECT_EQ(Result::NOT_SUPPORTED, res);
+ }
+}
+
+TEST_IO_STREAM(GetSupportedProfiles, "Try to call optional method GetSupportedProfiles",
+ testGetSupportedProfiles(stream.get()))
+
+static void testSetAudioProperties(IStream* stream) {
+ Result res;
+ hidl_vec<AudioProfile> profiles;
+ auto ret = stream->getSupportedProfiles(returnIn(res, profiles));
+ EXPECT_TRUE(ret.isOk());
+ if (res == Result::NOT_SUPPORTED) {
+ GTEST_SKIP() << "Retrieving supported profiles is not implemented";
+ }
+ for (const auto& profile : profiles) {
+ for (const auto& sampleRate : profile.sampleRates) {
+ for (const auto& channelMask : profile.channelMasks) {
+ AudioConfigBase config{.format = profile.format,
+ .sampleRateHz = sampleRate,
+ .channelMask = {{channelMask}}};
+ auto ret = stream->setAudioProperties(config);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret) << config.format << "; " << config.sampleRateHz << "; "
+ << toString(config.channelMask);
+ }
+ }
+ }
+}
+
+TEST_IO_STREAM(SetAudioProperties, "Call setAudioProperties for all supported profiles",
+ testSetAudioProperties(stream.get()))
+#endif
static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+#if MAJOR_VERSION <= 6
uint32_t sampleRateHz;
auto mask = mkEnumBitfield<AudioChannelMask>({});
AudioFormat format;
- stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+ auto ret = stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+ EXPECT_TRUE(ret.isOk());
// FIXME: the qcom hal it does not currently negotiate the sampleRate &
// channel mask
EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
EXPECT_EQ(expectedConfig.channelMask, mask);
EXPECT_EQ(expectedConfig.format, format);
+#elif MAJOR_VERSION >= 7
+ AudioConfigBase actualConfig{};
+ auto ret = stream->getAudioProperties(returnIn(actualConfig));
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(expectedConfig.base.sampleRateHz, actualConfig.sampleRateHz);
+ EXPECT_EQ(expectedConfig.base.channelMask, actualConfig.channelMask);
+ EXPECT_EQ(expectedConfig.base.format, actualConfig.format);
+#endif
}
TEST_IO_STREAM(GetAudioProperties,
@@ -1160,7 +1196,7 @@
ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666)))
static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
- initializer_list<Result> expectedResults) {
+ std::initializer_list<Result> expectedResults) {
hidl_vec<ParameterValue> parameters;
Result res;
ASSERT_OK(Parameters::get(stream, keys, returnIn(res, parameters)));
@@ -1271,7 +1307,11 @@
return;
}
ASSERT_OK(res);
+#if MAJOR_VERSION <= 6
ASSERT_EQ(AudioSource::DEFAULT, source);
+#elif MAJOR_VERSION >= 7
+ ASSERT_EQ(xsd::AudioSource::AUDIO_SOURCE_DEFAULT, xsd::stringToAudioSource(source));
+#endif
}
static void testUnitaryGain(std::function<Return<Result>(float)> setGain) {
@@ -1286,7 +1326,7 @@
}
static void testOptionalUnitaryGain(std::function<Return<Result>(float)> setGain,
- string debugName) {
+ std::string debugName) {
auto result = setGain(1);
ASSERT_IS_OK(result);
if (result == Result::NOT_SUPPORTED) {
@@ -1306,7 +1346,7 @@
Result res;
// Ignore output parameters as the call should fail
ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
- [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ [&res](auto r, auto&, auto&, auto&, auto) { res = r; }));
EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
}
@@ -1371,7 +1411,7 @@
Result res;
// Ignore output parameters as the call should fail
ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
- [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ [&res](auto r, auto&, auto&, auto&, auto) { res = r; }));
EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
}
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
index 8ef2b43..1a1dbea 100644
--- a/audio/core/all-versions/vts/functional/ConfigHelper.h
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#pragma once
+
// Code in this file uses 'getCachedPolicyConfig'
#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
#error Must be included from AudioPrimaryHidlTest.h
@@ -46,32 +48,32 @@
}
// Cache result ?
- static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+ static const std::vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
{8000, 11025, 16000, 22050, 32000, 44100},
{AudioFormat::PCM_16_BIT});
}
- static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+ static const std::vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
{24000, 48000}, {AudioFormat::PCM_16_BIT});
}
- static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+ static const std::vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
if (!primaryHasMic()) return {};
return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
{AudioFormat::PCM_16_BIT});
}
- static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+ static const std::vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
if (!primaryHasMic()) return {};
return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
{AudioFormat::PCM_16_BIT});
}
- static vector<AudioConfig> combineAudioConfig(vector<audio_channel_mask_t> channelMasks,
- vector<uint32_t> sampleRates,
- audio_format_t format) {
- vector<AudioConfig> configs;
+ static std::vector<AudioConfig> combineAudioConfig(
+ std::vector<audio_channel_mask_t> channelMasks, std::vector<uint32_t> sampleRates,
+ audio_format_t format) {
+ std::vector<AudioConfig> configs;
configs.reserve(channelMasks.size() * sampleRates.size());
for (auto channelMask : channelMasks) {
for (auto sampleRate : sampleRates) {
@@ -86,10 +88,10 @@
return configs;
}
- static vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
- vector<uint32_t> sampleRates,
- vector<AudioFormat> formats) {
- vector<AudioConfig> configs;
+ static std::vector<AudioConfig> combineAudioConfig(std::vector<AudioChannelMask> channelMasks,
+ std::vector<uint32_t> sampleRates,
+ std::vector<AudioFormat> formats) {
+ std::vector<AudioConfig> configs;
configs.reserve(channelMasks.size() * sampleRates.size() * formats.size());
for (auto channelMask : channelMasks) {
for (auto sampleRate : sampleRates) {
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
index 0c0727f..6efed79 100644
--- a/audio/core/all-versions/vts/functional/DeviceManager.h
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-// Code in this file uses 'environment'
-#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
-#error Must be included from AudioPrimaryHidlTest.h
-#endif
+#pragma once
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
template <class Derived, class Key, class Interface>
class InterfaceManager {
diff --git a/audio/core/all-versions/vts/functional/PolicyConfig.h b/audio/core/all-versions/vts/functional/PolicyConfig.h
new file mode 100644
index 0000000..c9e0c0d
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/PolicyConfig.h
@@ -0,0 +1,96 @@
+/*
+ * 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
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
+
+#include <Serializer.h>
+
+struct PolicyConfigData {
+ android::HwModuleCollection hwModules;
+ android::DeviceVector availableOutputDevices;
+ android::DeviceVector availableInputDevices;
+ sp<android::DeviceDescriptor> defaultOutputDevice;
+};
+
+class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig {
+ public:
+ explicit PolicyConfig(const std::string& configFileName)
+ : android::AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
+ defaultOutputDevice),
+ mConfigFileName{configFileName} {
+ for (const auto& location : android::audio_get_configuration_paths()) {
+ std::string path = location + '/' + mConfigFileName;
+ if (access(path.c_str(), F_OK) == 0) {
+ mFilePath = path;
+ break;
+ }
+ }
+ mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
+ if (mStatus == OK) {
+ mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice);
+ // Available devices are not 'attached' to modules at this moment.
+ // Need to go over available devices and find their module.
+ for (const auto& device : availableOutputDevices) {
+ for (const auto& module : hwModules) {
+ if (module->getDeclaredDevices().indexOf(device) >= 0) {
+ mModulesWithDevicesNames.insert(module->getName());
+ break;
+ }
+ }
+ }
+ for (const auto& device : availableInputDevices) {
+ for (const auto& module : hwModules) {
+ if (module->getDeclaredDevices().indexOf(device) >= 0) {
+ mModulesWithDevicesNames.insert(module->getName());
+ break;
+ }
+ }
+ }
+ }
+ }
+ status_t getStatus() const { return mStatus; }
+ std::string getError() const {
+ if (mFilePath.empty()) {
+ return std::string{"Could not find "} + mConfigFileName +
+ " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
+ } else {
+ return "Invalid config file: " + mFilePath;
+ }
+ }
+ const std::string& getFilePath() const { return mFilePath; }
+ sp<const android::HwModule> getModuleFromName(const std::string& name) const {
+ return getHwModules().getModuleFromName(name.c_str());
+ }
+ sp<const android::HwModule> getPrimaryModule() const { return mPrimaryModule; }
+ const std::set<std::string>& getModulesWithDevicesNames() const {
+ return mModulesWithDevicesNames;
+ }
+ bool haveInputProfilesInModule(const std::string& name) const {
+ auto module = getModuleFromName(name);
+ return module && !module->getInputProfiles().empty();
+ }
+
+ private:
+ const std::string mConfigFileName;
+ status_t mStatus = NO_INIT;
+ std::string mFilePath;
+ sp<const android::HwModule> mPrimaryModule = nullptr;
+ std::set<std::string> mModulesWithDevicesNames;
+};
diff --git a/audio/effect/7.0/IEffect.hal b/audio/effect/7.0/IEffect.hal
index 5b176dc..aa94f6d 100644
--- a/audio/effect/7.0/IEffect.hal
+++ b/audio/effect/7.0/IEffect.hal
@@ -56,7 +56,6 @@
*
* @return retval operation completion status.
*/
- @callflow(next={"prepareForProcessing"})
enable() generates (Result retval);
/**
@@ -64,7 +63,6 @@
*
* @return retval operation completion status.
*/
- @callflow(next={"close"})
disable() generates (Result retval);
/**
@@ -78,7 +76,7 @@
* @param device output device specification.
* @return retval operation completion status.
*/
- setDevice(bitfield<AudioDevice> device) generates (Result retval);
+ setDevice(DeviceAddress device) generates (Result retval);
/**
* Set and get volume. Used by audio framework to delegate volume control to
@@ -147,7 +145,7 @@
* @param device input device specification.
* @return retval operation completion status.
*/
- setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+ setInputDevice(DeviceAddress device) generates (Result retval);
/**
* Read audio parameters configurations for input and output buffers.
@@ -251,7 +249,6 @@
* the queue.
* @return statusMQ a message queue used for passing status from the effect.
*/
- @callflow(next={"setProcessBuffers"})
prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
/**
@@ -416,6 +413,5 @@
* @return retval OK in case the success.
* INVALID_STATE if the effect was already closed.
*/
- @exit
close() generates (Result retval);
};
diff --git a/audio/effect/7.0/IVirtualizerEffect.hal b/audio/effect/7.0/IVirtualizerEffect.hal
index 0e6ff54..141b4e6 100644
--- a/audio/effect/7.0/IVirtualizerEffect.hal
+++ b/audio/effect/7.0/IVirtualizerEffect.hal
@@ -48,7 +48,7 @@
struct SpeakerAngle {
/** Speaker channel mask */
- bitfield<AudioChannelMask> mask;
+ vec<AudioChannelMask> mask;
// all angles are expressed in degrees and
// are relative to the listener.
int16_t azimuth; // 0 is the direction the listener faces
@@ -61,17 +61,17 @@
* Retrieves virtual speaker angles for the given channel mask on the
* specified device.
*/
- getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+ getVirtualSpeakerAngles(vec<AudioChannelMask> mask, DeviceAddress device)
generates (Result retval, vec<SpeakerAngle> speakerAngles);
/**
* Forces the virtualizer effect for the given output device.
*/
- forceVirtualizationMode(AudioDevice device) generates (Result retval);
+ forceVirtualizationMode(DeviceAddress device) generates (Result retval);
/**
* Returns audio device reflecting the current virtualization mode,
- * AUDIO_DEVICE_NONE when not virtualizing.
+ * Device type can be empty when not virtualizing.
*/
- getVirtualizationMode() generates (Result retval, AudioDevice device);
+ getVirtualizationMode() generates (Result retval, DeviceAddress device);
};
diff --git a/audio/effect/7.0/types.hal b/audio/effect/7.0/types.hal
index 7f5a382..fe4ee51 100644
--- a/audio/effect/7.0/types.hal
+++ b/audio/effect/7.0/types.hal
@@ -257,7 +257,7 @@
struct EffectBufferConfig {
AudioBuffer buffer;
uint32_t samplingRateHz;
- bitfield<AudioChannelMask> channels;
+ AudioChannelMask channels;
AudioFormat format;
EffectBufferAccess accessMode;
bitfield<EffectConfigParameters> mask;
@@ -276,8 +276,8 @@
};
struct EffectAuxChannelsConfig {
- bitfield<AudioChannelMask> mainChannels; // channel mask for main channels
- bitfield<AudioChannelMask> auxChannels; // channel mask for auxiliary channels
+ vec<AudioChannelMask> mainChannels; // channel mask for main channels
+ vec<AudioChannelMask> auxChannels; // channel mask for auxiliary channels
};
struct EffectOffloadParameter {
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index 7cdb18f..f4a7283 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -118,7 +118,6 @@
}
cc_test {
- enabled: false,
name: "VtsHalAudioEffectV7_0TargetTest",
defaults: ["VtsHalAudioEffectTargetTest_default"],
// Use test_config for vts suite.
@@ -126,6 +125,7 @@
test_config: "VtsHalAudioEffectV7_0TargetTest.xml",
static_libs: [
"android.hardware.audio.common@7.0",
+ "android.hardware.audio.common@7.0-enums",
"android.hardware.audio.effect@7.0",
],
data: [
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 4787c09..b64f105 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "AudioEffectHidlHalTest"
#include <android-base/logging.h>
+#if MAJOR_VERSION <= 6
#include <system/audio.h>
+#endif
#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffect.h)
#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
@@ -25,6 +27,10 @@
#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h)
#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>
+#endif
#include <common/all-versions/VersionUtils.h>
@@ -45,6 +51,12 @@
using ::android::hidl::memory::V1_0::IMemory;
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
+#if MAJOR_VERSION >= 7
+// Make an alias for enumerations generated from the APM config XSD.
+namespace xsd {
+using namespace ::audio::policy::configuration::CPP_VERSION;
+}
+#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -171,7 +183,7 @@
effectsFactory = IEffectsFactory::getService(std::get<PARAM_FACTORY_NAME>(GetParam()));
ASSERT_NE(nullptr, effectsFactory.get());
- findAndCreateEffect(getEffectType());
+ ASSERT_NO_FATAL_FAILURE(findAndCreateEffect(getEffectType()));
ASSERT_NE(nullptr, effect.get());
Return<Result> ret = effect->init();
@@ -201,7 +213,7 @@
void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
Uuid effectUuid;
- findEffectInstance(type, &effectUuid);
+ ASSERT_NO_FATAL_FAILURE(findEffectInstance(type, &effectUuid));
Return<void> ret = effectsFactory->createEffect(
effectUuid, 1 /*session*/, 1 /*ioHandle*/,
#if MAJOR_VERSION >= 6
@@ -244,10 +256,16 @@
});
ASSERT_TRUE(ret.isOk());
ASSERT_EQ(Result::OK, retval);
+#if MAJOR_VERSION <= 6
ASSERT_TRUE(audio_channel_mask_is_valid(
static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
*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);
+ ASSERT_NE(*channelCount, 0);
+#endif
}
TEST_P(AudioEffectHidlTest, Close) {
@@ -391,7 +409,12 @@
TEST_P(AudioEffectHidlTest, SetDevice) {
description("Verify that SetDevice works for an output chain effect");
+#if MAJOR_VERSION <= 6
Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
+#else
+ DeviceAddress device{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER)};
+ Return<Result> ret = effect->setDevice(device);
+#endif
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, ret);
}
@@ -441,22 +464,28 @@
TEST_P(AudioEffectHidlTest, SetInputDevice) {
description("Verify that SetInputDevice does not crash");
+#if MAJOR_VERSION <= 6
Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
+#else
+ DeviceAddress device{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC)};
+ Return<Result> ret = effect->setInputDevice(device);
+#endif
EXPECT_TRUE(ret.isOk());
}
TEST_P(AudioEffectHidlTest, SetAudioSource) {
description("Verify that SetAudioSource does not crash");
+#if MAJOR_VERSION <= 6
Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
+#else
+ Return<Result> ret = effect->setAudioSource(toString(xsd::AudioSource::AUDIO_SOURCE_MIC));
+#endif
EXPECT_TRUE(ret.isOk());
}
TEST_P(AudioEffectHidlTest, Offload) {
description("Verify that calling Offload method does not crash");
- EffectOffloadParameter offloadParam;
- offloadParam.isOffload = false;
- offloadParam.ioHandle = static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE);
- Return<Result> ret = effect->offload(offloadParam);
+ Return<Result> ret = effect->offload(EffectOffloadParameter{});
EXPECT_TRUE(ret.isOk());
}
diff --git a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
index de1ec02..982cf2c 100644
--- a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
+++ b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
@@ -140,6 +140,7 @@
EXPECT_EQ(bus, -1);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, CarAudioControlHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
index 0c10664..fa35143 100644
--- a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -149,6 +149,7 @@
AudioFocusChange::GAIN_TRANSIENT | 0);
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, CarAudioControlHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index f5cf425..0ba066e 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -52,5 +52,6 @@
static_libs: [
"android.hardware.automotive.can@libnetdevice",
"android.hardware.automotive@libc++fs",
+ "libnl++",
],
}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 8b98e5e..2efe054 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -254,7 +254,7 @@
satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
if (rule.exclude) {
- // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+ // Any exclude rule being satisfied invalidates the whole filter set.
if (satisfied) return false;
} else {
anyNonExcludeRulePresent = true;
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
index 31e5ad0..2605f88 100644
--- a/automotive/can/1.0/default/libnetdevice/Android.bp
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -18,13 +18,16 @@
name: "android.hardware.automotive.can@libnetdevice",
defaults: ["android.hardware.automotive.can@defaults"],
vendor_available: true,
- relative_install_path: "hw",
srcs: [
- "NetlinkRequest.cpp",
- "NetlinkSocket.cpp",
"can.cpp",
"common.cpp",
+ "ethtool.cpp",
+ "ifreqs.cpp",
"libnetdevice.cpp",
+ "vlan.cpp",
],
export_include_dirs: ["include"],
+ static_libs: [
+ "libnl++",
+ ],
}
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
deleted file mode 100644
index 556debf..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#include "NetlinkRequest.h"
-
-#include <android-base/logging.h>
-
-namespace android::netdevice::impl {
-
-static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
- return reinterpret_cast<struct rtattr*>( //
- reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
-}
-
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
- size_t dataLen) {
- size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
- if (newLen > maxLen) {
- LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
- return nullptr;
- }
-
- auto attr = nlmsg_tail(n);
- attr->rta_len = RTA_SPACE(dataLen);
- attr->rta_type = type;
- if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
-
- n->nlmsg_len = newLen;
- return attr;
-}
-
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
- return addattr_l(n, maxLen, type, nullptr, 0);
-}
-
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
- size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
- nest->rta_len = nestLen;
-}
-
-} // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
deleted file mode 100644
index 3e28d78..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <android-base/macros.h>
-#include <linux/rtnetlink.h>
-
-#include <string>
-
-namespace android::netdevice {
-
-typedef unsigned short rtattrtype_t; // as in rtnetlink.h
-typedef __u16 nlmsgtype_t; // as in netlink.h
-
-/** Implementation details, do not use outside NetlinkRequest template. */
-namespace impl {
-
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
- size_t dataLen);
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
-
-} // namespace impl
-
-/**
- * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
- *
- * \param T specific message header (such as struct ifinfomsg)
- * \param BUFSIZE how much space to reserve for payload (not counting the header size)
- */
-template <class T, unsigned int BUFSIZE = 128>
-struct NetlinkRequest {
- /**
- * Create empty message.
- *
- * \param type Message type (such as RTM_NEWLINK)
- * \param flags Message flags (such as NLM_F_REQUEST)
- */
- NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
- mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
- mRequest.nlmsg.nlmsg_type = type;
- mRequest.nlmsg.nlmsg_flags = flags;
- }
-
- /** \return pointer to raw netlink message header. */
- struct nlmsghdr* header() {
- return &mRequest.nlmsg;
- }
- /** Reference to message-specific header. */
- T& data() { return mRequest.data; }
-
- /**
- * Adds an attribute of a simple type.
- *
- * If this method fails (i.e. due to insufficient space), the message will be marked
- * as bad (\see isGood).
- *
- * \param type attribute type (such as IFLA_IFNAME)
- * \param attr attribute data
- */
- template <class A>
- void addattr(rtattrtype_t type, const A& attr) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
- if (ap == nullptr) mIsGood = false;
- }
-
- template <>
- void addattr(rtattrtype_t type, const std::string& s) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
- if (ap == nullptr) mIsGood = false;
- }
-
- /** Guard class to frame nested attributes. See nest(int). */
- struct Nest {
- Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
- ~Nest() { mReq.nestEnd(mAttr); }
-
- private:
- NetlinkRequest& mReq;
- struct rtattr* mAttr;
-
- DISALLOW_COPY_AND_ASSIGN(Nest);
- };
-
- /**
- * Add nested attribute.
- *
- * The returned object is a guard for auto-nesting children inside the argument attribute.
- * When the Nest object goes out of scope, the nesting attribute is closed.
- *
- * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
- * inside IFLA_LINKINFO:
- * NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
- * {
- * auto linkinfo = req.nest(IFLA_LINKINFO);
- * req.addattr(IFLA_INFO_KIND, "can");
- * {
- * auto infodata = req.nest(IFLA_INFO_DATA);
- * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
- * }
- * }
- * // use req
- *
- * \param type attribute type (such as IFLA_LINKINFO)
- */
- Nest nest(int type) { return Nest(*this, type); }
-
- /**
- * Indicates, whether the message is in a good state.
- *
- * The bad state is usually a result of payload buffer being too small.
- * You can modify BUFSIZE template parameter to fix this.
- */
- bool isGood() const { return mIsGood; }
-
- private:
- bool mIsGood = true;
-
- struct {
- struct nlmsghdr nlmsg;
- T data;
- char buf[BUFSIZE];
- } mRequest = {};
-
- struct rtattr* nestStart(rtattrtype_t type) {
- if (!mIsGood) return nullptr;
- auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
- if (attr == nullptr) mIsGood = false;
- return attr;
- }
-
- void nestEnd(struct rtattr* nest) {
- if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
- }
-};
-
-} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
deleted file mode 100644
index 7817169..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.
- */
-
-#include "NetlinkSocket.h"
-
-#include <android-base/logging.h>
-
-namespace android::netdevice {
-
-NetlinkSocket::NetlinkSocket(int protocol) {
- mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
- if (!mFd.ok()) {
- PLOG(ERROR) << "Can't open Netlink socket";
- mFailed = true;
- return;
- }
-
- struct sockaddr_nl sa = {};
- sa.nl_family = AF_NETLINK;
-
- if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
- PLOG(ERROR) << "Can't bind Netlink socket";
- mFd.reset();
- mFailed = true;
- }
-}
-
-bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
- if (mFailed) return false;
-
- nlmsg->nlmsg_pid = 0; // kernel
- nlmsg->nlmsg_seq = mSeq++;
- nlmsg->nlmsg_flags |= NLM_F_ACK;
-
- struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
-
- struct sockaddr_nl sa = {};
- sa.nl_family = AF_NETLINK;
-
- struct msghdr msg = {};
- msg.msg_name = &sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- if (sendmsg(mFd.get(), &msg, 0) < 0) {
- PLOG(ERROR) << "Can't send Netlink message";
- return false;
- }
- return true;
-}
-
-bool NetlinkSocket::receiveAck() {
- if (mFailed) return false;
-
- char buf[8192];
-
- struct sockaddr_nl sa;
- struct iovec iov = {buf, sizeof(buf)};
-
- struct msghdr msg = {};
- msg.msg_name = &sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- const ssize_t status = recvmsg(mFd.get(), &msg, 0);
- if (status < 0) {
- PLOG(ERROR) << "Failed to receive Netlink message";
- return false;
- }
- size_t remainingLen = status;
-
- if (msg.msg_flags & MSG_TRUNC) {
- LOG(ERROR) << "Failed to receive Netlink message: truncated";
- return false;
- }
-
- for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
- nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
- // We're looking for error/ack message only, ignoring others.
- if (nlmsg->nlmsg_type != NLMSG_ERROR) {
- LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
- continue;
- }
-
- // Found error/ack message, return status.
- auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
- if (nlerr->error != 0) {
- LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
- return false;
- }
- return true;
- }
- // Couldn't find any error/ack messages.
- return false;
-}
-
-} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
deleted file mode 100644
index 2b40ea2..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include "NetlinkRequest.h"
-
-#include <android-base/macros.h>
-#include <android-base/unique_fd.h>
-
-#include <linux/netlink.h>
-
-namespace android::netdevice {
-
-/**
- * A wrapper around AF_NETLINK sockets.
- *
- * This class is not thread safe to use a single instance between multiple threads, but it's fine to
- * use multiple instances over multiple threads.
- */
-struct NetlinkSocket {
- NetlinkSocket(int protocol);
-
- /**
- * Send Netlink message to Kernel.
- *
- * \param msg Message to send, nlmsg_seq will be set to next sequence number
- * \return true, if succeeded
- */
- template <class T, unsigned int BUFSIZE>
- bool send(NetlinkRequest<T, BUFSIZE>& req) {
- if (!req.isGood()) return false;
- return send(req.header());
- }
-
- /**
- * Receive Netlink ACK message from Kernel.
- *
- * \return true if received ACK message, false in case of error
- */
- bool receiveAck();
-
- private:
- uint32_t mSeq = 0;
- base::unique_fd mFd;
- bool mFailed = false;
-
- bool send(struct nlmsghdr* msg);
-
- DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
-};
-
-} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index a2a85dc..083f4f0 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -14,26 +14,27 @@
* limitations under the License.
*/
-#include <libnetdevice/libnetdevice.h>
+#include <libnetdevice/can.h>
-#include "NetlinkRequest.h"
-#include "NetlinkSocket.h"
#include "common.h"
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/netlink.h>
#include <linux/can/raw.h>
+#include <linux/rtnetlink.h>
namespace android::netdevice::can {
static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
base::unique_fd socket(const std::string& ifname) {
- struct sockaddr_can addr = {};
+ sockaddr_can addr = {};
addr.can_family = AF_CAN;
addr.can_ifindex = nametoindex(ifname);
if (addr.can_ifindex == 0) {
@@ -57,7 +58,7 @@
return {};
}
- if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+ if (0 != bind(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
LOG(ERROR) << "Can't bind to CAN interface " << ifname;
return {};
}
@@ -66,31 +67,30 @@
}
bool setBitrate(std::string ifname, uint32_t bitrate) {
- struct can_bittiming bt = {};
+ can_bittiming bt = {};
bt.bitrate = bitrate;
- NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
- const auto ifidx = nametoindex(ifname);
- if (ifidx == 0) {
+ req->ifi_index = nametoindex(ifname);
+ if (req->ifi_index == 0) {
LOG(ERROR) << "Can't find interface " << ifname;
return false;
}
- req.data().ifi_index = ifidx;
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, "can");
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "can");
{
- auto infodata = req.nest(IFLA_INFO_DATA);
+ auto infodata = req.addNested(IFLA_INFO_DATA);
/* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
* and IFLA_CAN_CTRLMODE as well. */
- req.addattr(IFLA_CAN_BITTIMING, bt);
+ req.add(IFLA_CAN_BITTIMING, bt);
}
}
- NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 5c62443..28e50af 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -26,9 +26,8 @@
const auto ifidx = if_nametoindex(ifname.c_str());
if (ifidx != 0) return ifidx;
- const auto err = errno;
- if (err != ENODEV) {
- LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
+ if (errno != ENODEV) {
+ PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
}
return 0;
}
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 8097f37..661e3f8 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -16,6 +16,9 @@
#pragma once
+#include <linux/can.h>
+#include <net/if.h>
+
#include <string>
namespace android::netdevice {
diff --git a/automotive/can/1.0/default/libnetdevice/ethtool.cpp b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
new file mode 100644
index 0000000..762ef5c
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ethtool.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.
+ */
+
+#include <libnetdevice/ethtool.h>
+
+#include "ifreqs.h"
+
+#include <linux/ethtool.h>
+
+namespace android::netdevice::ethtool {
+
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command) {
+ struct ethtool_value valueop = {};
+ valueop.cmd = command;
+
+ auto ifr = ifreqs::fromName(ifname);
+ ifr.ifr_data = &valueop;
+
+ if (!ifreqs::send(SIOCETHTOOL, ifr)) return std::nullopt;
+ return valueop.data;
+}
+
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value) {
+ struct ethtool_value valueop = {};
+ valueop.cmd = command;
+ valueop.data = value;
+
+ auto ifr = ifreqs::fromName(ifname);
+ ifr.ifr_data = &valueop;
+
+ return ifreqs::send(SIOCETHTOOL, ifr);
+}
+
+} // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
new file mode 100644
index 0000000..8df6434
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.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.
+ */
+
+#include "ifreqs.h"
+
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <map>
+
+namespace android::netdevice::ifreqs {
+
+static constexpr int defaultSocketDomain = AF_INET;
+std::atomic_int socketDomain = defaultSocketDomain;
+
+struct SocketParams {
+ int domain;
+ int type;
+ int protocol;
+};
+
+static const std::map<int, SocketParams> socketParams = {
+ {AF_INET, {AF_INET, SOCK_DGRAM, 0}},
+ {AF_CAN, {AF_CAN, SOCK_RAW, CAN_RAW}},
+};
+
+static SocketParams getSocketParams(int domain) {
+ if (socketParams.count(domain)) return socketParams.find(domain)->second;
+
+ auto params = socketParams.find(defaultSocketDomain)->second;
+ params.domain = domain;
+ return params;
+}
+
+bool send(unsigned long request, struct ifreq& ifr) {
+ const auto sp = getSocketParams(socketDomain);
+ base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol));
+ if (!sock.ok()) {
+ LOG(ERROR) << "Can't create socket";
+ return false;
+ }
+
+ if (ioctl(sock.get(), request, &ifr) < 0) {
+ PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
+ return false;
+ }
+
+ return true;
+}
+
+struct ifreq fromName(const std::string& ifname) {
+ struct ifreq ifr = {};
+ strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+ return ifr;
+}
+
+} // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
new file mode 100644
index 0000000..74e5877
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.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
+
+#include <net/if.h>
+
+#include <string>
+
+namespace android::netdevice::ifreqs {
+
+/**
+ * \see useSocketDomain()
+ */
+extern std::atomic_int socketDomain;
+
+/**
+ * Sends ioctl interface request.
+ *
+ * \param request Request type (such as SIOCGIFFLAGS)
+ * \param ifr Request data (both input and output)
+ * \return true if the call succeeded, false otherwise
+ */
+bool send(unsigned long request, struct ifreq& ifr);
+
+/**
+ * Initializes interface request with interface name.
+ *
+ * \param ifname Interface to initialize request with
+ * \return Interface request with ifr_name field set to ifname
+ */
+struct ifreq fromName(const std::string& ifname);
+
+} // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
new file mode 100644
index 0000000..26bfdce
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
@@ -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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace android::netdevice::ethtool {
+
+/**
+ * Fetch a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to fetch data for
+ * \param command Fetch command (ETHTOOL_G*)
+ * \return value, or nullopt if fetch failed
+ */
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command);
+
+/**
+ * Set a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to set data for
+ * \param command Set command (ETHTOOL_S*)
+ * \param value New value
+ * \return true if succeeded, false otherwise
+ */
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value);
+
+} // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 3818a31..70cb688 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -16,11 +16,27 @@
#pragma once
+#include <linux/if_ether.h>
+
+#include <array>
#include <optional>
+#include <set>
#include <string>
namespace android::netdevice {
+typedef std::array<uint8_t, ETH_ALEN> hwaddr_t;
+
+/**
+ * Configures libnetdevice to use other socket domain than AF_INET,
+ * what requires less permissive SEPolicy rules for a given process.
+ *
+ * In such case, the process would only be able to control interfaces of a given kind.
+
+ * \param domain Socket domain to use (e.g. AF_CAN), see socket(2) for details
+ */
+void useSocketDomain(int domain);
+
/**
* Checks, if the network interface exists.
*
@@ -38,6 +54,36 @@
std::optional<bool> isUp(std::string ifname);
/**
+ * Interface condition to wait for.
+ */
+enum class WaitCondition {
+ /**
+ * Interface is present (but not necessarily up).
+ */
+ PRESENT,
+
+ /**
+ * Interface is up.
+ */
+ PRESENT_AND_UP,
+
+ /**
+ * Interface is down or not present (disconnected) at all.
+ */
+ DOWN_OR_GONE,
+};
+
+/**
+ * Listens for interface changes until anticipated condition takes place.
+ *
+ * \param ifnames List of interfaces to watch for.
+ * \param cnd Awaited condition.
+ * \param allOf true if all interfaces need to satisfy the condition, false if only one satistying
+ * interface should stop the wait.
+ */
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
+
+/**
* Brings network interface up.
*
* \param ifname Interface to bring up
@@ -70,4 +116,22 @@
*/
bool del(std::string dev);
+/**
+ * Fetches interface's hardware address.
+ *
+ * \param ifname Interface name
+ * \return Hardware address (MAC address) or nullopt if the lookup failed
+ */
+std::optional<hwaddr_t> getHwAddr(const std::string& ifname);
+
+/**
+ * Changes interface's hardware address.
+ *
+ * \param ifname Interface name
+ * \param hwaddr New hardware address to set
+ */
+bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr);
+
} // namespace android::netdevice
+
+bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]);
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
new file mode 100644
index 0000000..3e1b736
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
@@ -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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::netdevice::vlan {
+
+bool add(const std::string& eth, const std::string& vlan, uint16_t id);
+
+} // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index b051442..4c5b309 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -16,83 +16,178 @@
#include <libnetdevice/libnetdevice.h>
-#include "NetlinkRequest.h"
-#include "NetlinkSocket.h"
#include "common.h"
+#include "ifreqs.h"
#include <android-base/logging.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
#include <linux/can.h>
+#include <linux/rtnetlink.h>
#include <net/if.h>
+#include <sstream>
+
namespace android::netdevice {
+void useSocketDomain(int domain) {
+ ifreqs::socketDomain = domain;
+}
+
bool exists(std::string ifname) {
return nametoindex(ifname) != 0;
}
-static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
- /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
- * but SEPolicy forces us to limit our flexibility here. */
- base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
- if (!sock.ok()) {
- LOG(ERROR) << "Can't create socket";
- return false;
- }
-
- if (ioctl(sock.get(), request, &ifr) < 0) {
- PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
- return false;
- }
-
- return true;
-}
-
-static struct ifreq ifreqFromName(const std::string& ifname) {
- struct ifreq ifr = {};
- strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
- return ifr;
-}
-
-std::optional<bool> isUp(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
- return ifr.ifr_flags & IFF_UP;
-}
-
bool up(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
ifr.ifr_flags |= IFF_UP;
- return sendIfreq(SIOCSIFFLAGS, ifr);
+ return ifreqs::send(SIOCSIFFLAGS, ifr);
}
bool down(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
ifr.ifr_flags &= ~IFF_UP;
- return sendIfreq(SIOCSIFFLAGS, ifr);
+ return ifreqs::send(SIOCSIFFLAGS, ifr);
}
bool add(std::string dev, std::string type) {
- NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, type);
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, type);
}
- NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
bool del(std::string dev) {
- NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
- NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
+}
+
+std::optional<hwaddr_t> getHwAddr(const std::string& ifname) {
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
+
+ hwaddr_t hwaddr;
+ memcpy(hwaddr.data(), ifr.ifr_hwaddr.sa_data, hwaddr.size());
+ return hwaddr;
+}
+
+bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) {
+ auto ifr = ifreqs::fromName(ifname);
+
+ // fetch sa_family
+ if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return false;
+
+ memcpy(ifr.ifr_hwaddr.sa_data, hwaddr.data(), hwaddr.size());
+ return ifreqs::send(SIOCSIFHWADDR, ifr);
+}
+
+std::optional<bool> isUp(std::string ifname) {
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
+ return ifr.ifr_flags & IFF_UP;
+}
+
+struct WaitState {
+ bool present;
+ bool up;
+
+ bool satisfied(WaitCondition cnd) const {
+ switch (cnd) {
+ case WaitCondition::PRESENT:
+ if (present) return true;
+ break;
+ case WaitCondition::PRESENT_AND_UP:
+ if (present && up) return true;
+ break;
+ case WaitCondition::DOWN_OR_GONE:
+ if (!present || !up) return true;
+ break;
+ }
+ return false;
+ }
+};
+
+static std::string toString(WaitCondition cnd) {
+ switch (cnd) {
+ case WaitCondition::PRESENT:
+ return "become present";
+ case WaitCondition::PRESENT_AND_UP:
+ return "come up";
+ case WaitCondition::DOWN_OR_GONE:
+ return "go down";
+ }
+}
+
+static std::string toString(const std::set<std::string>& ifnames) {
+ std::stringstream ss;
+ std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
+ auto str = ss.str();
+ str.pop_back();
+ return str;
+}
+
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
+ nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+
+ using StatesMap = std::map<std::string, WaitState>;
+ StatesMap states = {};
+ for (const auto ifname : ifnames) {
+ const auto present = exists(ifname);
+ const auto up = present && isUp(ifname).value_or(false);
+ states[ifname] = {present, up};
+ }
+
+ const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
+ return it.second.satisfied(cnd);
+ };
+ const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() {
+ if (allOf) {
+ return std::all_of(states.begin(), states.end(), mapConditionChecker);
+ } else {
+ return std::any_of(states.begin(), states.end(), mapConditionChecker);
+ }
+ };
+
+ if (isFullySatisfied()) return;
+
+ LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to "
+ << toString(cnd);
+ for (const auto rawMsg : sock) {
+ const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ if (!msg.has_value()) continue;
+
+ const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
+ if (ifnames.count(ifname) == 0) continue;
+
+ const bool present = (msg->header.nlmsg_type != RTM_DELLINK);
+ const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0;
+ states[ifname] = {present, up};
+
+ if (isFullySatisfied()) {
+ LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
+ << " to " << toString(cnd);
+ return;
+ }
+ }
+ LOG(FATAL) << "Can't read Netlink socket";
}
} // namespace android::netdevice
+
+bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
+ static_assert(lhs.size() == ETH_ALEN);
+ return 0 == memcmp(lhs.data(), rhs, lhs.size());
+}
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
new file mode 100644
index 0000000..ee02f7b
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -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.
+ */
+
+#include <libnetdevice/vlan.h>
+
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+
+#include <linux/rtnetlink.h>
+
+namespace android::netdevice::vlan {
+
+bool add(const std::string& eth, const std::string& vlan, uint16_t id) {
+ const auto ethidx = nametoindex(eth);
+ if (ethidx == 0) {
+ LOG(ERROR) << "Ethernet interface " << eth << " doesn't exist";
+ return false;
+ }
+
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, vlan);
+ req.add<uint32_t>(IFLA_LINK, ethidx);
+
+ {
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "vlan");
+
+ {
+ auto linkinfo = req.addNested(IFLA_INFO_DATA);
+ req.add(IFLA_VLAN_ID, id);
+ }
+ }
+
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
+}
+
+} // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
new file mode 100644
index 0000000..4042b16
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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_library_static {
+ name: "libnl++",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor_available: true,
+ srcs: [
+ "protocols/common/Empty.cpp",
+ "protocols/common/Error.cpp",
+ "protocols/generic/Ctrl.cpp",
+ "protocols/generic/Generic.cpp",
+ "protocols/generic/GenericMessageBase.cpp",
+ "protocols/generic/Unknown.cpp",
+ "protocols/route/Link.cpp",
+ "protocols/route/Route.cpp",
+ "protocols/route/structs.cpp",
+ "protocols/MessageDefinition.cpp",
+ "protocols/NetlinkProtocol.cpp",
+ "protocols/all.cpp",
+ "Attributes.cpp",
+ "MessageFactory.cpp",
+ "Socket.cpp",
+ "common.cpp",
+ "printer.cpp",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/default/libnl++/Attributes.cpp b/automotive/can/1.0/default/libnl++/Attributes.cpp
new file mode 100644
index 0000000..620f57b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Attributes.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <libnl++/Attributes.h>
+
+namespace android::nl {
+
+Attributes::Attributes() {}
+
+Attributes::Attributes(Buffer<nlattr> buffer) : Buffer<nlattr>(buffer) {}
+
+const Attributes::Index& Attributes::index() const {
+ if (mIndex.has_value()) return *mIndex;
+
+ mIndex = Index();
+ auto& index = *mIndex;
+
+ for (auto attr : static_cast<Buffer<nlattr>>(*this)) {
+ index.emplace(attr->nla_type, attr);
+ }
+
+ return index;
+}
+
+bool Attributes::contains(nlattrtype_t attrtype) const {
+ return index().count(attrtype) > 0;
+}
+
+/* Parser specializations for selected types (more to come if necessary). */
+
+template <>
+Attributes Attributes::parse(Buffer<nlattr> buf) {
+ return buf.data<nlattr>();
+}
+
+template <>
+std::string Attributes::parse(Buffer<nlattr> buf) {
+ const auto rawString = buf.data<char>().getRaw();
+ std::string str(rawString.ptr(), rawString.len());
+
+ str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
+
+ return str;
+}
+
+template <typename T>
+static T parseUnsigned(Buffer<nlattr> buf) {
+ return buf.data<T>().copyFirst();
+}
+
+template <>
+uint8_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint8_t>(buf);
+}
+
+template <>
+uint16_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint16_t>(buf);
+}
+
+template <>
+uint32_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint32_t>(buf);
+}
+
+template <>
+uint64_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint64_t>(buf);
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/MessageFactory.cpp b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
new file mode 100644
index 0000000..6f35897
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <libnl++/MessageFactory.h>
+
+#include <android-base/logging.h>
+#include <libnl++/bits.h>
+
+namespace android::nl {
+
+static nlattr* tail(nlmsghdr* msg) {
+ return reinterpret_cast<nlattr*>(uintptr_t(msg) + impl::align(msg->nlmsg_len));
+}
+
+nlattr* MessageFactoryBase::add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen) {
+ const auto totalAttrLen = impl::space<nlattr>(dataLen);
+ const auto newLen = impl::align(msg->nlmsg_len) + totalAttrLen;
+ if (newLen > maxLen) {
+ LOG(ERROR) << "Can't add attribute of size " << dataLen //
+ << " - exceeded maxLen: " << newLen << " > " << maxLen;
+ return nullptr;
+ }
+
+ auto attr = tail(msg);
+ attr->nla_len = totalAttrLen;
+ attr->nla_type = type;
+ if (dataLen > 0) memcpy(impl::data<nlattr, void>(attr), data, dataLen);
+
+ msg->nlmsg_len = newLen;
+ return attr;
+}
+
+void MessageFactoryBase::closeNested(nlmsghdr* msg, nlattr* nested) {
+ if (nested == nullptr) return;
+ nested->nla_len = uintptr_t(tail(msg)) - uintptr_t(nested);
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
new file mode 100644
index 0000000..514d9bb
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#include <libnl++/Socket.h>
+
+#include <libnl++/printer.h>
+
+#include <android-base/logging.h>
+
+namespace android::nl {
+
+/**
+ * Print all outbound/inbound Netlink messages.
+ */
+static constexpr bool kSuperVerbose = false;
+
+Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol) {
+ mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+ if (!mFd.ok()) {
+ PLOG(ERROR) << "Can't open Netlink socket";
+ mFailed = true;
+ return;
+ }
+
+ sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pid = pid;
+ sa.nl_groups = groups;
+
+ if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
+ PLOG(ERROR) << "Can't bind Netlink socket";
+ mFd.reset();
+ mFailed = true;
+ }
+}
+
+bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
+ if constexpr (kSuperVerbose) {
+ LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
+ << toString(msg, mProtocol);
+ }
+ if (mFailed) return false;
+
+ mSeq = msg->nlmsg_seq;
+ const auto rawMsg = msg.getRaw();
+ const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
+ reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
+ if (bytesSent < 0) {
+ PLOG(ERROR) << "Can't send Netlink message";
+ return false;
+ } else if (size_t(bytesSent) != rawMsg.len()) {
+ LOG(ERROR) << "Can't send Netlink message: truncated message";
+ return false;
+ }
+ return true;
+}
+
+bool Socket::increaseReceiveBuffer(size_t maxSize) {
+ if (maxSize == 0) {
+ LOG(ERROR) << "Maximum receive size should not be zero";
+ return false;
+ }
+
+ if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+ return true;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
+ return receiveFrom(maxSize).first;
+}
+
+std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
+ if (mFailed) return {std::nullopt, {}};
+
+ if (!increaseReceiveBuffer(maxSize)) return {std::nullopt, {}};
+
+ sockaddr_nl sa = {};
+ socklen_t saLen = sizeof(sa);
+ const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), maxSize, MSG_TRUNC,
+ reinterpret_cast<sockaddr*>(&sa), &saLen);
+
+ if (bytesReceived <= 0) {
+ PLOG(ERROR) << "Failed to receive Netlink message";
+ return {std::nullopt, {}};
+ } else if (size_t(bytesReceived) > maxSize) {
+ PLOG(ERROR) << "Received data larger than maximum receive size: " //
+ << bytesReceived << " > " << maxSize;
+ return {std::nullopt, {}};
+ }
+
+ Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
+ if constexpr (kSuperVerbose) {
+ LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
+ }
+ return {msg, sa};
+}
+
+bool Socket::receiveAck(uint32_t seq) {
+ const auto nlerr = receive<nlmsgerr>({NLMSG_ERROR});
+ if (!nlerr.has_value()) return false;
+
+ if (nlerr->data.msg.nlmsg_seq != seq) {
+ LOG(ERROR) << "Received ACK for a different message (" << nlerr->data.msg.nlmsg_seq
+ << ", expected " << seq << "). Multi-message tracking is not implemented.";
+ return false;
+ }
+
+ if (nlerr->data.error == 0) return true;
+
+ LOG(WARNING) << "Received Netlink error message: " << strerror(-nlerr->data.error);
+ return false;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(const std::set<nlmsgtype_t>& msgtypes,
+ size_t maxSize) {
+ if (mFailed || !increaseReceiveBuffer(maxSize)) return std::nullopt;
+
+ for (const auto rawMsg : *this) {
+ if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
+ LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
+ << rawMsg->nlmsg_type;
+ continue;
+ }
+
+ return rawMsg;
+ }
+
+ return std::nullopt;
+}
+
+std::optional<unsigned> Socket::getPid() {
+ if (mFailed) return std::nullopt;
+
+ sockaddr_nl sa = {};
+ socklen_t sasize = sizeof(sa);
+ if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
+ PLOG(ERROR) << "Failed to get PID of Netlink socket";
+ return std::nullopt;
+ }
+ return sa.nl_pid;
+}
+
+pollfd Socket::preparePoll(short events) {
+ return {mFd.get(), events, 0};
+}
+
+Socket::receive_iterator::receive_iterator(Socket& socket, bool end)
+ : mSocket(socket), mIsEnd(end) {
+ if (!end) receive();
+}
+
+Socket::receive_iterator Socket::receive_iterator::operator++() {
+ CHECK(!mIsEnd) << "Trying to increment end iterator";
+ ++mCurrent;
+ if (mCurrent.isEnd()) receive();
+ return *this;
+}
+
+bool Socket::receive_iterator::operator==(const receive_iterator& other) const {
+ if (mIsEnd != other.mIsEnd) return false;
+ if (mIsEnd && other.mIsEnd) return true;
+ return mCurrent == other.mCurrent;
+}
+
+const Buffer<nlmsghdr>& Socket::receive_iterator::operator*() const {
+ CHECK(!mIsEnd) << "Trying to dereference end iterator";
+ return *mCurrent;
+}
+
+void Socket::receive_iterator::receive() {
+ CHECK(!mIsEnd) << "Trying to receive on end iterator";
+ CHECK(mCurrent.isEnd()) << "Trying to receive without draining previous read";
+
+ const auto buf = mSocket.receive();
+ if (buf.has_value()) {
+ mCurrent = buf->begin();
+ } else {
+ mIsEnd = true;
+ }
+}
+
+Socket::receive_iterator Socket::begin() {
+ return {*this, false};
+}
+
+Socket::receive_iterator Socket::end() {
+ return {*this, true};
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
new file mode 100644
index 0000000..23c2d94
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android::nl {
+
+unsigned int nametoindex(const std::string& ifname) {
+ const auto ifidx = if_nametoindex(ifname.c_str());
+ if (ifidx != 0) return ifidx;
+
+ if (errno != ENODEV) {
+ PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
+ }
+ return 0;
+}
+
+std::string printableOnly(std::string str) {
+ const auto isInvalid = [](char c) { return !isprint(c); };
+ std::replace_if(str.begin(), str.end(), isInvalid, '?');
+
+ return str;
+}
+
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc) {
+ for (const auto byte : data.getRaw()) {
+ crc ^= byte;
+ for (unsigned i = 0; i < 8; i++) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ 0xA001;
+ } else {
+ crc >>= 1;
+ }
+ }
+ }
+ return crc;
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/common.h b/automotive/can/1.0/default/libnl++/common.h
new file mode 100644
index 0000000..38263c5
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/common.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+
+#include <linux/can.h>
+#include <net/if.h>
+
+#include <string>
+
+namespace android::nl {
+
+/**
+ * Returns the index of a given network interface.
+ *
+ * If the syscall to check the index fails with other error than ENODEV, it gets logged and the
+ * return value indicates the interface doesn't exists.
+ *
+ * \param ifname Interface to check
+ * \return Interface index, or 0 if the interface doesn't exist
+ */
+unsigned int nametoindex(const std::string& ifname);
+
+/**
+ * Filter a string against non-printable characters.
+ *
+ * Replaces all non-printable characters with '?'.
+ *
+ * \param str String to filter.
+ * \return Filtered string.
+ */
+std::string printableOnly(std::string str);
+
+/**
+ * Calculates a (optionally running) CRC16 checksum.
+ *
+ * CRC16 isn't a strong checksum, but is good for quick comparison purposes.
+ * One benefit (and also a drawback too) is that all-zero payloads with any length will
+ * always have a checksum of 0x0000.
+ *
+ * \param data Buffer to calculate checksum for
+ * \param crc Previous CRC16 value to continue calculating running checksum
+ * \return CRC16 checksum
+ */
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc = 0);
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
new file mode 100644
index 0000000..f16d997
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
@@ -0,0 +1,170 @@
+/*
+ * 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-base/logging.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+#include <utils/Mutex.h>
+
+#include <map>
+
+namespace android::nl {
+
+/**
+ * Netlink attribute map.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message attributes. The class doesn't own the underlying data, so the instance is valid as long
+ * as the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+class Attributes : private Buffer<nlattr> {
+ public:
+ /**
+ * Constructs empty attribute map.
+ */
+ Attributes();
+
+ /**
+ * Construct attribute map from underlying buffer.
+ *
+ * \param buffer Source buffer pointing at the first attribute.
+ */
+ Attributes(Buffer<nlattr> buffer);
+
+ /**
+ * Checks, if the map contains given attribute type (key).
+ *
+ * \param attrtype Attribute type (such as IFLA_IFNAME).
+ * \return true if attribute is in the map, false otherwise.
+ */
+ bool contains(nlattrtype_t attrtype) const;
+
+ /**
+ * Fetches attribute of a given type by copying it.
+ *
+ * While this is quite efficient for simple types, fetching nested attribute creates a new copy
+ * of child attribute map. This may be costly if you calculate the index for child maps multiple
+ * times. Examples below.
+ *
+ * BAD:
+ * ```
+ * const auto flags = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC).
+ * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index lazy-calculated
+ * get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
+ * const auto& cacheinfo = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC). // new instance of IFLA_AF_SPEC index
+ * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index calculated again
+ * getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // AF_INET6 calculated again
+ * ```
+ *
+ * GOOD:
+ * ```
+ * const auto inet6 = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC).
+ * get<nl::Attributes>(AF_INET6);
+ * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
+ * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // index reused
+ * ```
+ *
+ * If the attribute doesn't exists, default value of a given type is returned and warning
+ * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+ *
+ * \param attrtype Attribute to fetch.
+ * \return Attribute value.
+ */
+ template <typename T>
+ T get(nlattrtype_t attrtype) const {
+ const auto& ind = index();
+ const auto it = ind.find(attrtype);
+ if (it == ind.end()) {
+ LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+ return T{};
+ }
+
+ return parse<T>(it->second);
+ }
+
+ /**
+ * Fetches a reference to a given attribute's data.
+ *
+ * This method is intended for arbitrary structures not specialized with get(nlattrtype_t)
+ * template and slightly more efficient for larger payloads due to not copying its data.
+ *
+ * If the attribute doesn't exists, a reference to empty value of a given type is returned and
+ * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+ *
+ * \param attrtype Attribute to fetch.
+ * \return Reference to the attribute's data.
+ */
+ template <typename T>
+ const T& getStruct(nlattrtype_t attrtype) const {
+ const auto& ind = index();
+ const auto it = ind.find(attrtype);
+ if (it == ind.end()) {
+ LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+ static const T empty = {};
+ return empty;
+ }
+
+ const auto& [ok, val] = it->second.data<T>().getFirst();
+ if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T);
+ return val;
+ }
+
+ private:
+ using Index = std::map<nlattrtype_t, Buffer<nlattr>>;
+
+ /**
+ * Attribute index.
+ *
+ * Since this field is not protected by mutex, the use of \see index() dependent methods
+ * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the
+ * following assumptions:
+ *
+ * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the
+ * buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the
+ * underlying data buffer.
+ *
+ * 2. Index calculation and access would come with performance penalty never justified in most
+ * or all use cases (see the previous point). Since Index is not a trivially assignable data
+ * structure, it's not possible to use it with atomic types only and avoid mutexes.
+ */
+ mutable std::optional<Index> mIndex;
+
+ /**
+ * Lazy-calculate and cache index.
+ *
+ * \return Attribute index.
+ */
+ const Index& index() const;
+
+ /**
+ * Parse attribute data into a specific type.
+ *
+ * \param buf Raw attribute data.
+ * \return Parsed data.
+ */
+ template <typename T>
+ static T parse(Buffer<nlattr> buf);
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
new file mode 100644
index 0000000..bf83fbc
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <libnl++/bits.h>
+
+#include <linux/netlink.h>
+
+#include <optional>
+
+namespace android::nl {
+
+/**
+ * Buffer wrapper containing netlink structure (e.g. nlmsghdr, nlattr).
+ *
+ * This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
+ *
+ * While netlink structures contain information about their total length (with payload), they can
+ * not be trusted - the value may either be larger than the buffer message is allocated in or
+ * smaller than the header itself (so it couldn't even fit itself).
+ *
+ * As a solution, Buffer<> keeps track of two lengths (both attribute for header with payload):
+ * - buffer length - how much memory was allocated to a given structure
+ * - declared length - what nlmsg_len or nla_len says how long the structure is
+ *
+ * In most cases buffer length would be larger than declared length (or equal - modulo alignment -
+ * for continuous data). If that's not the case, there is a potential of ouf-of-bounds read which
+ * this template attempts to protect against.
+ */
+template <typename T>
+class Buffer {
+ public:
+ /**
+ * Constructs empty buffer of size 0.
+ */
+ Buffer() : mData(nullptr), mBufferEnd(nullptr) {}
+
+ /**
+ * Buffer constructor.
+ *
+ * \param data A pointer to the data the Buffer wraps.
+ * \param bufLen Length of the buffer.
+ */
+ Buffer(const T* data, size_t bufLen) : mData(data), mBufferEnd(pointerAdd(data, bufLen)) {}
+
+ const T* operator->() const {
+ CHECK(firstOk()) << "buffer can't fit the first element's header";
+ return mData;
+ }
+
+ std::pair<bool, const T&> getFirst() const {
+ if (!ok()) {
+ static const T empty = {};
+ return {false, empty};
+ }
+ return {true, *mData};
+ }
+
+ /**
+ * Copy the first element of the buffer.
+ *
+ * This is a memory-safe cast operation, useful for reading e.g. uint32_t values
+ * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is
+ * padded with default constructor output (usually zeros).
+ */
+ T copyFirst() const {
+ T val = {};
+ memcpy(&val, mData, std::min(sizeof(val), remainingLength()));
+ return val;
+ }
+
+ bool firstOk() const { return sizeof(T) <= remainingLength(); }
+
+ template <typename D>
+ const Buffer<D> data(size_t offset = 0) const {
+ return {impl::data<const T, const D>(mData, offset), dataEnd()};
+ }
+
+ class iterator {
+ public:
+ iterator() : mCurrent(nullptr, size_t(0)) {
+ CHECK(isEnd()) << "end() iterator should indicate it's beyond end";
+ }
+ iterator(const Buffer<T>& buf) : mCurrent(buf) {}
+
+ iterator operator++() {
+ // mBufferEnd stays the same
+ mCurrent.mData = reinterpret_cast<const T*>( //
+ uintptr_t(mCurrent.mData) + impl::align(mCurrent.declaredLength()));
+
+ return *this;
+ }
+
+ bool operator==(const iterator& other) const {
+ // all iterators beyond end are the same
+ if (isEnd() && other.isEnd()) return true;
+
+ return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
+ }
+
+ const Buffer<T>& operator*() const { return mCurrent; }
+
+ bool isEnd() const { return !mCurrent.ok(); }
+
+ protected:
+ Buffer<T> mCurrent;
+ };
+ iterator begin() const { return {*this}; }
+ iterator end() const { return {}; }
+
+ class raw_iterator : public iterator {
+ public:
+ iterator operator++() {
+ this->mCurrent.mData++; // ignore alignment
+ return *this;
+ }
+ const T& operator*() const { return *this->mCurrent.mData; }
+ };
+
+ class raw_view {
+ public:
+ raw_view(const Buffer<T>& buffer) : mBuffer(buffer) {}
+ raw_iterator begin() const { return {mBuffer}; }
+ raw_iterator end() const { return {}; }
+
+ const T* ptr() const { return mBuffer.mData; }
+ size_t len() const { return mBuffer.remainingLength(); }
+
+ private:
+ const Buffer<T> mBuffer;
+ };
+
+ raw_view getRaw() const { return {*this}; }
+
+ private:
+ const T* mData;
+ const void* mBufferEnd;
+
+ Buffer(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
+
+ bool ok() const { return declaredLength() <= remainingLength(); }
+
+ // to be specialized individually for each T with payload after a header
+ inline size_t declaredLengthImpl() const { return sizeof(T); }
+
+ size_t declaredLength() const {
+ // We can't even fit a header, so let's return some absurd high value to trip off
+ // buffer overflow checks.
+ static constexpr size_t badHeaderLength = std::numeric_limits<size_t>::max() / 2;
+
+ if (sizeof(T) > remainingLength()) return badHeaderLength;
+ const auto len = declaredLengthImpl();
+ if (sizeof(T) > len) return badHeaderLength;
+ return len;
+ }
+
+ size_t remainingLength() const {
+ auto len = intptr_t(mBufferEnd) - intptr_t(mData);
+ return (len >= 0) ? len : 0;
+ }
+
+ const void* dataEnd() const {
+ auto declaredEnd = pointerAdd(mData, declaredLength());
+ return std::min(declaredEnd, mBufferEnd);
+ }
+
+ static const void* pointerAdd(const void* ptr, size_t len) {
+ return reinterpret_cast<const void*>(uintptr_t(ptr) + len);
+ }
+
+ template <typename D>
+ friend class Buffer; // calling private constructor of data buffers
+};
+
+template <>
+inline size_t Buffer<nlmsghdr>::declaredLengthImpl() const {
+ return mData->nlmsg_len;
+}
+
+template <>
+inline size_t Buffer<nlattr>::declaredLengthImpl() const {
+ return mData->nla_len;
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Message.h b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
new file mode 100644
index 0000000..50b3c4b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <libnl++/Attributes.h>
+#include <libnl++/Buffer.h>
+
+#include <set>
+
+namespace android::nl {
+
+/**
+ * In-place Netlink message parser.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message contents. The class doesn't own the underlying data, so the instance is valid as long as
+ * the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+template <typename T>
+class Message {
+ public:
+ /**
+ * Validate buffer contents as a message carrying T data and create instance of parsed message.
+ *
+ * \param buf Buffer containing the message.
+ * \return Parsed message or nullopt, if the buffer data is invalid.
+ */
+ static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf) {
+ const auto& [nlOk, nlHeader] = buf.getFirst();
+ if (!nlOk) return std::nullopt;
+
+ const auto& [dataOk, dataHeader] = buf.data<T>().getFirst();
+ if (!dataOk) return std::nullopt;
+
+ const auto attributes = buf.data<nlattr>(sizeof(T));
+
+ return Message<T>(nlHeader, dataHeader, attributes);
+ }
+
+ /**
+ * Validate buffer contents as a message of a given type and create instance of parsed message.
+ *
+ * \param buf Buffer containing the message.
+ * \param msgtypes Acceptable message types (within a specific Netlink protocol)
+ * \return Parsed message or nullopt, if the buffer data is invalid or message type
+ * doesn't match.
+ */
+ static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf,
+ const std::set<nlmsgtype_t>& msgtypes) {
+ const auto& [nlOk, nlHeader] = buf.getFirst(); // we're doing it twice, but it's fine
+ if (!nlOk) return std::nullopt;
+
+ if (msgtypes.count(nlHeader.nlmsg_type) == 0) return std::nullopt;
+
+ return parse(buf);
+ }
+
+ /**
+ * Netlink message header.
+ *
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ const nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ const T& data;
+
+ /**
+ * Netlink message attributes.
+ */
+ const Attributes attributes;
+
+ const T* operator->() const { return &data; }
+
+ private:
+ Message(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes)
+ : header(nlHeader), data(dataHeader), attributes(attributes) {}
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
new file mode 100644
index 0000000..c3d72c5
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+
+#include <linux/netlink.h>
+
+#include <string>
+
+namespace android::nl {
+
+class MessageFactoryBase {
+ protected:
+ static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen);
+ static void closeNested(nlmsghdr* msg, nlattr* nested);
+};
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T Message payload type (such as ifinfomsg).
+ * \param BUFSIZE how much space to reserve for attributes.
+ */
+template <class T, unsigned int BUFSIZE = 128>
+class MessageFactory : private MessageFactoryBase {
+ struct alignas(NLMSG_ALIGNTO) Message {
+ nlmsghdr header;
+ T data;
+ uint8_t attributesBuffer[BUFSIZE];
+ };
+
+ public:
+ /**
+ * Create empty message.
+ *
+ * \param type Message type (such as RTM_NEWLINK).
+ * \param flags Message flags (such as NLM_F_REQUEST).
+ */
+ MessageFactory(nlmsgtype_t type, uint16_t flags)
+ : header(mMessage.header), data(mMessage.data) {
+ mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
+ mMessage.header.nlmsg_type = type;
+ mMessage.header.nlmsg_flags = flags;
+ }
+
+ /**
+ * Netlink message header.
+ *
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ T& data;
+
+ T* operator->() { return &mMessage.data; }
+
+ /**
+ * Build netlink message.
+ *
+ * In fact, this operation is almost a no-op, since the factory builds the message in a single
+ * buffer, using native data structures.
+ *
+ * A likely failure case is when the BUFSIZE template parameter is too small to acommodate
+ * added attributes. In such a case, please increase this parameter.
+ *
+ * \return Netlink message or std::nullopt in case of failure.
+ */
+ std::optional<Buffer<nlmsghdr>> build() const {
+ if (!mIsGood) return std::nullopt;
+ return {{&mMessage.header, mMessage.header.nlmsg_len}};
+ }
+
+ /**
+ * Adds an attribute of a trivially copyable type.
+ *
+ * Template specializations may extend this function for other types, such as std::string.
+ *
+ * If this method fails (i.e. due to insufficient space), a warning will be printed to the log
+ * and the message will be marked as bad, causing later \see build call to fail.
+ *
+ * \param type attribute type (such as IFLA_IFNAME)
+ * \param attr attribute data
+ */
+ template <class A>
+ void add(nlattrtype_t type, const A& attr) {
+ add(type, &attr, sizeof(attr));
+ }
+
+ template <>
+ void add(nlattrtype_t type, const std::string& s) {
+ add(type, s.c_str(), s.size() + 1);
+ }
+
+ /** Guard class to frame nested attributes. \see addNested(nlattrtype_t). */
+ class [[nodiscard]] NestedGuard {
+ public:
+ NestedGuard(MessageFactory & req, nlattrtype_t type) : mReq(req), mAttr(req.add(type)) {}
+ ~NestedGuard() { closeNested(&mReq.mMessage.header, mAttr); }
+
+ private:
+ MessageFactory& mReq;
+ nlattr* mAttr;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedGuard);
+ };
+
+ /**
+ * Add nested attribute.
+ *
+ * The returned object is a guard for auto-nesting children inside the argument attribute.
+ * When the guard object goes out of scope, the nesting attribute is closed.
+ *
+ * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+ * inside IFLA_LINKINFO:
+ * MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ * {
+ * auto linkinfo = req.addNested(IFLA_LINKINFO);
+ * req.add(IFLA_INFO_KIND, "can");
+ * {
+ * auto infodata = req.addNested(IFLA_INFO_DATA);
+ * req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
+ * }
+ * }
+ * // use req
+ *
+ * \param type attribute type (such as IFLA_LINKINFO)
+ */
+ NestedGuard addNested(nlattrtype_t type) { return {*this, type}; }
+
+ private:
+ Message mMessage = {};
+ bool mIsGood = true;
+
+ nlattr* add(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
+ if (!mIsGood) return nullptr;
+ auto attr = MessageFactoryBase::add(&mMessage.header, sizeof(mMessage), type, data, len);
+ if (attr == nullptr) mIsGood = false;
+ return attr;
+ }
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
new file mode 100644
index 0000000..8ea3575
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/Message.h>
+#include <libnl++/MessageFactory.h>
+
+#include <linux/netlink.h>
+#include <poll.h>
+
+#include <optional>
+#include <set>
+#include <vector>
+
+namespace android::nl {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+class Socket {
+ public:
+ static constexpr size_t defaultReceiveSize = 8192;
+
+ /**
+ * Socket constructor.
+ *
+ * \param protocol the Netlink protocol to use.
+ * \param pid port id. Default value of 0 allows the kernel to assign us a unique pid.
+ * (NOTE: this is NOT the same as process id).
+ * \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
+ * bit is a different group. Default value of 0 means no groups are selected.
+ * See man netlink.7.
+ * for more details.
+ */
+ Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
+
+ /**
+ * Send Netlink message with incremented sequence number to the Kernel.
+ *
+ * \param msg Message to send. Its sequence number will be updated.
+ * \return true, if succeeded.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool send(MessageFactory<T, BUFSIZE>& req) {
+ sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pid = 0; // Kernel
+ return send(req, sa);
+ }
+
+ /**
+ * Send Netlink message with incremented sequence number.
+ *
+ * \param msg Message to send. Its sequence number will be updated.
+ * \param sa Destination address.
+ * \return true, if succeeded.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
+ req.header.nlmsg_seq = mSeq + 1;
+
+ const auto msg = req.build();
+ if (!msg.has_value()) return false;
+
+ return send(*msg, sa);
+ }
+
+ /**
+ * Send Netlink message.
+ *
+ * \param msg Message to send.
+ * \param sa Destination address.
+ * \return true, if succeeded.
+ */
+ bool send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa);
+
+ /**
+ * Receive one or multiple Netlink messages.
+ *
+ * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+ * call to the read function or until deallocation of Socket instance.
+ *
+ * \param maxSize Maximum total size of received messages
+ * \return Buffer view with message data, std::nullopt on error.
+ */
+ std::optional<Buffer<nlmsghdr>> receive(size_t maxSize = defaultReceiveSize);
+
+ /**
+ * Receive one or multiple Netlink messages and the sender process address.
+ *
+ * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+ * call to the read function or until deallocation of Socket instance.
+ *
+ * \param maxSize Maximum total size of received messages.
+ * \return A pair (for use with structured binding) containing:
+ * - buffer view with message data, std::nullopt on error;
+ * - sender process address.
+ */
+ std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> receiveFrom(
+ size_t maxSize = defaultReceiveSize);
+
+ /**
+ * Receive matching Netlink message of a given payload type.
+ *
+ * This method should be used if the caller expects exactly one incoming message of exactly
+ * given type (such as ACK). If there is a use case to handle multiple types of messages,
+ * please use receive(size_t) directly and iterate through potential multipart messages.
+ *
+ * If this method is used in such an environment, it will only return the first matching message
+ * from multipart packet and will issue warnings on messages that do not match.
+ *
+ * \param msgtypes Expected message types (such as NLMSG_ERROR).
+ * \param maxSize Maximum total size of received messages.
+ * \return Parsed message or std::nullopt in case of error.
+ */
+ template <typename T>
+ std::optional<Message<T>> receive(const std::set<nlmsgtype_t>& msgtypes,
+ size_t maxSize = defaultReceiveSize) {
+ const auto msg = receive(msgtypes, maxSize);
+ if (!msg.has_value()) return std::nullopt;
+
+ const auto parsed = Message<T>::parse(*msg);
+ if (!parsed.has_value()) {
+ LOG(WARNING) << "Received matching Netlink message, but couldn't parse it";
+ return std::nullopt;
+ }
+
+ return parsed;
+ }
+
+ /**
+ * Receive Netlink ACK message.
+ *
+ * \param req Message to match sequence number against.
+ * \return true if received ACK message, false in case of error.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool receiveAck(MessageFactory<T, BUFSIZE>& req) {
+ return receiveAck(req.header.nlmsg_seq);
+ }
+
+ /**
+ * Receive Netlink ACK message.
+ *
+ * \param seq Sequence number of message to ACK.
+ * \return true if received ACK message, false in case of error.
+ */
+ bool receiveAck(uint32_t seq);
+
+ /**
+ * Fetches the socket PID.
+ *
+ * \return PID that socket is bound to or std::nullopt.
+ */
+ std::optional<unsigned> getPid();
+
+ /**
+ * Creates a pollfd object for the socket.
+ *
+ * \param events Value for pollfd.events.
+ * \return A populated pollfd object.
+ */
+ pollfd preparePoll(short events = 0);
+
+ /**
+ * Live iterator continuously receiving messages from Netlink socket.
+ *
+ * Iteration ends when socket fails to receive a buffer.
+ *
+ * Example:
+ * ```
+ * nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+ * for (const auto rawMsg : sock) {
+ * const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ * if (!msg.has_value()) continue;
+ *
+ * LOG(INFO) << msg->attributes.get<std::string>(IFLA_IFNAME)
+ * << " is " << ((msg->data.ifi_flags & IFF_UP) ? "up" : "down");
+ * }
+ * LOG(FATAL) << "Failed to read from Netlink socket";
+ * ```
+ */
+ class receive_iterator {
+ public:
+ receive_iterator(Socket& socket, bool end);
+
+ receive_iterator operator++();
+ bool operator==(const receive_iterator& other) const;
+ const Buffer<nlmsghdr>& operator*() const;
+
+ private:
+ Socket& mSocket;
+ bool mIsEnd;
+ Buffer<nlmsghdr>::iterator mCurrent;
+
+ void receive();
+ };
+ receive_iterator begin();
+ receive_iterator end();
+
+ private:
+ const int mProtocol;
+ base::unique_fd mFd;
+ std::vector<uint8_t> mReceiveBuffer;
+
+ bool mFailed = false;
+ uint32_t mSeq = 0;
+
+ bool increaseReceiveBuffer(size_t maxSize);
+ std::optional<Buffer<nlmsghdr>> receive(const std::set<nlmsgtype_t>& msgtypes, size_t maxSize);
+
+ DISALLOW_COPY_AND_ASSIGN(Socket);
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/bits.h b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
new file mode 100644
index 0000000..4c8f1aa
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
@@ -0,0 +1,54 @@
+/*
+ * 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>
+
+namespace android::nl::impl {
+
+// The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h.
+
+/**
+ * Equivalent to NLMSG_ALIGNTO.
+ */
+constexpr size_t alignto = NLMSG_ALIGNTO;
+static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
+
+/**
+ * Equivalent to NLMSG_ALIGN(len).
+ */
+constexpr size_t align(size_t len) {
+ return (len + alignto - 1) & ~(alignto - 1);
+}
+
+/**
+ * Equivalent to NLMSG_SPACE(len).
+ */
+template <typename H>
+constexpr size_t space(size_t len) {
+ return align(align(sizeof(H)) + len);
+}
+
+/**
+ * Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset).
+ */
+template <typename H, typename D>
+constexpr D* data(H* header, size_t offset = 0) {
+ return reinterpret_cast<D*>(uintptr_t(header) + space<H>(offset));
+}
+
+} // namespace android::nl::impl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
new file mode 100644
index 0000000..3570918
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/printer.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 <libnl++/Buffer.h>
+
+#include <linux/netlink.h>
+
+#include <string>
+
+namespace android::nl {
+
+/**
+ * Stringify a Netlink message.
+ *
+ * \param hdr Pointer to the message(s) to print.
+ * \param protocol Which Netlink protocol hdr uses.
+ * \param printPayload True will stringify message data, false will only stringify the header(s).
+ * \return Stringified message.
+ */
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = true);
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/types.h b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
new file mode 100644
index 0000000..567590b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
@@ -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.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+
+namespace android::nl {
+
+typedef decltype(nlmsghdr::nlmsg_type) nlmsgtype_t;
+typedef decltype(nlattr::nla_type) nlattrtype_t;
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
new file mode 100644
index 0000000..e6cada2
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 <libnl++/printer.h>
+
+#include "common.h"
+#include "protocols/all.h"
+
+#include <android-base/logging.h>
+#include <libnl++/Buffer.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+
+namespace android::nl {
+
+static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
+ bool first = true;
+ auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
+ if ((nlmsg_flags & flag) != flag) return;
+ nlmsg_flags &= ~flag;
+
+ if (first) {
+ first = false;
+ } else {
+ ss << '|';
+ }
+
+ ss << name;
+ };
+
+ printFlag(NLM_F_REQUEST, "REQUEST");
+ printFlag(NLM_F_MULTI, "MULTI");
+ printFlag(NLM_F_ACK, "ACK");
+ printFlag(NLM_F_ECHO, "ECHO");
+ printFlag(NLM_F_DUMP_INTR, "DUMP_INTR");
+ printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
+
+ switch (genre) {
+ case protocols::MessageGenre::UNKNOWN:
+ break;
+ 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:
+ 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:
+ printFlag(NLM_F_NONREC, "NONREC");
+ break;
+ case protocols::MessageGenre::ACK:
+ printFlag(NLM_F_CAPPED, "CAPPED");
+ printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
+ break;
+ }
+
+ if (nlmsg_flags != 0) {
+ if (!first) ss << '|';
+ ss << std::hex << nlmsg_flags << std::dec;
+ }
+}
+
+static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
+ const auto rawData = data.getRaw();
+ const auto dataLen = rawData.len();
+ ss << std::hex;
+ int i = 0;
+ for (const auto byte : rawData) {
+ if (i % 16 == 0 && dataLen > 16) {
+ ss << std::endl << ' ' << std::dec << std::setw(4) << i << std::hex;
+ }
+ if (i++ > 0 || dataLen > 16) ss << ' ';
+ ss << std::setw(2) << unsigned(byte);
+ }
+ ss << std::dec;
+ if (dataLen > 16) ss << std::endl;
+}
+
+static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
+ const protocols::AttributeMap& attrMap) {
+ using DataType = protocols::AttributeDefinition::DataType;
+ const auto attrtype = attrMap[attr->nla_type];
+
+ ss << attrtype.name << ": ";
+ switch (attrtype.dataType) {
+ case DataType::Raw:
+ toStream(ss, attr.data<uint8_t>());
+ break;
+ case DataType::Nested: {
+ ss << '{';
+ bool first = true;
+ for (const auto childattr : attr.data<nlattr>()) {
+ if (!first) ss << ", ";
+ first = false;
+ toStream(ss, childattr, std::get<protocols::AttributeMap>(attrtype.ops));
+ }
+ ss << '}';
+ break;
+ }
+ case DataType::String: {
+ const auto str = attr.data<char>().getRaw();
+ ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
+ break;
+ }
+ case DataType::Uint:
+ ss << attr.data<uint32_t>().copyFirst();
+ break;
+ case DataType::Struct: {
+ const auto structToStream =
+ std::get<protocols::AttributeDefinition::ToStream>(attrtype.ops);
+ structToStream(ss, attr);
+ break;
+ }
+ }
+}
+
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload) {
+ if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
+
+ std::stringstream ss;
+ ss << std::setfill('0');
+
+ auto protocolMaybe = protocols::get(protocol);
+ if (!protocolMaybe.has_value()) {
+ ss << "nlmsg{protocol=" << protocol << "}";
+ return ss.str();
+ }
+ protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
+
+ const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
+ const auto msgDetails =
+ protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
+
+ ss << "nlmsg{" << protocolDescr.getName() << " ";
+
+ ss << "hdr={";
+ ss << "type=" << msgDetails.name;
+ if (hdr->nlmsg_flags != 0) {
+ ss << ", flags=";
+ flagsToStream(ss, hdr->nlmsg_flags, msgDetails.genre);
+ }
+ if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
+ if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
+ ss << ", len=" << hdr->nlmsg_len;
+ ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
+ ss << '}';
+
+ if (!printPayload) return ss.str();
+ ss << ' ';
+
+ if (!msgDescMaybe.has_value()) {
+ toStream(ss, hdr.data<uint8_t>());
+ } else {
+ const protocols::MessageDescriptor& msgDesc = *msgDescMaybe;
+ msgDesc.dataToStream(ss, hdr);
+
+ bool first = true;
+ for (auto attr : hdr.data<nlattr>(msgDesc.getContentsSize())) {
+ if (first) {
+ ss << " attributes: {";
+ first = false;
+ } else {
+ ss << ", ";
+ }
+ toStream(ss, attr, msgDesc.getAttributeMap());
+ }
+ if (!first) ss << '}';
+ }
+
+ ss << "}";
+
+ return ss.str();
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
new file mode 100644
index 0000000..c93d865
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.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 "MessageDefinition.h"
+
+namespace android::nl::protocols {
+
+AttributeMap::AttributeMap(const std::initializer_list<value_type> attrTypes)
+ : std::map<std::optional<nlattrtype_t>, AttributeDefinition>(attrTypes) {}
+
+const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const {
+ if (count(nla_type) == 0) {
+ if (count(std::nullopt) == 0) return {std::to_string(nla_type)};
+
+ auto definition = find(std::nullopt)->second;
+ definition.name += std::to_string(nla_type);
+ return definition;
+ }
+ return find(nla_type)->second;
+}
+
+MessageDescriptor::MessageDescriptor(const std::string& name,
+ const MessageDetailsMap&& messageDetails,
+ const AttributeMap&& attrTypes, size_t contentsSize)
+ : mName(name),
+ mContentsSize(contentsSize),
+ mMessageDetails(messageDetails),
+ mAttributeMap(attrTypes) {}
+
+MessageDescriptor::~MessageDescriptor() {}
+
+size_t MessageDescriptor::getContentsSize() const {
+ return mContentsSize;
+}
+
+const MessageDescriptor::MessageDetailsMap& MessageDescriptor::getMessageDetailsMap() const {
+ return mMessageDetails;
+}
+
+const AttributeMap& MessageDescriptor::getAttributeMap() const {
+ return mAttributeMap;
+}
+
+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};
+ return it->second;
+}
+
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype) {
+ if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
+ return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
+}
+
+} // 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
new file mode 100644
index 0000000..bd0e60f
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -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.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+
+#include <map>
+#include <sstream>
+#include <variant>
+
+namespace android::nl::protocols {
+
+struct AttributeDefinition;
+
+/**
+ * Mapping between nlattrtype_t identifier and attribute definition.
+ *
+ * The map contains values for all nlattrtype_t identifiers - if some is missing, a generic
+ * definition with a identifier as its name will be generated.
+ *
+ * It's possible to define a default attribute to return instead of to_string of its identifier
+ * (useful for nested attribute lists). In such case, an entry with id=std::nullopt needs to be
+ * present in the map.
+ */
+class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefinition> {
+ public:
+ using std::map<std::optional<nlattrtype_t>, AttributeDefinition>::value_type;
+
+ AttributeMap(const std::initializer_list<value_type> attrTypes);
+
+ const AttributeDefinition operator[](nlattrtype_t nla_type) const;
+};
+
+/**
+ * Attribute definition.
+ *
+ * Describes the name and type (optionally sub types, in case of Nested attribute)
+ * for a given message attribute.
+ */
+struct AttributeDefinition {
+ enum class DataType : uint8_t {
+ Raw,
+ Nested,
+ String,
+ Uint,
+ Struct,
+ };
+ 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{};
+};
+
+/**
+ * General message type's kind.
+ *
+ * For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values"
+ * section in linux/netlink.h.
+ */
+enum class MessageGenre {
+ UNKNOWN,
+ GET,
+ NEW,
+ DELETE,
+ ACK,
+};
+
+/**
+ * Message family descriptor.
+ *
+ * Describes the structure of all message types with the same header and attributes.
+ */
+class MessageDescriptor {
+ public:
+ struct MessageDetails {
+ std::string name;
+ MessageGenre genre;
+ };
+ typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap;
+
+ public:
+ virtual ~MessageDescriptor();
+
+ size_t getContentsSize() const;
+ const MessageDetailsMap& getMessageDetailsMap() const;
+ const AttributeMap& getAttributeMap() const;
+ MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
+ virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
+
+ static MessageDetails getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype);
+
+ protected:
+ MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
+ const AttributeMap&& attrTypes, size_t contentsSize);
+
+ private:
+ const std::string mName;
+ const size_t mContentsSize;
+ const MessageDetailsMap mMessageDetails;
+ const AttributeMap mAttributeMap;
+};
+
+/**
+ * Message definition template.
+ *
+ * A convenience initialization helper of a message descriptor.
+ */
+template <typename T>
+class MessageDefinition : public MessageDescriptor {
+ public:
+ MessageDefinition( //
+ const std::string& name,
+ const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
+ const std::initializer_list<AttributeMap::value_type> attrTypes = {})
+ : MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
+
+ void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
+ const auto& [ok, msg] = hdr.data<T>().getFirst();
+ if (!ok) {
+ ss << "{incomplete payload}";
+ return;
+ }
+
+ toStream(ss, msg);
+ }
+
+ protected:
+ virtual void toStream(std::stringstream& ss, const T& data) const = 0;
+};
+
+} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
new file mode 100644
index 0000000..cd2e8c6
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -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.
+ */
+
+#include "NetlinkProtocol.h"
+
+namespace android::nl::protocols {
+
+NetlinkProtocol::NetlinkProtocol(int protocol, const std::string& name,
+ const MessageDescriptorList&& messageDescrs)
+ : mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
+
+NetlinkProtocol::~NetlinkProtocol() {}
+
+int NetlinkProtocol::getProtocol() const {
+ return mProtocol;
+}
+
+const std::string& NetlinkProtocol::getName() const {
+ return mName;
+}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>>
+NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
+ if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
+ return *mMessageDescrs.find(nlmsg_type)->second;
+}
+
+NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
+ const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
+ MessageDescriptorMap map;
+ for (const auto& descr : descrs) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
+ map.emplace(mtype, descr);
+ }
+ }
+
+ const MessageDescriptorList baseDescriptors = {
+ std::make_shared<base::Empty>(),
+ std::make_shared<base::Error>(protocol),
+ };
+
+ for (const auto& descr : baseDescriptors) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
+ map.emplace(mtype, descr);
+ }
+ }
+
+ return map;
+}
+
+} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
new file mode 100644
index 0000000..c969547
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.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.
+ */
+
+#pragma once
+
+#include "MessageDefinition.h"
+#include "common/Empty.h"
+#include "common/Error.h"
+
+#include <libnl++/types.h>
+
+#include <string>
+#include <vector>
+
+namespace android::nl::protocols {
+
+/**
+ * Netlink-based protocol definition.
+ *
+ * Usually it's just an id/name and a list of supported messages.
+ */
+class NetlinkProtocol {
+ public:
+ virtual ~NetlinkProtocol();
+
+ int getProtocol() const;
+
+ const std::string& getName() const;
+
+ virtual const std::optional<std::reference_wrapper<const MessageDescriptor>>
+ getMessageDescriptor(nlmsgtype_t nlmsg_type);
+
+ protected:
+ typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
+
+ NetlinkProtocol(int protocol, const std::string& name,
+ const MessageDescriptorList&& messageDescrs);
+
+ private:
+ typedef std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> MessageDescriptorMap;
+
+ const int mProtocol;
+ const std::string mName;
+ const MessageDescriptorMap mMessageDescrs;
+
+ static MessageDescriptorMap toMap(const MessageDescriptorList& descrs, int protocol);
+};
+
+} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/README b/automotive/can/1.0/default/libnl++/protocols/README
new file mode 100644
index 0000000..45c95c4
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/README
@@ -0,0 +1,8 @@
+This folder contains message definitions for various protocols based on Netlink.
+
+The structure is as follows:
+protocols/*.(cpp|h) - base definition classes and protocol definition lookup
+protocols/common/ - common message types that apply to all protocols
+protocols/<proto>/<proto>.(cpp|h) - protocol definition (usually just a list of message types)
+protocols/<proto>/*.(cpp|h) - message definition that covers all message types with the same
+ header (T type in MessageDefinition template) and attributes
diff --git a/automotive/can/1.0/default/libnl++/protocols/all.cpp b/automotive/can/1.0/default/libnl++/protocols/all.cpp
new file mode 100644
index 0000000..a398dc8
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/all.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "all.h"
+
+#include "generic/Generic.h"
+#include "route/Route.h"
+
+#include <map>
+
+namespace android::nl::protocols {
+
+// This should be a map of unique_ptr, but it's not trivial to uniformly initialize such a map
+static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
+ std::initializer_list<std::shared_ptr<NetlinkProtocol>> l) {
+ std::map<int, std::shared_ptr<NetlinkProtocol>> map;
+ for (auto p : l) {
+ map[p->getProtocol()] = p;
+ }
+ return map;
+}
+
+static auto all = toMap({
+ std::make_unique<generic::Generic>(),
+ std::make_unique<route::Route>(),
+});
+
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
+ if (all.count(protocol) == 0) return std::nullopt;
+ return *all.find(protocol)->second.get();
+}
+
+} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/all.h b/automotive/can/1.0/default/libnl++/protocols/all.h
new file mode 100644
index 0000000..6d6ec1e
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/all.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.
+ */
+
+#pragma once
+
+#include "NetlinkProtocol.h"
+
+namespace android::nl::protocols {
+
+/**
+ * Protocol definition lookup.
+ *
+ * \param protocol Protocol identifier from linux/netlink.h
+ * \return Protocol definition or nullopt if it's not implemented
+ */
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol);
+
+} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
new file mode 100644
index 0000000..8a672d3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
@@ -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.
+ */
+
+#include "Empty.h"
+
+namespace android::nl::protocols::base {
+
+// clang-format off
+Empty::Empty() : MessageDefinition<char>("nlmsg", {
+ {NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
+ {NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
+ {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
+}) {}
+// clang-format on
+
+void Empty::toStream(std::stringstream&, const char&) const {}
+
+} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.h b/automotive/can/1.0/default/libnl++/protocols/common/Empty.h
new file mode 100644
index 0000000..79a0f46
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.h
@@ -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.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+#include <libnl++/printer.h>
+
+namespace android::nl::protocols::base {
+
+// no-payload (like NLMSG_NOOP) messages can't be defined with T=void, so let's use char
+class Empty : public MessageDefinition<char> {
+ public:
+ Empty();
+ void toStream(std::stringstream&, const char&) const override;
+};
+
+} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
new file mode 100644
index 0000000..44708a3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.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 "Error.h"
+
+#include "../MessageDefinition.h"
+
+#include <libnl++/printer.h>
+
+namespace android::nl::protocols::base {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
+ {NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
+}, {
+ {NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
+ {NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
+ {NLMSGERR_ATTR_COOKIE, {"COOKIE", DataType::Raw}},
+}), mProtocol(protocol) {}
+// clang-format on
+
+void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
+ ss << "nlmsgerr{error=" << data.error
+ << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
+}
+
+} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.h b/automotive/can/1.0/default/libnl++/protocols/common/Error.h
new file mode 100644
index 0000000..782986b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.h
@@ -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.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+namespace android::nl::protocols::base {
+
+class Error : public MessageDefinition<nlmsgerr> {
+ public:
+ Error(int protocol);
+ void toStream(std::stringstream& ss, const nlmsgerr& data) const override;
+
+ private:
+ const int mProtocol;
+};
+
+} // 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
new file mode 100644
index 0000000..a3c6736
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
@@ -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.
+ */
+
+#include "Ctrl.h"
+
+namespace android::nl::protocols::generic {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
+ {CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
+ {CTRL_CMD_DELFAMILY, "DELFAMILY"},
+ {CTRL_CMD_GETFAMILY, "GETFAMILY"},
+ {CTRL_CMD_NEWOPS, "NEWOPS"},
+ {CTRL_CMD_DELOPS, "DELOPS"},
+ {CTRL_CMD_GETOPS, "GETOPS"},
+ {CTRL_CMD_NEWMCAST_GRP, "NEWMCAST_GRP"},
+ {CTRL_CMD_DELMCAST_GRP, "DELMCAST_GRP"},
+ {CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
+}, {
+ {CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
+ {CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::String}},
+ {CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
+ {CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
+ {CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
+ {CTRL_ATTR_OPS, {"OPS", DataType::Nested, AttributeMap{
+ {std::nullopt, {"OP", DataType::Nested, AttributeMap{
+ {CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
+ {CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
+ }}},
+ }}},
+ {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_ID, {"ID", DataType::Uint}},
+ }}},
+ }}},
+}) {}
+// clang-format on
+
+} // 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
new file mode 100644
index 0000000..6af87a8
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.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 {
+
+class Ctrl : public GenericMessageBase {
+ public:
+ Ctrl();
+};
+
+} // 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
new file mode 100644
index 0000000..1a24914
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
@@ -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.
+ */
+
+#include "Generic.h"
+
+#include "Ctrl.h"
+#include "Unknown.h"
+
+namespace android::nl::protocols::generic {
+
+Generic::Generic() : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>()}) {}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>> Generic::getMessageDescriptor(
+ nlmsgtype_t nlmsg_type) {
+ const auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
+ if (desc.has_value()) return desc;
+
+ auto it = mFamilyRegister.find(nlmsg_type);
+ if (it != mFamilyRegister.end()) return *it->second;
+ return *(mFamilyRegister[nlmsg_type] = std::make_shared<Unknown>(nlmsg_type));
+}
+
+} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
new file mode 100644
index 0000000..593c92d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.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 "../NetlinkProtocol.h"
+
+namespace android::nl::protocols::generic {
+
+/**
+ * Definition of NETLINK_GENERIC protocol.
+ */
+class Generic : public NetlinkProtocol {
+ public:
+ Generic();
+
+ const std::optional<std::reference_wrapper<const MessageDescriptor>> getMessageDescriptor(
+ nlmsgtype_t nlmsg_type);
+
+ private:
+ std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> 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
new file mode 100644
index 0000000..134638e
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.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 "GenericMessageBase.h"
+
+namespace android::nl::protocols::generic {
+
+GenericMessageBase::GenericMessageBase(
+ 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}}},
+ attrTypes),
+ mCommandNames(commandNames) {}
+
+void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
+ ss << "genlmsghdr{";
+ if (mCommandNames.count(data.cmd) == 0) {
+ ss << "cmd=" << unsigned(data.cmd);
+ } else {
+ ss << "cmd=" << mCommandNames.find(data.cmd)->second;
+ }
+ ss << ", version=" << unsigned(data.version);
+ if (data.reserved != 0) ss << ", reserved=" << data.reserved;
+ ss << "}";
+}
+
+} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
new file mode 100644
index 0000000..443f10c
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.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 "../MessageDefinition.h"
+
+#include <linux/genetlink.h>
+
+namespace android::nl::protocols::generic {
+
+class GenericMessageBase : public MessageDefinition<genlmsghdr> {
+ public:
+ typedef std::map<uint8_t, std::string> GenericCommandNameMap;
+
+ GenericMessageBase(
+ nlmsgtype_t msgtype, const std::string&& msgname,
+ const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
+ const std::initializer_list<AttributeMap::value_type> attrTypes = {});
+
+ void toStream(std::stringstream& ss, const genlmsghdr& data) const override;
+
+ private:
+ const GenericCommandNameMap mCommandNames;
+};
+
+} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp
new file mode 100644
index 0000000..17367f0
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "Unknown.h"
+
+namespace android::nl::protocols::generic {
+
+Unknown::Unknown(nlmsgtype_t msgtype)
+ : GenericMessageBase(msgtype, "Unknown(" + std::to_string(msgtype) + ")") {}
+
+} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.h b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.h
new file mode 100644
index 0000000..62ae19d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.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 {
+
+class Unknown : public GenericMessageBase {
+ public:
+ Unknown(nlmsgtype_t msgtype);
+};
+
+} // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
new file mode 100644
index 0000000..7db487a
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "Link.h"
+
+#include "structs.h"
+
+#include <net/if.h>
+
+namespace android::nl::protocols::route {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Link::Link() : MessageDefinition<ifinfomsg>("link", {
+ {RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
+ {RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
+ {RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
+}, {
+ {IFLA_ADDRESS, {"ADDRESS"}},
+ {IFLA_BROADCAST, {"BROADCAST"}},
+ {IFLA_IFNAME, {"IFNAME", DataType::String}},
+ {IFLA_MTU, {"MTU", DataType::Uint}},
+ {IFLA_LINK, {"LINK", DataType::Uint}},
+ {IFLA_QDISC, {"QDISC", DataType::String}},
+ {IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
+ {IFLA_COST, {"COST"}},
+ {IFLA_PRIORITY, {"PRIORITY"}},
+ {IFLA_MASTER, {"MASTER", DataType::Uint}},
+ {IFLA_WIRELESS, {"WIRELESS"}},
+ {IFLA_PROTINFO, {"PROTINFO"}},
+ {IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
+ {IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
+ {IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
+ {IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
+ {IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
+ {IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
+ {IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
+ {IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
+ {IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
+ {IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
+ {IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
+ }}},
+ {IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
+ {IFLA_IFALIAS, {"IFALIAS", DataType::String}},
+ {IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
+ {IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
+ {IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
+ {IFLA_VF_PORTS, {"VF_PORTS"}},
+ {IFLA_PORT_SELF, {"PORT_SELF"}},
+ {IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
+ {AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
+ {IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
+ }}},
+ {AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
+ {IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
+ {IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
+ {IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
+ {IFLA_INET6_MCAST, {"INET6_MCAST"}},
+ {IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
+ {IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
+ {IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
+ {IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
+ }}},
+ }}},
+ {IFLA_GROUP, {"GROUP", DataType::Uint}},
+ {IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
+ {IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
+ {IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
+ {IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
+ {IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
+ {IFLA_CARRIER, {"CARRIER", DataType::Uint}},
+ {IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
+ {IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
+ {IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
+ {IFLA_LINK_NETNSID, {"LINK_NETNSID"}}, // NLA_S32
+ {IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
+ {IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
+ {IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
+ {IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
+ {IFLA_PAD, {"PAD"}},
+ {IFLA_XDP, {"XDP"}},
+ {IFLA_EVENT, {"EVENT", DataType::Uint}},
+ {IFLA_NEW_NETNSID, {"NEW_NETNSID"}}, // NLA_S32
+ {IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}}, // NLA_S32
+ {IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
+ {IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
+ {IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}}, // NLA_S32
+ {IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
+ {IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
+ {IFLA_PROP_LIST, {"PROP_LIST"}},
+ {IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
+ {IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
+}) {}
+// clang-format off
+
+void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
+ ss << "ifinfomsg{"
+ << "family=" << unsigned(data.ifi_family) << ", type=" << data.ifi_type
+ << ", index=" << data.ifi_index << ", flags=" << data.ifi_flags
+ << ", change=" << data.ifi_change << "}";
+}
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.h b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
new file mode 100644
index 0000000..ecfefc9
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.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.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+#include <linux/rtnetlink.h>
+
+namespace android::nl::protocols::route {
+
+class Link : public MessageDefinition<ifinfomsg> {
+ public:
+ Link();
+ void toStream(std::stringstream& ss, const ifinfomsg& data) const override;
+};
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Route.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Route.cpp
new file mode 100644
index 0000000..c134911
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Route.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 "Route.h"
+
+#include "Link.h"
+
+namespace android::nl::protocols::route {
+
+Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {std::make_shared<Link>()}) {}
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Route.h b/automotive/can/1.0/default/libnl++/protocols/route/Route.h
new file mode 100644
index 0000000..433e610
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Route.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.
+ */
+
+#pragma once
+
+#include "../NetlinkProtocol.h"
+
+namespace android::nl::protocols::route {
+
+/**
+ * Definition of NETLINK_ROUTE protocol.
+ */
+class Route : public NetlinkProtocol {
+ public:
+ Route();
+};
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
new file mode 100644
index 0000000..b62cec3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.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 "structs.h"
+
+namespace android::nl::protocols::route {
+
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+ const auto& [ok, data] = attr.data<rtnl_link_ifmap>().getFirst();
+ if (!ok) {
+ ss << "invalid structure";
+ return;
+ }
+ ss << '{' //
+ << data.mem_start << ',' //
+ << data.mem_end << ',' //
+ << data.base_addr << ',' //
+ << data.irq << ',' //
+ << unsigned(data.dma) << ',' //
+ << unsigned(data.port) << '}';
+}
+
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+ const auto& [ok, data] = attr.data<ifla_cacheinfo>().getFirst();
+ if (!ok) {
+ ss << "invalid structure";
+ return;
+ }
+ ss << '{' //
+ << data.max_reasm_len << ',' //
+ << data.tstamp << ',' //
+ << data.reachable_time << ',' //
+ << data.retrans_time << '}';
+}
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
new file mode 100644
index 0000000..b9d622a
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -0,0 +1,78 @@
+/*
+ * 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 <libnl++/Buffer.h>
+
+#include <linux/rtnetlink.h>
+
+#include <sstream>
+
+namespace android::nl::protocols::route {
+
+// rtnl_link_ifmap
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
+
+// 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) {
+ const auto& [ok, data] = attr.data<T>().getFirst();
+ if (!ok) {
+ ss << "invalid structure";
+ return;
+ }
+ ss << '{' //
+ << data.rx_packets << ',' //
+ << data.tx_packets << ',' //
+ << data.rx_bytes << ',' //
+ << data.tx_bytes << ',' //
+ << data.rx_errors << ',' //
+ << data.tx_errors << ',' //
+ << data.rx_dropped << ',' //
+ << data.tx_dropped << ',' //
+ << data.multicast << ',' //
+ << data.collisions << ',' //
+ << data.rx_length_errors << ',' //
+ << data.rx_over_errors << ',' //
+ << data.rx_crc_errors << ',' //
+ << data.rx_frame_errors << ',' //
+ << data.rx_fifo_errors << ',' //
+ << data.rx_missed_errors << ',' //
+ << data.tx_aborted_errors << ',' //
+ << data.tx_carrier_errors << ',' //
+ << data.tx_fifo_errors << ',' //
+ << data.tx_heartbeat_errors << ',' //
+ << data.tx_window_errors << ',' //
+ << data.rx_compressed << ',' //
+ << data.tx_compressed << ',' //
+ << data.rx_nohandler << '}';
+}
+
+} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
index b52a54a..9a9d322 100644
--- a/automotive/can/1.0/default/service.cpp
+++ b/automotive/can/1.0/default/service.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
+#include <libnetdevice/libnetdevice.h>
namespace android::hardware::automotive::can::V1_0::implementation {
@@ -27,6 +28,8 @@
configureRpcThreadpool(16, true);
LOG(DEBUG) << "CAN controller service starting...";
+ netdevice::useSocketDomain(AF_CAN);
+
sp<CanController> canController(new CanController);
if (canController->registerAsService("socketcan") != OK) {
LOG(FATAL) << "Failed to register CAN controller";
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
index a8e7c0b..d91d9f5 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -176,8 +176,9 @@
* adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest\
* --gtest_filter=*_<NAME_OF_VALID_BUS>
*/
-INSTANTIATE_TEST_SUITE_P( //
- PerInstance, CanBusHalTest, testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)),
- PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanBusHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanBusHalTest,
+ testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)),
+ PrintInstanceNameToString);
} // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 9039435..fc77579 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -86,7 +86,7 @@
EXPECT_EQ(ICanController::Result::OK, result);
/* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ * file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto service = manager->get(ICanBus::descriptor, config.name);
mBus = ICanBus::castFrom(service);
@@ -868,9 +868,9 @@
* Example manual invocation:
* adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest
*/
-INSTANTIATE_TEST_SUITE_P( //
- PerInstance, CanBusVirtualHalTest,
- testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
- PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanBusVirtualHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanBusVirtualHalTest,
+ testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+ PrintInstanceNameToString);
} // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 8ef5758..294cd17 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -119,7 +119,7 @@
void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
/* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ * file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto busService = manager->get(ICanBus::descriptor, srvname);
ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
@@ -145,7 +145,7 @@
assertRegistered(name, false);
}
-TEST_P(CanControllerHalTest, DownDummy) {
+TEST_P(CanControllerHalTest, DownFake) {
const auto result = mCanController->downInterface("imnotup");
ASSERT_FALSE(result);
}
@@ -293,9 +293,9 @@
* Example manual invocation:
* adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest
*/
-INSTANTIATE_TEST_SUITE_P( //
- PerInstance, CanControllerHalTest,
- testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
- PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanControllerHalTest,
+ testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+ PrintInstanceNameToString);
} // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
index e0782ec..0daea5a 100644
--- a/automotive/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -49,7 +49,7 @@
mDescription.cameraId = id;
- // Set up dummy data for testing
+ // Set up mock data for testing
if (mDescription.cameraId == kCameraName_Backup) {
mWidth = 640; // full NTSC/VGA
mHeight = 480; // full NTSC/VGA
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index 7fe7a33..ad607d8 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -369,7 +369,7 @@
TEST_P(EvsHidlTest, CameraStreamBuffering) {
ALOGI("Starting CameraStreamBuffering test");
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
@@ -381,7 +381,7 @@
sp<IEvsCamera> pCam = pEnumerator->openCamera(cam.cameraId);
ASSERT_NE(pCam, nullptr);
- // Ask for a crazy number of buffers in flight to ensure it errors correctly
+ // Ask for a very large number of buffers in flight to ensure it errors correctly
Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 870af1c..b0b2670 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -76,7 +76,7 @@
}
/*
- * List of supported controls that the master client can program.
+ * List of supported controls that the primary client can program.
* Paraemters are stored with its valid range
*/
unordered_map<CameraParam,
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index 117ee7a..d066471 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -70,7 +70,7 @@
// Add ultrasonics array desc.
sUltrasonicsArrayRecordList.emplace_back(
- EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
+ EvsUltrasonicsArray::GetMockArrayDesc("front_array"));
}
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
index bc69aa4..ebd47c6 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
@@ -45,7 +45,7 @@
namespace {
-void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
+void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
arrayDesc.maxReceiversCount = kMaxReceiversCount;
@@ -99,8 +99,8 @@
}
}
-// Fills dataFrameDesc with dummy data.
-bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
+// Fills dataFrameDesc with mock data.
+bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
dataFrameDesc.timestampNs = elapsedRealtimeNano();
const std::vector<uint8_t> transmittersIdList = {0};
@@ -137,9 +137,9 @@
: mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
- // Set up dummy data for description.
+ // Set up mock data for description.
mArrayDesc.ultrasonicsArrayId = deviceName;
- fillDummyArrayDesc(mArrayDesc);
+ fillMockArrayDesc(mArrayDesc);
// Assign allocator.
mShmemAllocator = IAllocator::getService("ashmem");
@@ -182,10 +182,10 @@
mStreamState = DEAD;
}
-UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) {
+UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
UltrasonicsArrayDesc ultrasonicsArrayDesc;
ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
- fillDummyArrayDesc(ultrasonicsArrayDesc);
+ fillMockArrayDesc(ultrasonicsArrayDesc);
return ultrasonicsArrayDesc;
}
@@ -497,17 +497,17 @@
if (timeForFrame) {
// Assemble the buffer description we'll transmit below
- UltrasonicsDataFrameDesc dummyDataFrameDesc;
- dummyDataFrameDesc.dataFrameId = idx;
- dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
+ UltrasonicsDataFrameDesc mockDataFrameDesc;
+ mockDataFrameDesc.dataFrameId = idx;
+ mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
- // Fill dummy waveform data.
- fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
+ // Fill mock waveform data.
+ fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- auto result = mStream->deliverDataFrame(dummyDataFrameDesc);
+ auto result = mStream->deliverDataFrame(mockDataFrameDesc);
if (result.isOk()) {
- LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId;
+ LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
} else {
// This can happen if the client dies and is likely unrecoverable.
// To avoid consuming resources generating failing calls, we stop sending
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
index 7a41012..88aa600 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.h
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
@@ -58,7 +58,7 @@
static sp<EvsUltrasonicsArray> Create(const char* deviceName);
// Returns a ultrasonics array descriptor filled with sample data.
- static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id);
+ static UltrasonicsArrayDesc GetMockArrayDesc(const char* id);
DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray);
virtual ~EvsUltrasonicsArray() override;
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 948d45f..8de9304 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -502,7 +502,7 @@
TEST_P(EvsHidlTest, CameraStreamBuffering) {
LOG(INFO) << "Starting CameraStreamBuffering test";
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
@@ -529,7 +529,7 @@
// Store a camera handle for a clean-up
activeCameras.push_back(pCam);
- // Ask for a crazy number of buffers in flight to ensure it errors correctly
+ // Ask for a very large number of buffers in flight to ensure it errors correctly
Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
@@ -935,12 +935,12 @@
/*
- * CameraMasterRelease
- * Verify that non-master client gets notified when the master client either
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
* terminates or releases a role.
*/
-TEST_P(EvsHidlTest, CameraMasterRelease) {
- LOG(INFO) << "Starting CameraMasterRelease test";
+TEST_P(EvsHidlTest, CameraPrimaryClientRelease) {
+ LOG(INFO) << "Starting CameraPrimaryClientRelease test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -966,57 +966,57 @@
}
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamMaster =
+ sp<IEvsCamera_1_1> pCamPrimary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamMaster, nullptr);
+ ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamMaster);
+ activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamNonMaster =
+ sp<IEvsCamera_1_1> pCamSecondary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamNonMaster, nullptr);
+ ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamNonMaster);
+ activeCameras.push_back(pCamSecondary);
// Set up per-client frame receiver objects which will fire up its own thread
- sp<FrameHandler> frameHandlerMaster =
- new FrameHandler(pCamMaster, cam,
+ sp<FrameHandler> frameHandlerPrimary =
+ new FrameHandler(pCamPrimary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerMaster, nullptr);
- sp<FrameHandler> frameHandlerNonMaster =
- new FrameHandler(pCamNonMaster, cam,
+ ASSERT_NE(frameHandlerPrimary, nullptr);
+ sp<FrameHandler> frameHandlerSecondary =
+ new FrameHandler(pCamSecondary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerNonMaster, nullptr);
+ ASSERT_NE(frameHandlerSecondary, nullptr);
- // Set one client as the master
- EvsResult result = pCamMaster->setMaster();
+ // Set one client as the primary client
+ EvsResult result = pCamPrimary->setMaster();
ASSERT_TRUE(result == EvsResult::OK);
- // Try to set another client as the master.
- result = pCamNonMaster->setMaster();
+ // Try to set another client as the primary client.
+ result = pCamSecondary->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
- // Start the camera's video stream via a master client.
- bool startResult = frameHandlerMaster->startStream();
+ // Start the camera's video stream via a primary client client.
+ bool startResult = frameHandlerPrimary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerMaster->waitForFrameCount(1);
+ frameHandlerPrimary->waitForFrameCount(1);
// Start the camera's video stream via another client
- startResult = frameHandlerNonMaster->startStream();
+ startResult = frameHandlerSecondary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerNonMaster->waitForFrameCount(1);
+ frameHandlerSecondary->waitForFrameCount(1);
- // Non-master client expects to receive a master role relesed
+ // Non-primary client expects to receive a primary client role relesed
// notification.
EvsEventDesc aTargetEvent = {};
EvsEventDesc aNotification = {};
@@ -1025,14 +1025,14 @@
std::mutex eventLock;
std::condition_variable eventCond;
std::thread listener = std::thread(
- [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+ [&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
// Notify that a listening thread is running.
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
@@ -1048,8 +1048,8 @@
}
lock.unlock();
- // Release a master role.
- pCamMaster->unsetMaster();
+ // Release a primary client role.
+ pCamPrimary->unsetMaster();
// Join a listening thread.
if (listener.joinable()) {
@@ -1060,24 +1060,24 @@
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
- // Non-master becomes a master.
- result = pCamNonMaster->setMaster();
+ // Non-primary becomes a primary client.
+ result = pCamSecondary->setMaster();
ASSERT_TRUE(result == EvsResult::OK);
- // Previous master client fails to become a master.
- result = pCamMaster->setMaster();
+ // Previous primary client fails to become a primary client.
+ result = pCamPrimary->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
listening = false;
listener = std::thread(
- [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+ [&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
// Notify that a listening thread is running.
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
@@ -1092,8 +1092,8 @@
}
lock.unlock();
- // Closing current master client.
- frameHandlerNonMaster->shutdown();
+ // Closing current primary client.
+ frameHandlerSecondary->shutdown();
// Join a listening thread.
if (listener.joinable()) {
@@ -1105,11 +1105,11 @@
static_cast<EvsEventType>(aNotification.aType));
// Closing streams.
- frameHandlerMaster->shutdown();
+ frameHandlerPrimary->shutdown();
// Explicitly release the camera
- pEnumerator->closeCamera(pCamMaster);
- pEnumerator->closeCamera(pCamNonMaster);
+ pEnumerator->closeCamera(pCamPrimary);
+ pEnumerator->closeCamera(pCamSecondary);
activeCameras.clear();
}
}
@@ -1117,7 +1117,7 @@
/*
* MultiCameraParameter:
- * Verify that master and non-master clients behave as expected when they try to adjust
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
* camera parameters.
*/
TEST_P(EvsHidlTest, MultiCameraParameter) {
@@ -1147,88 +1147,88 @@
}
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamMaster =
+ sp<IEvsCamera_1_1> pCamPrimary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamMaster, nullptr);
+ ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamMaster);
+ activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamNonMaster =
+ sp<IEvsCamera_1_1> pCamSecondary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamNonMaster, nullptr);
+ ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamNonMaster);
+ activeCameras.push_back(pCamSecondary);
// Get the parameter list
- std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
- pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
- camMasterCmds.reserve(cmdList.size());
+ std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+ pCamPrimary->getParameterList([&camPrimaryCmds](hidl_vec<CameraParam> cmdList) {
+ camPrimaryCmds.reserve(cmdList.size());
for (auto &&cmd : cmdList) {
- camMasterCmds.push_back(cmd);
+ camPrimaryCmds.push_back(cmd);
}
}
);
- pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
- camNonMasterCmds.reserve(cmdList.size());
+ pCamSecondary->getParameterList([&camSecondaryCmds](hidl_vec<CameraParam> cmdList) {
+ camSecondaryCmds.reserve(cmdList.size());
for (auto &&cmd : cmdList) {
- camNonMasterCmds.push_back(cmd);
+ camSecondaryCmds.push_back(cmd);
}
}
);
- if (camMasterCmds.size() < 1 ||
- camNonMasterCmds.size() < 1) {
+ if (camPrimaryCmds.size() < 1 ||
+ camSecondaryCmds.size() < 1) {
// Skip a camera device if it does not support any parameter.
continue;
}
// Set up per-client frame receiver objects which will fire up its own thread
- sp<FrameHandler> frameHandlerMaster =
- new FrameHandler(pCamMaster, cam,
+ sp<FrameHandler> frameHandlerPrimary =
+ new FrameHandler(pCamPrimary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerMaster, nullptr);
- sp<FrameHandler> frameHandlerNonMaster =
- new FrameHandler(pCamNonMaster, cam,
+ ASSERT_NE(frameHandlerPrimary, nullptr);
+ sp<FrameHandler> frameHandlerSecondary =
+ new FrameHandler(pCamSecondary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerNonMaster, nullptr);
+ ASSERT_NE(frameHandlerSecondary, nullptr);
- // Set one client as the master
- EvsResult result = pCamMaster->setMaster();
+ // Set one client as the primary client.
+ EvsResult result = pCamPrimary->setMaster();
ASSERT_EQ(EvsResult::OK, result);
- // Try to set another client as the master.
- result = pCamNonMaster->setMaster();
+ // Try to set another client as the primary client.
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
- // Start the camera's video stream via a master client.
- bool startResult = frameHandlerMaster->startStream();
+ // Start the camera's video stream via a primary client client.
+ bool startResult = frameHandlerPrimary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerMaster->waitForFrameCount(1);
+ frameHandlerPrimary->waitForFrameCount(1);
// Start the camera's video stream via another client
- startResult = frameHandlerNonMaster->startStream();
+ startResult = frameHandlerSecondary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerNonMaster->waitForFrameCount(1);
+ frameHandlerSecondary->waitForFrameCount(1);
int32_t val0 = 0;
std::vector<int32_t> values;
EvsEventDesc aNotification0 = {};
EvsEventDesc aNotification1 = {};
- for (auto &cmd : camMasterCmds) {
+ for (auto &cmd : camPrimaryCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
- pCamMaster->getIntParameterRange(
+ pCamPrimary->getIntParameterRange(
cmd,
[&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
minVal = val0;
@@ -1241,7 +1241,7 @@
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
values.clear();
- pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ pCamPrimary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1266,7 +1266,7 @@
std::condition_variable eventCond;
std::thread listener0 = std::thread(
[cmd, val0,
- &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ &aNotification0, &frameHandlerPrimary, &listening0, &listening1, &eventCond]() {
listening0 = true;
if (listening1) {
eventCond.notify_all();
@@ -1276,14 +1276,14 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
std::thread listener1 = std::thread(
[cmd, val0,
- &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ &aNotification1, &frameHandlerSecondary, &listening0, &listening1, &eventCond]() {
listening1 = true;
if (listening0) {
eventCond.notify_all();
@@ -1293,7 +1293,7 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1310,7 +1310,7 @@
// Try to program a parameter
values.clear();
- pCamMaster->setIntParameter(cmd, val0,
+ pCamPrimary->setIntParameter(cmd, val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1350,9 +1350,9 @@
}
// Clients expects to receive a parameter change notification
- // whenever a master client adjusts it.
+ // whenever a primary client client adjusts it.
values.clear();
- pCamMaster->getIntParameter(cmd,
+ pCamPrimary->getIntParameter(cmd,
[&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1367,9 +1367,9 @@
}
}
- // Try to adjust a parameter via non-master client
+ // Try to adjust a parameter via non-primary client
values.clear();
- pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+ pCamSecondary->setIntParameter(camSecondaryCmds[0], val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1380,21 +1380,21 @@
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
- // Non-master client attemps to be a master
- result = pCamNonMaster->setMaster();
+ // Non-primary client attempts to be a primary client
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
- // Master client retires from a master role
+ // Primary client retires from a primary client role
bool listening = false;
std::condition_variable eventCond;
std::thread listener = std::thread(
- [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+ [&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1408,7 +1408,7 @@
}
lock.unlock();
- result = pCamMaster->unsetMaster();
+ result = pCamPrimary->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
if (listener.joinable()) {
@@ -1419,7 +1419,7 @@
// Try to adjust a parameter after being retired
values.clear();
- pCamMaster->setIntParameter(camMasterCmds[0], val0,
+ pCamPrimary->setIntParameter(camPrimaryCmds[0], val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1430,15 +1430,15 @@
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
- // Non-master client becomes a master
- result = pCamNonMaster->setMaster();
+ // Non-primary client becomes a primary client
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OK, result);
- // Try to adjust a parameter via new master client
- for (auto &cmd : camNonMasterCmds) {
+ // Try to adjust a parameter via new primary client
+ for (auto &cmd : camSecondaryCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
- pCamNonMaster->getIntParameterRange(
+ pCamSecondary->getIntParameterRange(
cmd,
[&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
minVal = val0;
@@ -1452,7 +1452,7 @@
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
values.clear();
- pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ pCamSecondary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1476,7 +1476,7 @@
bool listening1 = false;
std::condition_variable eventCond;
std::thread listener0 = std::thread(
- [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ [&]() {
listening0 = true;
if (listening1) {
eventCond.notify_all();
@@ -1486,13 +1486,13 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
std::thread listener1 = std::thread(
- [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ [&]() {
listening1 = true;
if (listening0) {
eventCond.notify_all();
@@ -1502,7 +1502,7 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1519,7 +1519,7 @@
// Try to program a parameter
values.clear();
- pCamNonMaster->setIntParameter(cmd, val0,
+ pCamSecondary->setIntParameter(cmd, val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1531,9 +1531,9 @@
ASSERT_EQ(EvsResult::OK, result);
// Clients expects to receive a parameter change notification
- // whenever a master client adjusts it.
+ // whenever a primary client client adjusts it.
values.clear();
- pCamNonMaster->getIntParameter(cmd,
+ pCamSecondary->getIntParameter(cmd,
[&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1572,17 +1572,17 @@
}
}
- // New master retires from a master role
- result = pCamNonMaster->unsetMaster();
+ // New primary client retires from the role
+ result = pCamSecondary->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
// Shutdown
- frameHandlerMaster->shutdown();
- frameHandlerNonMaster->shutdown();
+ frameHandlerPrimary->shutdown();
+ frameHandlerSecondary->shutdown();
// Explicitly release the camera
- pEnumerator->closeCamera(pCamMaster);
- pEnumerator->closeCamera(pCamNonMaster);
+ pEnumerator->closeCamera(pCamPrimary);
+ pEnumerator->closeCamera(pCamSecondary);
activeCameras.clear();
}
}
@@ -1591,7 +1591,7 @@
/*
* HighPriorityCameraClient:
* EVS client, which owns the display, is priortized and therefore can take over
- * a master role from other EVS clients without the display.
+ * a primary client role from other EVS clients without the display.
*/
TEST_P(EvsHidlTest, HighPriorityCameraClient) {
LOG(INFO) << "Starting HighPriorityCameraClient test";
@@ -1673,7 +1673,7 @@
frameHandler0->waitForFrameCount(1);
frameHandler1->waitForFrameCount(1);
- // Client 1 becomes a master and programs a parameter.
+ // Client 1 becomes a primary client and programs a parameter.
EvsResult result = EvsResult::OK;
// Get a valid parameter value range
int32_t minVal, maxVal, step;
@@ -1686,7 +1686,7 @@
}
);
- // Client1 becomes a master
+ // Client1 becomes a primary client
result = pCam1->setMaster();
ASSERT_EQ(EvsResult::OK, result);
@@ -1825,7 +1825,7 @@
}
lock.unlock();
- // Client 0 steals a master role
+ // Client 0 steals a primary client role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
// Join a listener
@@ -2246,7 +2246,7 @@
TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
LOG(INFO) << "Starting CameraStreamExternalBuffering test";
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
@@ -2476,7 +2476,7 @@
}
}
-
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EvsHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance,
EvsHidlTest,
diff --git a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
index c431f9d..a1fd05a 100644
--- a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
+++ b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
@@ -190,6 +190,7 @@
ASSERT_LE(elapsed, kTimeout);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OccupantAwarenessAidl);
INSTANTIATE_TEST_SUITE_P(
InstantiationName, OccupantAwarenessAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(IOccupantAwareness::descriptor)),
diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
index b1b9d16..059d152 100644
--- a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
+++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
@@ -1127,6 +1127,7 @@
mSurroundViewService->stop3dSession(surroundView3dSession);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SurroundViewHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance,
SurroundViewHidlTest,
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index ef29560..7e8deb6 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,13 +20,10 @@
#include <iostream>
-#include <android/binder_process.h>
-#include <utils/Looper.h>
#include <vhal_v2_0/EmulatedUserHal.h>
#include <vhal_v2_0/EmulatedVehicleConnector.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
#include <vhal_v2_0/VehicleHalManager.h>
-#include <vhal_v2_0/WatchdogClient.h>
using namespace android;
using namespace android::hardware;
@@ -41,7 +38,7 @@
auto service = std::make_unique<VehicleHalManager>(hal.get());
connector->setValuePool(hal->getValuePool());
- configureRpcThreadpool(4, false /* callerWillJoin */);
+ configureRpcThreadpool(4, true /* callerWillJoin */);
ALOGI("Registering as service...");
status_t status = service->registerAsService();
@@ -51,22 +48,8 @@
return 1;
}
- // Setup a binder thread pool to be a car watchdog client.
- ABinderProcess_setThreadPoolMaxThreadCount(1);
- ABinderProcess_startThreadPool();
- sp<Looper> looper(Looper::prepare(0 /* opts */));
- std::shared_ptr<WatchdogClient> watchdogClient =
- ndk::SharedRefBase::make<WatchdogClient>(looper, service.get());
- // The current health check is done in the main thread, so it falls short of capturing the real
- // situation. Checking through HAL binder thread should be considered.
- if (!watchdogClient->initialize()) {
- ALOGE("Failed to initialize car watchdog client");
- return 1;
- }
ALOGI("Ready");
- while (true) {
- looper->pollAll(-1 /* timeoutMillis */);
- }
+ joinRpcThreadpool();
return 1;
}
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 cf18404..80a1831 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
@@ -499,6 +499,18 @@
},
.initialValue = {.int32Values = {0, 0, 0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HW_CUSTOM_INPUT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 0, 0, 3, 0, 0, 0, 0, 0},
+ },
+ .initialValue =
+ {
+ .int32Values = {0, 0, 0},
+ }},
+
{.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -1080,6 +1092,54 @@
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
},
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::POWER_POLICY_REQ),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::POWER_POLICY_GROUP_REQ),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::CURRENT_POWER_POLICY),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::WATCHDOG_ALIVE),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::WATCHDOG_TERMINATED_PROCESS),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index a0b566d..c83e2de 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -15,11 +15,13 @@
*/
#define LOG_TAG "DefaultVehicleHal_v2_0"
+#include <android-base/chrono_utils.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android/log.h>
#include <dirent.h>
#include <sys/system_properties.h>
+#include <utils/SystemClock.h>
#include <fstream>
#include <regex>
@@ -36,6 +38,8 @@
namespace impl {
+static constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s;
+
static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
size_t numVendorFloatSensors) {
std::unique_ptr<Obd2SensorStore> sensorStore(
@@ -342,6 +346,8 @@
initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
mInEmulator = isInEmulator();
ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
+ mRecurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs,
+ static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT));
}
std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
@@ -359,6 +365,10 @@
if (internalPropValue != nullptr) {
v = pool.obtain(*internalPropValue);
}
+ } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) {
+ // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically.
+ // So, the update is done through onContinuousPropertyTimer.
+ v = doInternalHealthCheck();
} else {
ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
}
@@ -512,6 +522,31 @@
return StatusCode::OK;
}
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::doInternalHealthCheck() {
+ VehicleHal::VehiclePropValuePtr v = nullptr;
+
+ // This is an example of very simpe health checking. VHAL is considered healthy if we can read
+ // PERF_VEHICLE_SPEED. The more comprehensive health checking is required.
+ VehiclePropValue propValue = {
+ .prop = static_cast<int32_t>(VehicleProperty::PERF_VEHICLE_SPEED),
+ };
+ auto internalPropValue = mPropStore->readValueOrNull(propValue);
+ if (internalPropValue != nullptr) {
+ v = createVhalHeartBeatProp();
+ } else {
+ ALOGW("VHAL health check failed");
+ }
+ return v;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createVhalHeartBeatProp() {
+ VehicleHal::VehiclePropValuePtr v = getValuePool()->obtainInt64(uptimeMillis());
+ v->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT);
+ v->areaId = 0;
+ v->status = VehiclePropertyStatus::AVAILABLE;
+ return v;
+}
+
} // impl
} // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index eb38d7d..5c67641 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -82,6 +82,8 @@
VehiclePropValue* outValue);
StatusCode fillObd2DtcInfo(VehiclePropValue* outValue);
StatusCode clearObd2FreezeFrames(const VehiclePropValue& propValue);
+ VehicleHal::VehiclePropValuePtr doInternalHealthCheck();
+ VehicleHal::VehiclePropValuePtr createVhalHeartBeatProp();
/* Private members */
VehiclePropertyStore* mPropStore;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index f7a42e9..931fee4 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1480,6 +1480,33 @@
| VehiclePropertyType:INT32_VEC
| VehicleArea:GLOBAL),
+ /**
+ * Defines a custom OEM partner input event.
+ *
+ * This input event must be used by OEM partners who wish to propagate events not supported
+ * by Android. It is composed by an array of int32 values only.
+ *
+ * The Android properties are:
+ *
+ * int32Values[0] : Input code identifying the function representing this event. Valid event
+ * types are defined by CustomInputType.CUSTOM_EVENT_F1 up to
+ * CustomInputType.CUSTOM_EVENT_F10. They represent the custom event to be
+ * defined by OEM partners.
+ * int32Values[1] : target display type defined in VehicleDisplay. Events not tied to specific
+ * display must be sent to VehicleDisplay#MAIN.
+ * int32Values[2] : repeat counter, if 0 then event is not repeated. Values 1 or above means
+ * how many times this event repeated.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @data_enum CustomInputType
+ * @access VehiclePropertyAccess:READ
+ */
+ HW_CUSTOM_INPUT = (
+ 0X0A30
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
/***************************************************************************
* Most Car Cabin properties have both a POSition and MOVE parameter. These
* are used to control the various movements for seats, doors, and windows
@@ -2892,6 +2919,114 @@
| VehiclePropertyGroup:SYSTEM
| VehiclePropertyType:MIXED
| VehicleArea:GLOBAL),
+
+ /**
+ * Defines a request to apply power policy.
+ *
+ * VHAL sets this property to change car power policy. Car power policy service subscribes to
+ * this property and actually changes the power policy.
+ * The request is made by setting the VehiclePropValue with the ID of a power policy which is
+ * defined at /vendor/etc/power_policy.xml. If the given ID is not defined, car power policy
+ * service ignores the request and the current power policy is maintained.
+ *
+ * string: "sample_policy_id" // power policy ID
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ POWER_POLICY_REQ = (
+ 0x0F21
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines a request to set the power polic group used to decide a default power policy per
+ * power status transition.
+ *
+ * VHAL sets this property with the ID of a power policy group in order to set the default power
+ * policy applied at power status transition. Power policy groups are defined at
+ * /vendor/etc/power_policy.xml. If the given ID is not defined, car power policy service
+ * ignores the request.
+ * Car power policy service subscribes to this property and sets the power policy group.
+ * The actual application of power policy takes place when the system power status changes and
+ * there is a valid mapped power policy for the new power status.
+ *
+ * string: "sample_policy_group_id" // power policy group ID
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ POWER_POLICY_GROUP_REQ = (
+ 0x0F22
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Notifies the current power policy to VHAL layer.
+ *
+ * Car power policy service sets this property when the current power policy is changed.
+ *
+ * string: "sample_policy_id" // power policy ID
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ CURRENT_POWER_POLICY = (
+ 0x0F23
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines an event that car watchdog updates to tell it's alive.
+ *
+ * Car watchdog sets this property to system uptime in milliseconds at every 3 second.
+ * During the boot, the update may take longer time.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ WATCHDOG_ALIVE = (
+ 0xF31
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT64
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines a process terminated by car watchdog and the reason of termination.
+ *
+ * int32Values[0]: 1 // ProcessTerminationReason showing why a process is terminated.
+ * string: "/system/bin/log" // Process execution command.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ WATCHDOG_TERMINATED_PROCESS = (
+ 0x0F32
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:MIXED
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines an event that VHAL signals to car watchdog as a heartbeat.
+ *
+ * If VHAL supports this property, VHAL should write system uptime to this property at every 3
+ * second. Car watchdog subscribes to this property and checks if the property is updated at
+ * every 3 second. With the buffer time of 3 second, car watchdog waits for a heart beat to be
+ * signaled up to 6 seconds from the last heart beat. If it isn’t, car watchdog considers
+ * VHAL unhealthy and terminates it.
+ * If this property is not supported by VHAL, car watchdog doesn't check VHAL health status.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ VHAL_HEARTBEAT = (
+ 0x0F33
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT64
+ | VehicleArea:GLOBAL),
};
/**
@@ -4790,3 +4925,46 @@
ROTARY_INPUT_TYPE_AUDIO_VOLUME = 1,
};
+/**
+ * The reason why a process is terminated by car watchdog.
+ * This is used with WATCHDOG_TERMINATED_PROCESS property.
+ */
+enum ProcessTerminationReason : int32_t {
+ /**
+ * A process doesn't respond to car watchdog within the timeout.
+ */
+ NOT_RESPONDING = 1,
+
+ /**
+ * A process uses more IO operations than what is allowed.
+ */
+ IO_OVERUSE = 2,
+
+ /**
+ * A process uses more memory space than what is allowed.
+ */
+ MEMORY_OVERUSE = 3,
+};
+
+/**
+ * Input code values for HW_CUSTOM_INPUT.
+ */
+enum CustomInputType : int32_t {
+ /**
+ * Ten functions representing the custom input code to be defined and implemented by OEM
+ * partners.
+ *
+ * OEMs need to formally contact Android team if more than 10 functions are required.
+ */
+ CUSTOM_EVENT_F1 = 1001,
+ CUSTOM_EVENT_F2 = 1002,
+ CUSTOM_EVENT_F3 = 1003,
+ CUSTOM_EVENT_F4 = 1004,
+ CUSTOM_EVENT_F5 = 1005,
+ CUSTOM_EVENT_F6 = 1006,
+ CUSTOM_EVENT_F7 = 1007,
+ CUSTOM_EVENT_F8 = 1008,
+ CUSTOM_EVENT_F9 = 1009,
+ CUSTOM_EVENT_F10 = 1010,
+};
+
diff --git a/biometrics/README.md b/biometrics/README.md
new file mode 100644
index 0000000..8ae1ad6
--- /dev/null
+++ b/biometrics/README.md
@@ -0,0 +1,12 @@
+## Biometric HALs ##
+---
+
+## Overview: ##
+
+The interfaces within the biometrics.* HAL tree are used by the Android Biometric Services
+(e.g. FingerprintService, FaceService) to discover and operate biometric sensors on the device.
+
+More details and versioning information can be found within each particular HAL.
+
+More complete information about the Android Biometric HALs and subsystem can be found at
+[source.android.com](https://source.android.com/security/biometric).
\ No newline at end of file
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
new file mode 100644
index 0000000..f7462e6
--- /dev/null
+++ b/biometrics/common/aidl/Android.bp
@@ -0,0 +1,16 @@
+aidl_interface {
+ name: "android.hardware.biometrics.common",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/biometrics/common/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ cpp: {
+ enabled: false,
+ },
+ }
+}
\ No newline at end of file
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
new file mode 100644
index 0000000..8dbc149
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.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.biometrics.common;
+@VintfStability
+parcelable CommonProps {
+ int sensorId;
+ android.hardware.biometrics.common.SensorStrength sensorStrength;
+ int maxEnrollmentsPerUser;
+ android.hardware.biometrics.common.HardwareInfo[] hardwareInfo;
+}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/HardwareInfo.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/HardwareInfo.aidl
new file mode 100644
index 0000000..b94b6b0
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/HardwareInfo.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.biometrics.common;
+@VintfStability
+parcelable HardwareInfo {
+ String deviceName;
+ String hardwareVersion;
+ String firmwareVersion;
+ String serialNumber;
+}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
new file mode 100644
index 0000000..1a875bf
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.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.biometrics.common;
+@VintfStability
+interface ICancellationSignal {
+ oneway void cancel();
+}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
new file mode 100644
index 0000000..eaff85d
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.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.biometrics.common;
+@Backing(type="byte") @VintfStability
+enum SensorStrength {
+ CONVENIENCE = 0,
+ WEAK = 1,
+ STRONG = 2,
+}
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
new file mode 100644
index 0000000..9c3fd58
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.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.biometrics.common;
+
+import android.hardware.biometrics.common.HardwareInfo;
+import android.hardware.biometrics.common.SensorStrength;
+
+@VintfStability
+parcelable CommonProps {
+ /**
+ * A statically configured unique ID that identifies a single biometric sensor. IDs must start
+ * at zero and increment by one for each unique sensor. Note that ID allocations are shared
+ * between all biometric modalities (e.g. fingerprint, face, iris), and a single ID must never
+ * be claimed by more than a single sensor.
+ */
+ int sensorId;
+
+ /**
+ * A statically configured strength for this sensor. See the SensorStrength interface for more
+ * information.
+ */
+ SensorStrength sensorStrength;
+
+ /**
+ * The maximum number of enrollments that a single user can have. Statically configured.
+ */
+ int maxEnrollmentsPerUser;
+
+ /**
+ * A list of hardware information for subsystems that pertain to this biometric sensor.
+ */
+ HardwareInfo[] hardwareInfo;
+}
\ No newline at end of file
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/HardwareInfo.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/HardwareInfo.aidl
new file mode 100644
index 0000000..23f0202
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/HardwareInfo.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.common;
+
+@VintfStability
+parcelable HardwareInfo {
+ /**
+ * An identifier uniquely identifying a subsystem.
+ */
+ String deviceName;
+
+ /**
+ * The hardware version. For example, <vendor>/<model>/<revision>.
+ */
+ String hardwareVersion;
+
+ /**
+ * The firmware version.
+ */
+ String firmwareVersion;
+
+ /**
+ * The sensor's serial number.
+ */
+ String serialNumber;
+}
\ No newline at end of file
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
new file mode 100644
index 0000000..1010256
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.common;
+
+@VintfStability
+oneway interface ICancellationSignal {
+ void cancel();
+}
+
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
new file mode 100644
index 0000000..790691c
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.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.biometrics.common;
+
+@VintfStability
+@Backing(type="byte")
+enum SensorStrength {
+ /**
+ * A sensor that meets the requirements for Class 1 biometrics as defined in the CDD. This does
+ * not correspond to a public BiometricManager.Authenticators constant. Sensors of this strength
+ * are not available to applications via the public API surface.
+ */
+ CONVENIENCE,
+
+ /**
+ * A sensor that meets the requirements for Class 2 biometrics as defined in the CDD.
+ * Corresponds to BiometricManager.Authenticators.BIOMETRIC_WEAK.
+ */
+ WEAK,
+
+ /**
+ * A sensor that meets the requirements for Class 3 biometrics as defined in the CDD.
+ * Corresponds to BiometricManager.Authenticators.BIOMETRIC_STRONG.
+ *
+ * Notably, this is the only strength that allows generation/verification of
+ * HardwareAuthToken(s).
+ */
+ STRONG,
+}
\ No newline at end of file
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000..14a86f1
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.face@1.1",
+ root: "android.hardware",
+ srcs: [
+ "IBiometricsFace.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000..84e7443
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.1;
+
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+ /**
+ * Enrolls a user's face for a remote client, for example Android Auto.
+ *
+ * The HAL implementation is responsible for creating a secure communication
+ * channel and receiving the enrollment images from a mobile device with
+ * face authentication hardware.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * Requirements for using this API:
+ * - Mobile devices MUST NOT delegate enrollment to another device by calling
+ * this API. This feature is intended only to allow enrollment on devices
+ * where it is impossible to enroll locally on the device.
+ * - The path MUST be protected by a secret key with rollback protection.
+ * - Synchronizing between devices MUST be accomplished by having both
+ * devices agree on a secret PIN entered by the user (similar to BT
+ * pairing procedure) and use a salted version of that PIN plus other secret
+ * to encrypt traffic.
+ * - All communication to/from the remote device MUST be encrypted and signed
+ * to prevent image injection and other man-in-the-middle type attacks.
+ * - generateChallenge() and revokeChallenge() MUST be implemented on both
+ * remote and local host (e.g. hash the result of the remote host with a
+ * local secret before responding to the API call) and any transmission of
+ * the challenge between hosts MUST be signed to prevent man-in-the-middle
+ * attacks.
+ * - In the event of a lost connection, the result of the last
+ * generateChallenge() MUST be invalidated and the process started over.
+ * - Both the remote and local host MUST honor the timeout and invalidate the
+ * challenge.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @return status The status of this method call.
+ */
+ enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
+ generates (Status status);
+
+ /**
+ * Enrolls a user's face.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @param windowId optional ID of a camera preview window for a
+ * single-camera device. Must be null if not used.
+ * @return status The status of this method call.
+ */
+ enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
+ handle windowId) generates (Status status);
+};
diff --git a/biometrics/face/1.0/default/Android.bp b/biometrics/face/1.1/default/Android.bp
similarity index 84%
rename from biometrics/face/1.0/default/Android.bp
rename to biometrics/face/1.1/default/Android.bp
index d6ff087..360071f 100644
--- a/biometrics/face/1.0/default/Android.bp
+++ b/biometrics/face/1.1/default/Android.bp
@@ -15,10 +15,10 @@
*/
cc_binary {
- name: "android.hardware.biometrics.face@1.0-service.example",
+ name: "android.hardware.biometrics.face@1.1-service.example",
defaults: ["hidl_defaults"],
vendor: true,
- init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
+ init_rc: ["android.hardware.biometrics.face@1.1-service.rc"],
vintf_fragments: ["manifest_face_default.xml"],
relative_install_path: "hw",
proprietary: true,
@@ -31,5 +31,6 @@
"libutils",
"liblog",
"android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
],
}
diff --git a/biometrics/face/1.0/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
similarity index 81%
rename from biometrics/face/1.0/default/BiometricsFace.cpp
rename to biometrics/face/1.1/default/BiometricsFace.cpp
index 2dd6476..2143880 100644
--- a/biometrics/face/1.0/default/BiometricsFace.cpp
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -110,4 +110,20 @@
return Status::OK;
}
+// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */,
+ const hidl_handle& /* windowId */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
} // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.0/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h
similarity index 81%
rename from biometrics/face/1.0/default/BiometricsFace.h
rename to biometrics/face/1.1/default/BiometricsFace.h
index 1d99ed2..5ce5771 100644
--- a/biometrics/face/1.0/default/BiometricsFace.h
+++ b/biometrics/face/1.1/default/BiometricsFace.h
@@ -16,7 +16,7 @@
#pragma once
-#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <random>
@@ -34,7 +34,7 @@
using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
using ::android::hardware::biometrics::face::V1_0::Status;
-class BiometricsFace : public V1_0::IBiometricsFace {
+class BiometricsFace : public V1_1::IBiometricsFace {
public:
BiometricsFace();
@@ -71,6 +71,14 @@
Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
+ // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+ Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures,
+ const hidl_handle& windowId) override;
+
+ Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures) override;
+
private:
std::mt19937 mRandom;
int32_t mUserId;
diff --git a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
similarity index 75%
rename from biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
rename to biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
index 6c7362f..687e2d8 100644
--- a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
+++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
@@ -1,4 +1,4 @@
-service vendor.face-hal-1-0-default /vendor/bin/hw/android.hardware.biometrics.face@1.0-service.example
+service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
diff --git a/biometrics/face/1.0/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml
similarity index 90%
rename from biometrics/face/1.0/default/manifest_face_default.xml
rename to biometrics/face/1.1/default/manifest_face_default.xml
index 380ae49..ec71d9c 100644
--- a/biometrics/face/1.0/default/manifest_face_default.xml
+++ b/biometrics/face/1.1/default/manifest_face_default.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.biometrics.face</name>
<transport>hwbinder</transport>
- <version>1.0</version>
+ <version>1.1</version>
<interface>
<name>IBiometricsFace</name>
<instance>default</instance>
diff --git a/biometrics/face/1.0/default/service.cpp b/biometrics/face/1.1/default/service.cpp
similarity index 88%
rename from biometrics/face/1.0/default/service.cpp
rename to biometrics/face/1.1/default/service.cpp
index 9818c95..344bdb9 100644
--- a/biometrics/face/1.0/default/service.cpp
+++ b/biometrics/face/1.1/default/service.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.biometrics.face@1.0-service"
+#define LOG_TAG "android.hardware.biometrics.face@1.1-service"
#include <android/hardware/biometrics/face/1.0/types.h>
-#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
#include <android/log.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
@@ -27,7 +27,7 @@
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::biometrics::face::implementation::BiometricsFace;
-using android::hardware::biometrics::face::V1_0::IBiometricsFace;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
int main() {
ALOGI("BiometricsFace HAL is being started.");
diff --git a/biometrics/face/1.0/default/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
similarity index 60%
copy from biometrics/face/1.0/default/Android.bp
copy to biometrics/face/1.1/vts/functional/Android.bp
index d6ff087..aa0b1fa 100644
--- a/biometrics/face/1.0/default/Android.bp
+++ b/biometrics/face/1.1/vts/functional/Android.bp
@@ -14,22 +14,16 @@
* limitations under the License.
*/
-cc_binary {
- name: "android.hardware.biometrics.face@1.0-service.example",
- defaults: ["hidl_defaults"],
- vendor: true,
- init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
- vintf_fragments: ["manifest_face_default.xml"],
- relative_install_path: "hw",
- proprietary: true,
- srcs: [
- "BiometricsFace.cpp",
- "service.cpp",
- ],
- shared_libs: [
- "libhidlbase",
- "libutils",
- "liblog",
+cc_test {
+ name: "VtsHalBiometricsFaceV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+ static_libs: [
"android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
],
}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000..0077c8c
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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 "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+ // The error passed to the last onError() callback.
+ FaceError error;
+
+ // The userId passed to the last callback.
+ int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+ public IBiometricsFaceClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.error = error;
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFace::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FaceCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+ ASSERT_EQ(Status::OK, res.status);
+ // Makes sure the "deviceId" represented by "res.value" is not 0.
+ // 0 would mean the HIDL is not available.
+ ASSERT_NE(0UL, res.value);
+ });
+ ASSERT_TRUE(ret1.isOk());
+ Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+ }
+
+ void TearDown() override {}
+
+ sp<IBiometricsFace> mService;
+ sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, Enroll1_1ZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, Enroll1_1GarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+} // anonymous namespace
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, FaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
new file mode 100644
index 0000000..4f8b71d
--- /dev/null
+++ b/biometrics/face/aidl/Android.bp
@@ -0,0 +1,22 @@
+aidl_interface {
+ name: "android.hardware.biometrics.face",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/biometrics/face/**/*.aidl",
+ ],
+ imports: [
+ "android.hardware.biometrics.common",
+ "android.hardware.common",
+ "android.hardware.keymaster",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ enabled: false,
+ platform_apis: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/biometrics/face/aidl/OWNERS b/biometrics/face/aidl/OWNERS
new file mode 100644
index 0000000..36d7261
--- /dev/null
+++ b/biometrics/face/aidl/OWNERS
@@ -0,0 +1,2 @@
+ilyamaty@google.com
+kchyn@google.com
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
new file mode 100644
index 0000000..011b711
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.biometrics.face;
+@Backing(type="byte") @VintfStability
+enum AcquiredInfo {
+ GOOD = 0,
+ INSUFFICIENT = 1,
+ TOO_BRIGHT = 2,
+ TOO_DARK = 3,
+ TOO_CLOSE = 4,
+ TOO_FAR = 5,
+ FACE_TOO_HIGH = 6,
+ FACE_TOO_LOW = 7,
+ FACE_TOO_RIGHT = 8,
+ FACE_TOO_LEFT = 9,
+ POOR_GAZE = 10,
+ NOT_DETECTED = 11,
+ TOO_MUCH_MOTION = 12,
+ RECALIBRATE = 13,
+ TOO_DIFFERENT = 14,
+ TOO_SIMILAR = 15,
+ PAN_TOO_EXTREME = 16,
+ TILT_TOO_EXTREME = 17,
+ ROLL_TOO_EXTREME = 18,
+ FACE_OBSCURED = 19,
+ START = 20,
+ SENSOR_DIRTY = 21,
+ VENDOR = 22,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl
new file mode 100644
index 0000000..15fcbf9
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.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.biometrics.face;
+@Backing(type="byte") @VintfStability
+enum Error {
+ HW_UNAVAILABLE = 1,
+ UNABLE_TO_PROCESS = 2,
+ TIMEOUT = 3,
+ NO_SPACE = 4,
+ CANCELED = 5,
+ UNABLE_TO_REMOVE = 6,
+ VENDOR = 8,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl
new file mode 100644
index 0000000..943129e
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.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.biometrics.face;
+@Backing(type="byte") @VintfStability
+enum FaceSensorType {
+ RGB = 0,
+ IR = 1,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
new file mode 100644
index 0000000..518fb14
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.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.biometrics.face;
+@VintfStability
+interface IFace {
+ android.hardware.biometrics.face.SensorProps[] getSensorProps();
+ android.hardware.biometrics.face.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.face.ISessionCallback cb);
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
new file mode 100644
index 0000000..5d9a430
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.biometrics.face;
+@VintfStability
+interface ISession {
+ void generateChallenge(in int cookie, in int timeoutSec);
+ void revokeChallenge(in int cookie, in long challenge);
+ android.hardware.biometrics.common.ICancellationSignal enroll(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.common.NativeHandle previewSurface);
+ android.hardware.biometrics.common.ICancellationSignal authenticate(in int cookie, in long operationId);
+ android.hardware.biometrics.common.ICancellationSignal detectInteraction(in int cookie);
+ void enumerateEnrollments(in int cookie);
+ void removeEnrollments(in int cookie, in int[] enrollmentIds);
+ void getAuthenticatorId(in int cookie);
+ void invalidateAuthenticatorId(in int cookie);
+ void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+}
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
new file mode 100644
index 0000000..477ba5a
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.biometrics.face;
+@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 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);
+ void onAuthenticationSucceeded(in int enrollmentId, in android.hardware.keymaster.HardwareAuthToken hat);
+ void onAuthenticationFailed();
+ void onLockoutTimed(in long durationMillis);
+ void onLockoutPermanent();
+ void onLockoutCleared();
+ void onInteractionDetected();
+ void onEnrollmentsEnumerated(in int[] enrollmentIds);
+ void onEnrollmentsRemoved(in int[] enrollmentIds);
+ void onAuthenticatorIdRetrieved(in long authenticatorId);
+ void onAuthenticatorIdInvalidated();
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl
new file mode 100644
index 0000000..9f977f5
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.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.biometrics.face;
+@VintfStability
+parcelable SensorProps {
+ android.hardware.biometrics.common.CommonProps commonProps;
+ android.hardware.biometrics.face.FaceSensorType sensorType;
+ boolean halControlsPreview;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
new file mode 100644
index 0000000..8e5139b
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.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.biometrics.face;
+@Backing(type="byte") @VintfStability
+enum SessionState {
+ IDLING = 0,
+ TERMINATED = 1,
+ GENERATING_CHALLENGE = 2,
+ REVOKING_CHALLENGE = 3,
+ ENROLLING = 4,
+ AUTHENTICATING = 5,
+ DETECTING_INTERACTION = 6,
+ ENUMERATING_ENROLLMENTS = 7,
+ REMOVING_ENROLLMENTS = 8,
+ GETTING_AUTHENTICATOR_ID = 9,
+ INVALIDATING_AUTHENTICATOR_ID = 10,
+ RESETTING_LOCKOUT = 11,
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
new file mode 100644
index 0000000..fffb418
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -0,0 +1,219 @@
+/*
+ * 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.biometrics.face;
+
+@VintfStability
+@Backing(type="byte")
+enum AcquiredInfo {
+
+ /**
+ * The acquired face data was good, no further user interaction is necessary.
+ */
+ GOOD = 0,
+
+ /**
+ * The acquired face data was too noisy or did not have sufficient detail.
+ * This is a catch-all for all acquisition errors not captured by the other
+ * constants.
+ */
+ INSUFFICIENT = 1,
+
+ /**
+ * Because there was too much ambient light, the captured face data was too
+ * bright. It's reasonable to return this after multiple
+ * AcquiredInfo.INSUFFICIENT.
+ *
+ * The user is expected to take action to retry the operation in better
+ * lighting conditions when this is returned.
+ */
+ TOO_BRIGHT = 2,
+
+ /**
+ * Because there was not enough illumination, the captured face data was too
+ * dark. It's reasonable to return this after multiple
+ * AcquiredInfo.INSUFFICIENT.
+ *
+ * The user is expected to take action to retry the operation in better
+ * lighting conditions when this is returned.
+ */
+ TOO_DARK = 3,
+
+ /**
+ * The detected face is too close to the sensor, and the image cannot be
+ * processed.
+ *
+ * The user is expected to be informed to move further from the sensor when
+ * this is returned.
+ */
+ TOO_CLOSE = 4,
+
+ /**
+ * The detected face is too small, as the user might be too far away from
+ * the sensor.
+ *
+ * The user is expected to be informed to move closer to the sensor when
+ * this is returned.
+ */
+ TOO_FAR = 5,
+
+ /**
+ * Only the upper part of the face was detected. The sensor's field of view
+ * is too high.
+ *
+ * The user should be informed to move up with respect to the sensor when
+ * this is returned.
+ */
+ FACE_TOO_HIGH = 6,
+
+ /**
+ * Only the lower part of the face was detected. The sensor's field of view
+ * is too low.
+ *
+ * The user should be informed to move down with respect to the sensor when
+ * this is returned.
+ */
+ FACE_TOO_LOW = 7,
+
+ /**
+ * Only the right part of the face was detected. The sensor's field of view
+ * is too far right.
+ *
+ * The user should be informed to move to the right with respect to the
+ * sensor when this is returned.
+ */
+ FACE_TOO_RIGHT = 8,
+
+ /**
+ * Only the left part of the face was detected. The sensor's field of view
+ * is too far left.
+ *
+ * The user should be informed to move to the left with respect to the
+ * sensor when this is returned.
+ */
+ FACE_TOO_LEFT = 9,
+
+ /**
+ * The user's eyes have strayed away from the sensor. If this message is
+ * sent, the user should be informed to look at the device. If the user
+ * can't be found in the frame, one of the other acquisition messages
+ * must be sent, e.g. NOT_DETECTED.
+ */
+ POOR_GAZE = 10,
+
+ /**
+ * No face was detected within the sensor's field of view.
+ *
+ * The user should be informed to point the sensor to a face when this is
+ * returned.
+ */
+ NOT_DETECTED = 11,
+
+ /**
+ * Too much motion was detected.
+ *
+ * The user should be informed to keep their face steady relative to the
+ * sensor.
+ */
+ TOO_MUCH_MOTION = 12,
+
+ /**
+ * The sensor needs to be re-calibrated. This is an unexpected condition,
+ * and must only be sent if a serious, uncorrectable, and unrecoverable
+ * calibration issue is detected which requires user intervention, e.g.
+ * re-enrolling. The expected response to this message is to direct the
+ * user to re-enroll.
+ */
+ RECALIBRATE = 13,
+
+ /**
+ * The face is too different from a previous acquisition. This condition
+ * only applies to enrollment. This can happen if the user passes the
+ * device to someone else in the middle of enrollment.
+ */
+ TOO_DIFFERENT = 14,
+
+ /**
+ * The face is too similar to a previous acquisition. This condition only
+ * applies to enrollment. The user should change their pose.
+ */
+ TOO_SIMILAR = 15,
+
+ /**
+ * The magnitude of the pan angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The pan angle is defined as the angle swept out by the user’s face turning
+ * their neck left and right. The pan angle would be zero if the user faced the
+ * camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ PAN_TOO_EXTREME = 16,
+
+ /**
+ * The magnitude of the tilt angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The tilt angle is defined as the angle swept out by the user’s face looking up
+ * and down. The tilt angle would be zero if the user faced the camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ TILT_TOO_EXTREME = 17,
+
+ /**
+ * The magnitude of the roll angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The roll angle is defined as the angle swept out by the user’s face tilting their head
+ * towards their shoulders to the left and right. The roll angle would be zero if the user's
+ * head is vertically aligned with the camera.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ ROLL_TOO_EXTREME = 18,
+
+ /**
+ * The user’s face has been obscured by some object.
+ *
+ * The user should be informed to remove any objects from the line of sight from
+ * the sensor to the user’s face.
+ */
+ FACE_OBSCURED = 19,
+
+ /**
+ * This message represents the earliest message sent at the beginning of the authentication
+ * pipeline. It is expected to be used to measure latency. For example, in a camera-based
+ * authentication system it's expected to be sent prior to camera initialization. Note this
+ * should be sent whenever authentication is restarted (see IBiometricsFace#userActivity).
+ * The framework will measure latency based on the time between the last START message and the
+ * onAuthenticated callback.
+ */
+ START = 20,
+
+ /**
+ * The sensor is dirty. The user should be informed to clean the sensor.
+ */
+ SENSOR_DIRTY = 21,
+
+ /**
+ * Vendor-specific acquisition message. See ISessionCallback#onAcquired vendorCode
+ * documentation.
+ */
+ VENDOR = 22
+}
+
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl
new file mode 100644
index 0000000..1d02456
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl
@@ -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.biometrics.face;
+
+@VintfStability
+@Backing(type="byte")
+enum Error {
+ /**
+ * Reserved for testing and to keep subsequent numbering consistent with
+ * older interfaces.
+ *
+ * NO_ERROR = 0,
+ */
+
+ /**
+ * A hardware error has occurred that cannot be resolved. Try again later.
+ */
+ HW_UNAVAILABLE = 1,
+
+ /**
+ * The current enroll or authenticate operation could not be completed,
+ * e.g. the sensor was unable to process the current image or the HAT was
+ * invalid.
+ */
+ UNABLE_TO_PROCESS = 2,
+
+ /**
+ * The current operation took too long to complete. This is intended to
+ * prevent programs from blocking the face HAL indefinitely. The timeout is
+ * framework and sensor-specific, but is generally on the order of 30
+ * seconds.
+ *
+ * The timeout is a device-specific time meant to optimize power. For
+ * example after 30 seconds of searching for a face it can be use to
+ * indicate that the implementation is no longer looking and the framework
+ * should restart the operation on the next user interaction.
+ */
+ TIMEOUT = 3,
+
+ /**
+ * The current operation could not be completed because there is not enough
+ * storage space remaining to do so.
+ */
+ NO_SPACE = 4,
+
+ /**
+ * The current operation has been cancelled. This may happen if a new
+ * request (authenticate, remove, enumerate, enroll) is initiated while
+ * an on-going operation is in progress, or if cancel() was called.
+ */
+ CANCELED = 5,
+
+ /**
+ * The current remove operation could not be completed; the face template
+ * provided could not be removed.
+ */
+ UNABLE_TO_REMOVE = 6,
+
+ /**
+ * Reserved to maintain backwards compatibility. See
+ * ISessionCallback#onLockoutTimed instead.
+ *
+ * LOCKOUT = 7,
+ */
+
+ /**
+ * Used to enable a vendor-specific error message.
+ */
+ VENDOR = 8,
+
+ /**
+ * Reserved to maintain backwards compatibility. See
+ * ISessionCallback#onLockoutPermanent instead.
+ *
+ * LOCKOUT_PERMANENT = 9
+ */
+}
+
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
new file mode 100644
index 0000000..766f732
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.biometrics.face;
+
+@VintfStability
+@Backing(type="byte")
+enum FaceSensorType {
+ RGB,
+ IR
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
new file mode 100644
index 0000000..e9a66e2
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.face;
+
+import android.hardware.biometrics.face.ISession;
+import android.hardware.biometrics.face.ISessionCallback;
+import android.hardware.biometrics.face.SensorProps;
+
+@VintfStability
+interface IFace {
+ /**
+ * getSensorProps:
+ *
+ * @return A list of properties for all face sensors available to the HAL.
+ */
+ SensorProps[] getSensorProps();
+
+ /**
+ * createSession:
+ *
+ * Creates a session that can be used by the framework to perform operations such as
+ * enroll, authenticate, etc. for the given sensorId and userId.
+ *
+ * Implementations must store user-specific state or metadata in /data/vendor_de/<user>/facedata
+ * as specified by the SELinux policy. The directory /data/vendor_de is managed by vold (see
+ * vold_prepare_subdirs.cpp). Implementations may store additional user-specific data, such as
+ * embeddings or templates in StrongBox.
+ *
+ * @param sensorId The sensorId with which this session is being created.
+ * @param userId The userId with which this session is being created.
+ * @param cb A callback to notify the framework about the session's results and events.
+ * @return A new session.
+ */
+ ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
+
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
new file mode 100644
index 0000000..c7beae0
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -0,0 +1,365 @@
+/*
+ * 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.biometrics.face;
+
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.common.NativeHandle;
+
+/**
+ * A session is a collection of immutable state (sensorId, userId), mutable state (SessionState),
+ * methods available for the framework to call, and a callback (ISessionCallback) to notify the
+ * framework about the events and results. A session is used to establish communication between
+ * the framework and the HAL.
+ */
+@VintfStability
+interface ISession {
+ /**
+ * generateChallenge:
+ *
+ * Begins a secure transaction request. Note that the challenge by itself is not useful. It only
+ * becomes useful when wrapped in a verifiable message such as a HardwareAuthToken.
+ *
+ * Canonical example:
+ * 1) User requests an operation, such as face enrollment.
+ * 2) Face enrollment cannot happen until the user confirms their lockscreen credential
+ * (PIN/Pattern/Password).
+ * 3) However, the biometric subsystem does not want just "any" proof of credential
+ * confirmation. It needs proof that the user explicitly authenticated credential in order
+ * to allow addition of biometric enrollments.
+ * To secure this path, the following path is taken:
+ * 1) Upon user requesting face enroll, the framework requests
+ * IFace#generateChallenge
+ * 2) Framework sends the challenge to the credential subsystem, and upon credential
+ * confirmation, a HAT is created, containing the challenge in the "challenge" field.
+ * 3) Framework sends the HAT to the HAL, e.g. ISession#enroll.
+ * 4) Implementation verifies the authenticity and integrity of the HAT.
+ * 5) Implementation now has confidence that the user entered their credential to allow
+ * biometric enrollment.
+ *
+ * Note that the interface allows multiple in-flight challenges. For example, invoking
+ * generateChallenge(0, 0, timeoutSec) twice does not invalidate the first challenge. The
+ * challenge is invalidated only when:
+ * 1) The provided timeout expires, or
+ * 2) IFace#revokeChallenge is invoked
+ *
+ * For example, the following is a possible table of valid challenges:
+ * ----------------------------------------------
+ * | SensorId | UserId | ValidUntil | Challenge |
+ * |----------|--------|------------|-----------|
+ * | 0 | 0 | <Time1> | <Random1> |
+ * | 0 | 0 | <Time2> | <Random2> |
+ * | 1 | 0 | <Time3> | <Random3> |
+ * | 0 | 10 | <Time4> | <Random4> |
+ * ----------------------------------------------
+ *
+ * @param cookie A unique number identifying this operation
+ * @param timeoutSec Duration for which the challenge is valid for
+ */
+ void generateChallenge(in int cookie, in int timeoutSec);
+
+ /**
+ * revokeChallenge:
+ *
+ * Revokes a challenge that was previously generated. Note that if an invalid combination of
+ * parameters is requested, the implementation must still notify the framework using the
+ * provided callback.
+ *
+ * @param cookie A unique number identifying this operation
+ * @param challenge Challenge that should be revoked.
+ */
+ void revokeChallenge(in int cookie, in long challenge);
+
+ /**
+ * enroll:
+ *
+ * A request to add a face enrollment.
+ *
+ * Once the HAL is able to start processing the enrollment request, it must notify the framework
+ * via ISessionCallback#onStateChanged with SessionState::ENROLLING.
+ *
+ * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
+ * framework via ISessionCallback#onError with the applicable enrollment-specific error, and
+ * then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent
+ * operation is in the queue.
+ *
+ * Before capturing face data, the implementation must first verify the authenticity and
+ * integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
+ * within the provided HardwareAuthToken is valid. See IFace#generateChallenge. If any of
+ * the above checks fail, the framework must be notified via ISessionCallback#onError and the
+ * HAL must notify the framework when it returns to the idle state. See
+ * Error::UNABLE_TO_PROCESS.
+ *
+ * During enrollment, the implementation may notify the framework via
+ * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
+ * can be invoked multiple times if necessary. Similarly, the framework may be notified of
+ * enrollment progress changes via ISessionCallback#onEnrollmentProgress. Once the framework is
+ * notified that there are 0 "remaining" steps, the framework may cache the "enrollmentId". See
+ * ISessionCallback#onEnrollmentProgress for more info. The HAL must notify the framework once
+ * it returns to the idle state.
+ *
+ * When a finger is successfully added and before the framework is notified of remaining=0, the
+ * implementation MUST update and associate this (sensorId, userId) pair with a new new
+ * entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
+ *
+ * @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 previewSurface A surface provided by the framework if SensorProps#halControlsPreview is
+ * set to true. The HAL must send the preview frames to previewSurface if
+ * it's not null.
+ * @param hat See above documentation.
+ * @return ICancellationSignal An object that can be used by the framework to cancel this
+ * operation.
+ */
+ ICancellationSignal enroll(in int cookie, in HardwareAuthToken hat, in NativeHandle previewSurface);
+
+ /**
+ * authenticate:
+ *
+ * A request to start looking for faces to authenticate.
+ *
+ * Once the HAL is able to start processing the authentication request, it must notify framework
+ * via ISessionCallback#onStateChanged with SessionState::AUTHENTICATING.
+ *
+ * At any point during authentication, if a non-recoverable error occurs, the HAL must notify
+ * the framework via ISessionCallback#onError with the applicable authentication-specific error,
+ * and then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no
+ * subsequent operation is in the queue.
+ *
+ * During authentication, the implementation may notify the framework via
+ * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
+ * can be invoked multiple times if necessary.
+ *
+ * The HAL must notify the framework of accepts/rejects via ISessionCallback#onAuthentication*.
+ *
+ * The authentication lifecycle ends when either
+ * 1) A face is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked, or
+ * 2) Any non-recoverable error occurs (such as lockout). See the full list of
+ * authentication-specific errors in the Error enum.
+ *
+ * Note that upon successful authentication, the lockout counter for this (sensorId, userId)
+ * pair must be cleared.
+ *
+ * Note that upon successful authentication, ONLY sensors configured as SensorStrength::STRONG
+ * are allowed to create and send a HardwareAuthToken to the framework. See the Android CDD for
+ * more details. For SensorStrength::STRONG sensors, the HardwareAuthToken's "challenge" field
+ * must be set with the operationId passed in during #authenticate. If the sensor is NOT
+ * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
+ *
+ * @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 operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
+ * upon successful authentication and wrapped in the HardwareAuthToken's
+ * "challenge" field and sent to the framework via
+ * ISessionCallback#onAuthenticated. The operationId is an opaque identifier
+ * created from a separate secure subsystem such as, but not limited to
+ * KeyStore/KeyMaster. The HardwareAuthToken can then be used as an
+ * attestation for the provided operation. For example, this is used
+ * to unlock biometric-bound auth-per-use keys (see
+ * setUserAuthenticationParameters in KeyGenParameterSpec.Builder and
+ * KeyProtection.Builder.
+ * @return ICancellationSignal An object that can be used by the framework to cancel this
+ * operation.
+ */
+ ICancellationSignal authenticate(in int cookie, in long operationId);
+
+ /**
+ * detectInteraction:
+ *
+ * A request to start looking for faces without performing matching.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::DETECTING_INTERACTION.
+ *
+ * The framework will use this method in cases where determing user presence is required, but
+ * identifying/authentication is not. For example, when the device is encrypted (first boot) or
+ * in lockdown mode.
+ *
+ * At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
+ * the framework via ISessionCallback#onError with the applicable error, and then send
+ * ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent operation is
+ * in the queue.
+ *
+ * The implementation must only check for a face-like image was detected (e.g. to
+ * minimize interactions due to non-face objects), and the lockout counter must not
+ * be modified.
+ *
+ * Upon detecting any face, the implementation must invoke
+ * ISessionCallback#onInteractionDetected.
+ *
+ * The lifecycle of this operation ends when either
+ * 1) Any face is detected and the framework is notified via
+ * ISessionCallback#onInteractiondetected
+ * 2) The operation was cancelled by the framework (see ICancellationSignal)
+ * 3) The HAL ends the operation, for example when a subsequent operation pre-empts this one.
+ *
+ * Note that if the operation is canceled, the implementation must notify the framework via
+ * ISessionCallback#onError with Error::CANCELED.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ * @return ICancellationSignal An object that can be used by the framework to cancel this
+ * operation.
+ */
+ ICancellationSignal detectInteraction(in int cookie);
+
+ /*
+ * enumerateEnrollments:
+ *
+ * A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
+ * framework typically uses this to ensure that its cache is in sync with the HAL.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::ENUMERATING_ENROLLMENTS.
+ *
+ * The implementation must then notify the framework with a list of enrollments applicable
+ * for the current session via ISessionCallback#onEnrollmentsEnumerated.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ */
+ void enumerateEnrollments(in int cookie);
+
+ /**
+ * removeEnrollments:
+ *
+ * A request to remove the enrollments for this (sensorId, userId) pair.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::REMOVING_ENROLLMENTS.
+ *
+ * After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
+ * etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ */
+ void removeEnrollments(in int cookie, in int[] enrollmentIds);
+
+ /**
+ * getAuthenticatorId:
+ *
+ * MUST return 0 via ISessionCallback#onAuthenticatorIdRetrieved for sensors that are configured
+ * as SensorStrength::WEAK or SensorStrength::CONVENIENCE.
+ *
+ * The following only applies to sensors that are configured as SensorStrength::STRONG.
+ *
+ * The authenticatorId is a (sensorId, user)-specific identifier which can be used during key
+ * generation and key import to to associate a key (in KeyStore / KeyMaster) with the current
+ * set of enrolled faces. For example, the following public Android APIs allow for keys
+ * to be invalidated when the user adds a new enrollment after the key was created:
+ * KeyGenParameterSpec.Builder.setInvalidatedByBiometricEnrollment and
+ * KeyProtection.Builder.setInvalidatedByBiometricEnrollment.
+ *
+ * In addition, upon successful face authentication, the signed HAT that is returned to
+ * the framework via ISessionCallback#onAuthenticated must contain this identifier in the
+ * authenticatorId field.
+ *
+ * Returns an entropy-encoded random identifier associated with the current set of enrollments
+ * via ISessionCallback#onAuthenticatorIdRetrieved. The authenticatorId
+ * 1) MUST change whenever a new face is enrolled
+ * 2) MUST return 0 if no faces are enrolled
+ * 3) MUST not change if a face is deleted.
+ * 4) MUST be an entropy-encoded random number
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path. The
+ * client must guarantee that it is unique per ISession.
+ */
+ void getAuthenticatorId(in int cookie);
+
+ /**
+ * invalidateAuthenticatorId:
+ *
+ * This method only applies to sensors that are configured as SensorStrength::STRONG. If invoked
+ * by the framework for sensor of other strengths, the HAL should immediately invoke
+ * ISessionCallback#onAuthenticatorIdInvalidated.
+ *
+ * The following only applies to sensors that are configured as SensorStrength::STRONG.
+ *
+ * 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
+ * ISessionCallback#onAuthenticatorInvalidated
+ *
+ * A practical use case of invalidation would be when the user adds a new enrollment to a sensor
+ * managed by a different HAL instance. The public android.security.keystore APIs bind keys to
+ * "all biometrics" rather than "face-only" or "face-only" (see #getAuthenticatorId
+ * for more details). As such, the framework would coordinate invalidation across multiple
+ * biometric HALs as necessary.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path. The
+ * client must guarantee that it is unique per ISession.
+ */
+ void invalidateAuthenticatorId(in int cookie);
+
+ /**
+ * resetLockout:
+ *
+ * Requests the implementation to clear the lockout counter. Upon receiving this request, the
+ * implementation must perform the following:
+ * 1) Verify the authenticity and integrity of the provided HAT
+ * 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
+ * order of minutes, not hours).
+ * If either of the checks fail, the HAL must invoke ISessionCallback#onError with
+ * Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in the
+ * queue.
+ *
+ * Upon successful verification, the HAL must clear the lockout counter and notify the framework
+ * via ISessionCallback#onLockoutCleared.
+ *
+ * Note that lockout is user AND sensor specific. In other words, there is a separate lockout
+ * state for each (user, sensor) pair. For example, the following is a valid state on a
+ * multi-sensor device:
+ * ------------------------------------------------------------------
+ * | SensorId | UserId | FailedAttempts | LockedOut | LockedUntil |
+ * |----------|--------|----------------|-----------|---------------|
+ * | 0 | 0 | 1 | false | x |
+ * | 1 | 0 | 5 | true | <future_time> |
+ * | 0 | 10 | 0 | false | x |
+ * | 1 | 10 | 0 | false | x |
+ * ------------------------------------------------------------------
+ *
+ * Lockout may be cleared in the following ways:
+ * 1) ISession#resetLockout
+ * 2) After a period of time, according to a rate-limiter.
+ *
+ * Note that the "FailedAttempts" counter must be cleared upon successful face
+ * authentication. For example, if SensorId=0 UserId=0 FailedAttempts=1, and a successful
+ * face authentication occurs, the counter for that (SensorId, UserId) pair must be reset
+ * to 0.
+ *
+ * In addition, lockout states MUST persist after device reboots, HAL crashes, etc.
+ *
+ * See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
+ * requirements.
+ *
+ * @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 See above documentation.
+ */
+ void resetLockout(in int cookie, in HardwareAuthToken hat);
+}
+
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
new file mode 100644
index 0000000..2608d5f
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.face;
+
+import android.hardware.biometrics.face.AcquiredInfo;
+import android.hardware.biometrics.face.Error;
+import android.hardware.biometrics.face.SessionState;
+import android.hardware.keymaster.HardwareAuthToken;
+
+@VintfStability
+interface ISessionCallback {
+ /**
+ * Used to notify the framework of session state changes. See ISession for more information.
+ */
+ void onStateChanged(in int cookie, in SessionState state);
+
+ /**
+ * Notifies the framework when a challenge is successfully generated.
+ */
+ void onChallengeGenerated(in int sensorId, in int userId, in long challenge);
+
+ /**
+ * Notifies the framework when a challenge has been revoked.
+ */
+ void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
+
+ /**
+ * This method must only be used to notify the framework during the following states:
+ * 1) SessionState::ENROLLING
+ * 2) SessionState::AUTHENTICATING
+ * 3) SessionState::DETECTING_INTERACTION
+ *
+ * These messages may be used to provide user guidance multiple times if necessary per
+ * operation.
+ *
+ * @param info See the AcquiredInfo enum.
+ * @param vendorCode Only valid if info == AcquiredInfo::VENDOR. The vendorCode must be used to
+ * index into the configuration
+ * com.android.internal.R.array.face_acquired_vendor that's installed
+ * on the vendor partition.
+ */
+ void onAcquired(in AcquiredInfo info, in int vendorCode);
+
+ /**
+ * This method must only be used to notify the framework during the following states:
+ * 1) SessionState::ENROLLING
+ * 2) SessionState::AUTHENTICATING
+ * 3) SessionState::DETECTING_INTERACTION
+ * 4) SessionState::INVALIDATING_AUTHENTICATOR_ID
+ * 5) SessionState::RESETTING_LOCKOUT
+ *
+ * These messages may be used to notify the framework or user that a non-recoverable error
+ * has occurred. The operation is finished, and the HAL must proceed with the next operation
+ * or return to SessionState::IDLING if the queue is empty.
+ *
+ * Note that cancellation (see common::ICancellationSignal) and preemption most be followed with
+ * an Error::CANCELED message.
+ *
+ * @param error See the Error enum.
+ * @param vendorCode Only valid if error == Error::VENDOR. The vendorCode must be used to index
+ * into the configuration
+ * com.android.internal.R.face_error_vendor that's installed on the
+ * vendor partition.
+ */
+ void onError(in Error error, in int vendorCode);
+
+ /**
+ * This method must only be used to notify the framework during the following state:
+ * 1) SessionState::ENROLLING
+ *
+ * @param enrollmentId Unique stable identifier for the enrollment that's being added by this
+ * ISession#enroll invocation.
+ * @param remaining Remaining number of steps before enrollment is complete.
+ */
+ void onEnrollmentProgress(in int enrollmentId, int remaining);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Used to notify the framework upon successful authentication. Note that the authentication
+ * lifecycle ends when either 1) a face is accepted, or 2) an error occurred. The
+ * authentication lifecycle does NOT end when a face is rejected.
+ *
+ * @param enrollmentId Face that was accepted.
+ * @param hat If the sensor is configured as SensorStrength::STRONG, a non-null attestation that
+ * a face was accepted. The HardwareAuthToken's "challenge" field must be set
+ * with the operationId passed in during ISession#authenticate. If the sensor is NOT
+ * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
+ */
+ void onAuthenticationSucceeded(in int enrollmentId, in HardwareAuthToken hat);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Used to notify the framework upon rejected attempts. Note that the authentication
+ * lifecycle ends when either 1) a face is accepted, or 2) an occurred. The
+ * authentication lifecycle does NOT end when a face is rejected.
+ */
+ void onAuthenticationFailed();
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Authentication is locked out due to too many unsuccessful attempts. This is a rate-limiting
+ * lockout, and authentication can be restarted after a period of time. See
+ * ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ * @param durationMillis Remaining duration of the lockout.
+ */
+ void onLockoutTimed(in long durationMillis);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Authentication is disabled until the user unlocks with their device credential
+ * (PIN/Pattern/Password). See ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ */
+ void onLockoutPermanent();
+
+ /**
+ * Notifies the framework that lockout has been cleared for this (sensorId, userId) pair.
+ *
+ * Note that this method can be used to notify the framework during any state.
+ *
+ * Lockout can be cleared in the following scenarios:
+ * 1) A timed lockout has ended (e.g. durationMillis specified in previous #onLockoutTimed
+ * has expired.
+ * 2) See ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user's lockout is cleared.
+ * @param userId User for the sensor's lockout is cleared.
+ */
+ void onLockoutCleared();
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::DETECTING_INTERACTION
+ *
+ * Notifies the framework that user interaction occurred. See ISession#detectInteraction.
+ */
+ void onInteractionDetected();
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::ENUMERATING_ENROLLMENTS.
+ *
+ * Notifies the framework of the current enrollments. See ISession#enumerateEnrollments.
+ *
+ * @param enrollmentIds A list of enrollments for the session's (userId, sensorId) pair.
+ */
+ void onEnrollmentsEnumerated(in int[] enrollmentIds);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::REMOVING_ENROLLMENTS.
+ *
+ * Notifies the framework that the specified enrollments are removed.
+ *
+ * @param enrollmentIds The enrollments that were removed.
+ */
+ void onEnrollmentsRemoved(in int[] enrollmentIds);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::GETTING_AUTHENTICATOR_ID.
+ *
+ * Notifies the framework with the authenticatorId corresponding to this session's
+ * (userId, sensorId) pair.
+ *
+ * @param authenticatorId See the above documentation.
+ */
+ void onAuthenticatorIdRetrieved(in long authenticatorId);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::INVALIDATING_AUTHENTICATOR_ID.
+ *
+ * See ISession#invalidateAuthenticatorId for more information.
+ */
+ void onAuthenticatorIdInvalidated();
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl
new file mode 100644
index 0000000..53cc44e
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.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.biometrics.face;
+
+import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.face.FaceSensorType;
+
+@VintfStability
+parcelable SensorProps {
+ /**
+ * Statically configured properties that apply to this face sensor.
+ */
+ CommonProps commonProps;
+
+ /**
+ * A statically configured sensor type representing this face sensor.
+ */
+ FaceSensorType sensorType;
+
+ /**
+ * Whether or not the HAL is responsible for showing the face enrollment preview to the user.
+ * Devices with multiple front camera sensors can set this to false and rely on the framework to
+ * show the preview with one of the unused cameras. Devices with a single front sensor must set
+ * this to true and configure their send their camera stream to the preview surface provided by
+ * the framework.
+ */
+ boolean halControlsPreview;
+}
+
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
new file mode 100644
index 0000000..1878f7c
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.face;
+
+@VintfStability
+@Backing(type="byte")
+enum SessionState {
+ /**
+ * The HAL is not processing any session requests.
+ */
+ IDLING,
+
+ /**
+ * The session has been terminated by the HAL.
+ */
+ TERMINATED,
+
+ /**
+ * The HAL is processing the ISession#generateChallenge request.
+ */
+ GENERATING_CHALLENGE,
+
+ /**
+ * The HAL is processing the ISession#revokeChallenge request.
+ */
+ REVOKING_CHALLENGE,
+
+ /**
+ * The HAL is processing the ISession#enroll request.
+ */
+ ENROLLING,
+
+ /**
+ * The HAL is processing the ISession#authenticate request.
+ */
+ AUTHENTICATING,
+
+ /**
+ * The HAL is processing the ISession#detectInteraction request.
+ */
+ DETECTING_INTERACTION,
+
+ /**
+ * The HAL is processing the ISession#enumerateEnrollments request.
+ */
+ ENUMERATING_ENROLLMENTS,
+
+ /**
+ * The HAL is processing the ISession#removeEnrollments request.
+ */
+ REMOVING_ENROLLMENTS,
+
+ /**
+ * The HAL is processing the ISession#getAuthenticatorId request.
+ */
+ GETTING_AUTHENTICATOR_ID,
+
+ /**
+ * The HAL is processing the ISession#invalidateAuthenticatorId request.
+ */
+ INVALIDATING_AUTHENTICATOR_ID,
+
+ /**
+ * The HAL is processing the ISession#resetLockout request.
+ */
+ RESETTING_LOCKOUT
+}
+
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
new file mode 100644
index 0000000..51a8ef4
--- /dev/null
+++ b/biometrics/face/aidl/default/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+ name: "android.hardware.biometrics.face-service.example",
+ relative_install_path: "hw",
+ init_rc: ["face-default.rc"],
+ vintf_fragments: ["face-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.biometrics.face-ndk_platform",
+ "android.hardware.biometrics.common-unstable-ndk_platform",
+ ],
+ srcs: [
+ "main.cpp",
+ "Face.cpp",
+ "Session.cpp",
+ ],
+}
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
new file mode 100644
index 0000000..1526245
--- /dev/null
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "Face.h"
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::face {
+
+const int kSensorId = 0;
+const common::SensorStrength kSensorStrength = common::SensorStrength::WEAK;
+const int kMaxEnrollmentsPerUser = 5;
+const FaceSensorType kSensorType = FaceSensorType::RGB;
+const bool kHalControlsPreview = true;
+const std::string kHwDeviceName = "faceSensor";
+const std::string kHardwareVersion = "vendor/model/revision";
+const std::string kFirmwareVersion = "1.01";
+const std::string kSerialNumber = "00000001";
+
+ndk::ScopedAStatus Face::getSensorProps(std::vector<SensorProps>* return_val) {
+ common::HardwareInfo hardware_info;
+ hardware_info.deviceName = kHwDeviceName;
+ hardware_info.hardwareVersion = kHardwareVersion;
+ hardware_info.firmwareVersion = kFirmwareVersion;
+ hardware_info.serialNumber = kSerialNumber;
+
+ common::CommonProps commonProps;
+ commonProps.sensorId = kSensorId;
+ commonProps.sensorStrength = kSensorStrength;
+ commonProps.maxEnrollmentsPerUser = kMaxEnrollmentsPerUser;
+ commonProps.hardwareInfo = {std::move(hardware_info)};
+
+ SensorProps props;
+ props.commonProps = std::move(commonProps);
+ props.sensorType = kSensorType;
+ props.halControlsPreview = kHalControlsPreview;
+
+ *return_val = {std::move(props)};
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Face::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
+ const std::shared_ptr<ISessionCallback>& cb,
+ std::shared_ptr<ISession>* return_val) {
+ *return_val = SharedRefBase::make<Session>(cb);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h
new file mode 100644
index 0000000..786b4f8
--- /dev/null
+++ b/biometrics/face/aidl/default/Face.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/face/BnFace.h>
+
+namespace aidl::android::hardware::biometrics::face {
+
+class Face : public BnFace {
+ public:
+ ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
+
+ ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
+ const std::shared_ptr<ISessionCallback>& cb,
+ std::shared_ptr<ISession>* _aidl_return) override;
+};
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
new file mode 100644
index 0000000..2b1d4a7
--- /dev/null
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -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.
+ */
+
+#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
+
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::face {
+
+class CancellationSignal : public common::BnCancellationSignal {
+ public:
+ ndk::ScopedAStatus cancel() override { 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*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t /*challenge*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::enroll(int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
+ const NativeHandle& /*previewSurface*/,
+ std::shared_ptr<biometrics::common::ICancellationSignal>*
+ /*returnVal*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
+ std::shared_ptr<common::ICancellationSignal>* return_val) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::AUTHENTICATING);
+ }
+ *return_val = SharedRefBase::make<CancellationSignal>();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::detectInteraction(
+ int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
+ const std::vector<int32_t>& /*enrollmentIds*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
+ const keymaster::HardwareAuthToken& /*hat*/) {
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
new file mode 100644
index 0000000..2bb5c42
--- /dev/null
+++ b/biometrics/face/aidl/default/Session.h
@@ -0,0 +1,65 @@
+/*
+ * 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/biometrics/face/BnSession.h>
+#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
+
+namespace aidl::android::hardware::biometrics::face {
+
+namespace common = aidl::android::hardware::biometrics::common;
+namespace keymaster = aidl::android::hardware::keymaster;
+
+using aidl::android::hardware::common::NativeHandle;
+
+class Session : public BnSession {
+ public:
+ explicit Session(std::shared_ptr<ISessionCallback> cb);
+
+ ndk::ScopedAStatus generateChallenge(int32_t cookie, int32_t timeoutSec) override;
+
+ ndk::ScopedAStatus revokeChallenge(int32_t cookie, int64_t challenge) override;
+
+ ndk::ScopedAStatus enroll(
+ int32_t cookie, const keymaster::HardwareAuthToken& hat,
+ const NativeHandle& previewSurface,
+ std::shared_ptr<biometrics::common::ICancellationSignal>* returnVal) override;
+
+ ndk::ScopedAStatus authenticate(
+ int32_t cookie, int64_t keystoreOperationId,
+ std::shared_ptr<common::ICancellationSignal>* returnVal) override;
+
+ ndk::ScopedAStatus detectInteraction(
+ int32_t cookie, std::shared_ptr<common::ICancellationSignal>* returnVal) override;
+
+ ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
+
+ ndk::ScopedAStatus removeEnrollments(int32_t cookie,
+ const std::vector<int32_t>& enrollmentIds) override;
+
+ ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
+
+ ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie) override;
+
+ ndk::ScopedAStatus resetLockout(int32_t cookie,
+ const keymaster::HardwareAuthToken& hat) override;
+
+ private:
+ std::shared_ptr<ISessionCallback> cb_;
+};
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc
new file mode 100644
index 0000000..f6499f0
--- /dev/null
+++ b/biometrics/face/aidl/default/face-default.rc
@@ -0,0 +1,5 @@
+service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.example
+ class hal
+ user nobody
+ group nobody
+
diff --git a/biometrics/face/aidl/default/face-default.xml b/biometrics/face/aidl/default/face-default.xml
new file mode 100644
index 0000000..6915ad0
--- /dev/null
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.biometrics.face</name>
+ <fqname>IFace/default</fqname>
+ </hal>
+</manifest>
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
new file mode 100644
index 0000000..80b153e
--- /dev/null
+++ b/biometrics/face/aidl/default/main.cpp
@@ -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.
+ */
+
+#include "Face.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::biometrics::face::Face;
+
+int main() {
+ LOG(INFO) << "Face HAL started";
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Face> hal = ndk::SharedRefBase::make<Face>();
+
+ const std::string instance = std::string(Face::descriptor) + "/default";
+ binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/biometrics/face/aidl/vts/Android.bp b/biometrics/face/aidl/vts/Android.bp
new file mode 100644
index 0000000..427b878
--- /dev/null
+++ b/biometrics/face/aidl/vts/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+ name: "VtsHalBiometricsFaceTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalBiometricsFaceTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ "android.hardware.biometrics.face-ndk_platform",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
new file mode 100644
index 0000000..c1ba66b
--- /dev/null
+++ b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.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 <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/biometrics/face/BnFace.h>
+#include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <future>
+
+namespace aidl::android::hardware::biometrics::face {
+namespace {
+
+constexpr int kSensorId = 0;
+constexpr int kUserId = 0;
+constexpr auto kCallbackTimeout = std::chrono::seconds(1);
+
+enum class SessionCallbackMethodName {
+ kOnStateChanged,
+};
+
+struct SessionCallbackInvocation {
+ SessionCallbackMethodName method_name;
+ SessionState state;
+};
+
+class SessionCallback : public BnSessionCallback {
+ public:
+ explicit SessionCallback(std::promise<SessionCallbackInvocation> invocation_promise)
+ : invocation_promise_(std::move(invocation_promise)) {}
+ ndk::ScopedAStatus onStateChanged(int32_t /*cookie*/, SessionState state) override {
+ SessionCallbackInvocation invocation = {};
+ invocation.method_name = SessionCallbackMethodName::kOnStateChanged;
+ invocation.state = state;
+ invocation_promise_.set_value(invocation);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onChallengeGenerated(int32_t /*sensorId*/, int32_t /*userId*/,
+ int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onChallengeRevoked(int32_t /*sensorId*/, int32_t /*userId*/,
+ int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onError(Error /*error*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
+ int32_t /*remaining*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticationSucceeded(
+ int32_t /*enrollmentId*/, const keymaster::HardwareAuthToken& /*hat*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus onLockoutTimed(int64_t /*durationMillis*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus onEnrollmentsEnumerated(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onEnrollmentsRemoved(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticatorIdInvalidated() override { return ndk::ScopedAStatus::ok(); }
+
+ private:
+ std::promise<SessionCallbackInvocation> invocation_promise_;
+};
+
+class Face : public testing::TestWithParam<std::string> {
+ protected:
+ void SetUp() override {
+ AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+ ASSERT_NE(binder, nullptr);
+ hal_ = IFace::fromBinder(ndk::SpAIBinder(binder));
+ }
+
+ std::shared_ptr<IFace> hal_;
+};
+
+TEST_P(Face, AuthenticateTest) {
+ std::promise<SessionCallbackInvocation> invocation_promise;
+ std::future<SessionCallbackInvocation> invocation_future = invocation_promise.get_future();
+ std::shared_ptr<SessionCallback> session_cb =
+ ndk::SharedRefBase::make<SessionCallback>(std::move(invocation_promise));
+
+ std::shared_ptr<ISession> session;
+ ASSERT_TRUE(hal_->createSession(kSensorId, kUserId, session_cb, &session).isOk());
+
+ std::shared_ptr<common::ICancellationSignal> cancel_cb;
+ ASSERT_TRUE(session->authenticate(0, 0, &cancel_cb).isOk());
+ ASSERT_EQ(invocation_future.wait_for(kCallbackTimeout), std::future_status::ready);
+
+ SessionCallbackInvocation invocation = invocation_future.get();
+ EXPECT_EQ(invocation.method_name, SessionCallbackMethodName::kOnStateChanged);
+ EXPECT_EQ(invocation.state, SessionState::AUTHENTICATING);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Face);
+INSTANTIATE_TEST_SUITE_P(IFace, Face,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IFace::descriptor)),
+ ::android::PrintInstanceNameToString);
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
index df29fd4..e0789ce 100644
--- a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -136,6 +136,7 @@
} // anonymous namespace
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FingerprintHidlTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
IBiometricsFingerprint::descriptor)),
diff --git a/biometrics/fingerprint/2.3/Android.bp b/biometrics/fingerprint/2.3/Android.bp
new file mode 100644
index 0000000..cf63502
--- /dev/null
+++ b/biometrics/fingerprint/2.3/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.fingerprint@2.3",
+ root: "android.hardware",
+ srcs: [
+ "IBiometricsFingerprint.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hardware.biometrics.fingerprint@2.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..13f03c5
--- /dev/null
+++ b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
@@ -0,0 +1,66 @@
+/*
+ * 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.biometrics.fingerprint@2.3;
+
+import @2.2::IBiometricsFingerprint;
+
+/**
+ * The interface for biometric fingerprint authentication.
+ */
+interface IBiometricsFingerprint extends @2.2::IBiometricsFingerprint {
+ /**
+ * Returns whether the fingerprint sensor is an under-display fingerprint
+ * sensor.
+ * @param sensorId the unique sensor ID for which the operation should be
+ * performed.
+ * @return isUdfps indicating whether the specified sensor is an
+ * under-display fingerprint sensor.
+ */
+ isUdfps(uint32_t sensorId) generates (bool isUdfps);
+
+ /**
+ * Notifies about a touch occurring within the under-display fingerprint
+ * sensor area.
+ *
+ * It it assumed that the device can only have one active under-display
+ * fingerprint sensor at a time.
+ *
+ * If multiple fingers are detected within the sensor area, only the
+ * chronologically first event will be reported.
+ *
+ * @param x The screen x-coordinate of the center of the touch contact area, in
+ * display pixels.
+ * @param y The screen y-coordinate of the center of the touch contact area, in
+ * display pixels.
+ * @param minor The length of the minor axis of an ellipse that describes the
+ * touch area, in display pixels.
+ * @param major The length of the major axis of an ellipse that describes the
+ * touch area, in display pixels.
+ */
+ onFingerDown(uint32_t x, uint32_t y, float minor, float major);
+
+ /**
+ * Notifies about a finger leaving the under-display fingerprint sensor area.
+ *
+ * It it assumed that the device can only have one active under-display
+ * fingerprint sensor at a time.
+ *
+ * If multiple fingers have left the sensor area, only the finger which
+ * previously caused a "finger down" event will be reported.
+ */
+ onFingerUp();
+};
diff --git a/biometrics/fingerprint/2.3/vts/functional/Android.bp b/biometrics/fingerprint/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..521c0f4
--- /dev/null
+++ b/biometrics/fingerprint/2.3/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFingerprintV2_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFingerprintV2_3TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hardware.biometrics.fingerprint@2.2",
+ "android.hardware.biometrics.fingerprint@2.3",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp b/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp
new file mode 100644
index 0000000..d2a08a0
--- /dev/null
+++ b/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 ASSERT_OK(v) ASSERT_TRUE(v.isOk())
+
+#include <android/hardware/biometrics/fingerprint/2.3/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+namespace {
+
+namespace hidl_interface_2_3 = android::hardware::biometrics::fingerprint::V2_3;
+
+using hidl_interface_2_3::IBiometricsFingerprint;
+
+using android::sp;
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFingerprint::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ }
+
+ sp<IBiometricsFingerprint> mService;
+};
+
+// This method returns true or false depending on the implementation.
+TEST_P(FingerprintHidlTest, isUdfpsTest) {
+ // Arbitrary ID
+ uint32_t sensorId = 1234;
+ ASSERT_OK(mService->isUdfps(sensorId));
+}
+
+// This method that doesn't return anything.
+TEST_P(FingerprintHidlTest, onFingerDownTest) {
+ ASSERT_OK(mService->onFingerDown(1, 2, 3.0f, 4.0f));
+}
+
+// This method that doesn't return anything.
+TEST_P(FingerprintHidlTest, onFingerUp) {
+ ASSERT_OK(mService->onFingerUp());
+}
+
+} // anonymous namespace
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FingerprintHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IBiometricsFingerprint::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
new file mode 100644
index 0000000..6bf2038
--- /dev/null
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -0,0 +1,20 @@
+aidl_interface {
+ name: "android.hardware.biometrics.fingerprint",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/biometrics/fingerprint/**/*.aidl",
+ ],
+ imports: [
+ "android.hardware.biometrics.common",
+ "android.hardware.keymaster",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/biometrics/fingerprint/aidl/OWNERS b/biometrics/fingerprint/aidl/OWNERS
new file mode 100644
index 0000000..36d7261
--- /dev/null
+++ b/biometrics/fingerprint/aidl/OWNERS
@@ -0,0 +1,2 @@
+ilyamaty@google.com
+kchyn@google.com
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
new file mode 100644
index 0000000..df30dca
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.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.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum AcquiredInfo {
+ GOOD = 0,
+ PARTIAL = 1,
+ INSUFFICIENT = 2,
+ SENSOR_DIRTY = 3,
+ TOO_SLOW = 4,
+ TOO_FAST = 5,
+ VENDOR = 6,
+ START = 7,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
new file mode 100644
index 0000000..6bd71b2
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.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.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum Error {
+ HW_UNAVAILABLE = 1,
+ UNABLE_TO_PROCESS = 2,
+ TIMEOUT = 3,
+ NO_SPACE = 4,
+ CANCELED = 5,
+ UNABLE_TO_REMOVE = 6,
+ VENDOR = 8,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
new file mode 100644
index 0000000..14bfece
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.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.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum FingerprintSensorType {
+ UNKNOWN = 0,
+ REAR = 1,
+ UNDER_DISPLAY_ULTRASONIC = 2,
+ UNDER_DISPLAY_OPTICAL = 3,
+ POWER_BUTTON = 4,
+ HOME_BUTTON = 5,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
new file mode 100644
index 0000000..c5c6786
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.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.biometrics.fingerprint;
+@VintfStability
+interface IFingerprint {
+ android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
+ android.hardware.biometrics.fingerprint.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.ISessionCallback cb);
+}
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
new file mode 100644
index 0000000..00a08ba
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.biometrics.fingerprint;
+@VintfStability
+interface ISession {
+ void generateChallenge(in int cookie, in int timeoutSec);
+ void revokeChallenge(in int cookie, in long challenge);
+ android.hardware.biometrics.common.ICancellationSignal enroll(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+ android.hardware.biometrics.common.ICancellationSignal authenticate(in int cookie, in long operationId);
+ android.hardware.biometrics.common.ICancellationSignal detectInteraction(in int cookie);
+ 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 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);
+ void onUiReady();
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
new file mode 100644
index 0000000..b7a48a5
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.biometrics.fingerprint;
+@VintfStability
+interface ISessionCallback {
+ void onStateChanged(in int cookie, in android.hardware.biometrics.fingerprint.SessionState state);
+ void onChallengeGenerated(in long challenge);
+ void onChallengeRevoked(in long challenge);
+ void onAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfo info, in int vendorCode);
+ void onError(in android.hardware.biometrics.fingerprint.Error error, in int vendorCode);
+ void onEnrollmentProgress(in int enrollmentId, int remaining);
+ void onAuthenticationSucceeded(in int enrollmentId, in android.hardware.keymaster.HardwareAuthToken hat);
+ void onAuthenticationFailed();
+ void onLockoutTimed(in long durationMillis);
+ void onLockoutPermanent();
+ void onLockoutCleared();
+ void onInteractionDetected();
+ void onEnrollmentsEnumerated(in int[] enrollmentIds);
+ void onEnrollmentsRemoved(in int[] enrollmentIds);
+ void onAuthenticatorIdRetrieved(in long authenticatorId);
+ void onAuthenticatorIdInvalidated();
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
new file mode 100644
index 0000000..8c779ab
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.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.biometrics.fingerprint;
+@VintfStability
+parcelable SensorProps {
+ android.hardware.biometrics.common.CommonProps commonProps;
+ android.hardware.biometrics.fingerprint.FingerprintSensorType sensorType;
+ boolean supportsNavigationGestures;
+ int sensorLocationX;
+ int sensorLocationY;
+ int sensorRadius;
+ int displayId;
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
new file mode 100644
index 0000000..e9daef1
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.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.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum SessionState {
+ IDLING = 0,
+ GENERATING_CHALLENGE = 1,
+ REVOKING_CHALLENGE = 2,
+ ENROLLING = 3,
+ AUTHENTICATING = 4,
+ DETECTING_INTERACTION = 5,
+ ENUMERATING_ENROLLMENTS = 6,
+ REMOVING_ENROLLMENTS = 7,
+ GETTING_AUTHENTICATOR_ID = 8,
+ INVALIDATING_AUTHENTICATOR_ID = 9,
+ RESETTING_LOCKOUT = 10,
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
new file mode 100644
index 0000000..adb1c78
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum AcquiredInfo {
+ /**
+ * A high quality fingerprint image was detected, no further user interaction is necessary.
+ */
+ GOOD,
+
+ /**
+ * Not enough of a fingerprint was detected. Reposition the finger, or a longer swipe needed.
+ */
+ PARTIAL,
+
+ /**
+ * Image doesn't contain enough detail for recognition.
+ */
+ INSUFFICIENT,
+
+ /**
+ * The sensor needs to be cleaned.
+ */
+ SENSOR_DIRTY,
+
+ /**
+ * For swipe-type sensors, the swipe was too slow and not enough data was collected.
+ */
+ TOO_SLOW,
+
+ /**
+ * For swipe-type sensors, the swipe was too fast and not enough data was collected.
+ */
+ TOO_FAST,
+
+ /**
+ * Vendor-specific acquisition message. See ISessionCallback#onAcquired vendorCode
+ * documentation.
+ */
+ VENDOR,
+
+ /**
+ * This message represents the earliest message sent at the beginning of the authentication
+ * pipeline. It is expected to be used to measure latency. For example, in a camera-based
+ * authentication system it's expected to be sent prior to camera initialization. Note this
+ * should be sent whenever authentication is started or restarted. The framework may measure
+ * latency based on the time between the last START message and the onAuthenticated callback.
+ */
+ START,
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
new file mode 100644
index 0000000..4fe7f5f
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum Error {
+ /**
+ * Used for testing, and to keep subsequent numbering consistent with older HIDLs.
+ */
+ // NO_ERROR = 0,
+
+ /**
+ * A hardware error has occurred that cannot be resolved. For example, I2C failure or a broken
+ * sensor.
+ */
+ HW_UNAVAILABLE = 1,
+
+ /**
+ * The implementation is unable to process the request. For example, invalid arguments were
+ * supplied.
+ */
+ UNABLE_TO_PROCESS = 2,
+
+ /**
+ * The current operation took too long to complete.
+ */
+ TIMEOUT = 3,
+
+ /**
+ * No space available to store additional enrollments.
+ */
+ NO_SPACE = 4,
+
+ /**
+ * The operation was canceled. See common::ICancellationSignal.
+ */
+ CANCELED = 5,
+
+ /**
+ * The implementation was unable to remove an enrollment.
+ * See ISession#removeEnrollments.
+ */
+ UNABLE_TO_REMOVE = 6,
+
+ /**
+ * Reserved to maintain backwards compatibility. See ISessionCallback#onLockoutTimed instead.
+ */
+ // LOCKOUT = 7,
+
+ /**
+ * Used to enable vendor-specific error messages.
+ */
+ VENDOR = 8,
+
+ /**
+ * Reserved to maintain backwards compatibility. See ISessionCallback#onLockoutPermanent
+ * instead.
+ */
+ // LOCKOUT_PERMANENT = 9,
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
new file mode 100644
index 0000000..765a2ed
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.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.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum FingerprintSensorType {
+ UNKNOWN,
+ REAR,
+ UNDER_DISPLAY_ULTRASONIC,
+ UNDER_DISPLAY_OPTICAL,
+ POWER_BUTTON,
+ HOME_BUTTON
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
new file mode 100644
index 0000000..3675aa4
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.biometrics.fingerprint.ISessionCallback;
+import android.hardware.biometrics.fingerprint.SensorProps;
+
+@VintfStability
+interface IFingerprint {
+ /**
+ * getSensorProps:
+ *
+ * @return A list of properties for all sensors that an instance of the HAL supports.
+ */
+ SensorProps[] getSensorProps();
+
+ /**
+ * createSession:
+ *
+ * Creates a session which can then be used by the framework to perform operations such as
+ * enroll, authenticate, etc for the given sensorId and userId.
+ *
+ * A physical sensor identified by sensorId typically supports only a single in-flight session
+ * at a time. As such, if a session is currently in a state other than SessionState::IDLING, the
+ * HAL MUST finish or cancel the current operation and return to SessionState::IDLING before the
+ * new session is created. For example:
+ * 1) If a session for sensorId=0, userId=0 is currently in a cancellable state (see
+ * ICancellationSignal) such as SessionState::AUTHENTICATING and the framework requests a
+ * new session for sensorId=0, userId=10, the HAL must end the current session with
+ * Error::CANCELED, invoke ISessionCallback#onStateChanged with SessionState::IDLING, and
+ * then return a new session for sensorId=0, userId=10.
+ * 2) If a session for sensorId=0, userId=0 is currently in a non-cancellable state such as
+ * SessionState::REMOVING_ENROLLMENTS, and the framework requests a new session for
+ * sensorId=0, userId=10, the HAL must finish the current operation before invoking
+ * ISessionCallback#onStateChanged with SessionState::IDLING, and return a new session for
+ * sensorId=0, userId=10.
+ *
+ * Implementations must store user-specific state or metadata in /data/vendor_de/<user>/fpdata
+ * as specified by the SeLinux policy. This directory is created/removed by vold (see
+ * vold_prepare_subdirs.cpp). Implementations may store additional user-specific data, such as
+ * embeddings or templates in StrongBox.
+ *
+ * @param sensorId The sensor with which this session is being created.
+ * @param userId The userId with which this session is being created.
+ * @param cb Used to notify the framework.
+ * @return A new session
+ */
+ ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
new file mode 100644
index 0000000..da767be
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -0,0 +1,429 @@
+/*
+ * 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.biometrics.fingerprint;
+
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.keymaster.HardwareAuthToken;
+
+/**
+ * Operations that can be performed for unique sessions retrieved via IFingerprint#createSession.
+ * Methods defined within this interface can be split into the following categories:
+ * 1) Methods associated with a state (see the SessionState enum). State-based operations are
+ * handled by the HAL in FIFO order.
+ * 1a) Cancellable state-based operations. If a cancellable operation is in-progress and the
+ * framework requests a subsequent state-based operation, the implementation should finish
+ * the operation via ISessionCallback#onError with Error::CANCELED.
+ * 1b) Non-cancellable state-based operations. These operations should fully complete before the
+ * next state-based operation can be started.
+ * 2) Methods without a state. These methods may be invoked by the framework depending on its
+ * use case. For example on devices with sensors of FingerprintSensorType::UNDER_DISPLAY_*,
+ * ISession#onFingerDown may be invoked while the HAL is in SessionState::ENROLLING,
+ * SessionState::AUTHENTICATING, or SessionState::DETECTING_INTERACTION.
+ *
+ * If the HAL has multiple operations in its queue, it is not required to notify the framework
+ * of SessionState::IDLING between each operation. However, it must notify the framework when all
+ * work is completed. See ISessionCallback#onStateChanged. For example, the following is a valid
+ * sequence of ISessionCallback#onStateChanged invocations: SessionState::IDLING -->
+ * SessionState::ENROLLING --> SessionState::ENUMERATING_ENROLLMENTS --> SessionState::IDLING.
+ */
+@VintfStability
+interface ISession {
+ /**
+ * Methods applicable to any fingerprint type.
+ */
+
+ /**
+ * generateChallenge:
+ *
+ * Begins a secure transaction request. Note that the challenge by itself is not useful. It only
+ * becomes useful when wrapped in a verifiable message such as a HardwareAuthToken.
+ *
+ * Canonical example:
+ * 1) User requests an operation, such as fingerprint enrollment.
+ * 2) Fingerprint enrollment cannot happen until the user confirms their lockscreen credential
+ * (PIN/Pattern/Password).
+ * 3) However, the biometric subsystem does not want just "any" proof of credential
+ * confirmation. It needs proof that the user explicitly authenticated credential in order
+ * to allow addition of biometric enrollments.
+ * To secure this path, the following path is taken:
+ * 1) Upon user requesting fingerprint enroll, the framework requests
+ * IFingerprint#generateChallenge
+ * 2) Framework sends the challenge to the credential subsystem, and upon credential
+ * confirmation, a HAT is created, containing the challenge in the "challenge" field.
+ * 3) Framework sends the HAT to the HAL, e.g. ISession#enroll.
+ * 4) Implementation verifies the authenticity and integrity of the HAT.
+ * 5) Implementation now has confidence that the user entered their credential to allow
+ * biometric enrollment.
+ *
+ * Note that the interface allows multiple in-flight challenges. For example, invoking
+ * generateChallenge(0, 0, timeoutSec, cb) twice does not invalidate the first challenge. The
+ * challenge is invalidated only when:
+ * 1) The provided timeout expires, or
+ * 2) IFingerprint#revokeChallenge is invoked
+ *
+ * For example, the following is a possible table of valid challenges:
+ * ----------------------------------------------
+ * | SensorId | UserId | ValidUntil | Challenge |
+ * |----------|--------|------------|-----------|
+ * | 0 | 0 | <Time1> | <Random1> |
+ * | 0 | 0 | <Time2> | <Random2> |
+ * | 1 | 0 | <Time3> | <Random3> |
+ * | 0 | 10 | <Time4> | <Random4> |
+ * ----------------------------------------------
+ *
+ * @param cookie A unique number identifying this operation
+ * @param timeoutSec Duration for which the challenge is valid for
+ */
+ void generateChallenge(in int cookie, in int timeoutSec);
+
+ /**
+ * revokeChallenge:
+ *
+ * Revokes a challenge that was previously generated. Note that if an invalid combination of
+ * parameters is requested, the implementation must still notify the framework using the
+ * provided callback.
+ *
+ * @param cookie A unique number identifying this operation
+ * @param challenge Challenge that should be revoked.
+ */
+ void revokeChallenge(in int cookie, in long challenge);
+
+ /**
+ * enroll:
+ *
+ * A request to add a fingerprint enrollment.
+ *
+ * Once the HAL is able to start processing the enrollment request, it must notify the framework
+ * via ISessionCallback#onStateChanged with SessionState::ENROLLING.
+ *
+ * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
+ * framework via ISessionCallback#onError with the applicable enrollment-specific error, and
+ * then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent
+ * operation is in the queue.
+ *
+ * Before capturing fingerprint data, the implementation must first verify the authenticity and
+ * integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
+ * within the provided HardwareAuthToken is valid. See IFingerprint#generateChallenge. If any of
+ * the above checks fail, the framework must be notified via ISessionCallback#onError and the
+ * HAL must notify the framework when it returns to the idle state. See
+ * Error::UNABLE_TO_PROCESS.
+ *
+ * During enrollment, the implementation may notify the framework via
+ * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
+ * can be invoked multiple times if necessary. Similarly, the framework may be notified of
+ * enrollment progress changes via ISessionCallback#onEnrollmentProgress. Once the framework is
+ * notified that there are 0 "remaining" steps, the framework may cache the "enrollmentId". See
+ * ISessionCallback#onEnrollmentProgress for more info. The HAL must notify the framework once
+ * it returns to the idle state.
+ *
+ * When a finger is successfully added and before the framework is notified of remaining=0, the
+ * implementation MUST update and associate this (sensorId, userId) pair with a new new
+ * entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
+ *
+ * @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 See above documentation.
+ */
+ ICancellationSignal enroll(in int cookie, in HardwareAuthToken hat);
+
+ /**
+ * authenticate:
+ *
+ * A request to start looking for fingerprints to authenticate.
+ *
+ * Once the HAL is able to start processing the authentication request, it must notify framework
+ * via ISessionCallback#onStateChanged with SessionState::AUTHENTICATING.
+ *
+ * At any point during authentication, if a non-recoverable error occurs, the HAL must notify
+ * the framework via ISessionCallback#onError with the applicable authentication-specific error,
+ * and then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no
+ * subsequent operation is in the queue.
+ *
+ * During authentication, the implementation may notify the framework via
+ * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
+ * can be invoked multiple times if necessary.
+ *
+ * The HAL must notify the framework of accepts/rejects via ISessionCallback#onAuthentication*.
+ *
+ * The authentication lifecycle ends when either
+ * 1) A fingerprint is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked, or
+ * 2) Any non-recoverable error occurs (such as lockout). See the full list of
+ * authentication-specific errors in the Error enum.
+ *
+ * Note that upon successful authentication, the lockout counter for this (sensorId, userId)
+ * pair must be cleared.
+ *
+ * Note that upon successful authentication, ONLY sensors configured as SensorStrength::STRONG
+ * are allowed to create and send a HardwareAuthToken to the framework. See the Android CDD for
+ * more details. For SensorStrength::STRONG sensors, the HardwareAuthToken's "challenge" field
+ * must be set with the operationId passed in during #authenticate. If the sensor is NOT
+ * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
+ *
+ * @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 operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
+ * upon successful authentication and wrapped in the HardwareAuthToken's
+ * "challenge" field and sent to the framework via
+ * ISessionCallback#onAuthenticated. The operationId is an opaque identifier
+ * created from a separate secure subsystem such as, but not limited to
+ * KeyStore/KeyMaster. The HardwareAuthToken can then be used as an
+ * attestation for the provided operation. For example, this is used
+ * to unlock biometric-bound auth-per-use keys (see
+ * setUserAuthenticationParameters in KeyGenParameterSpec.Builder and
+ * KeyProtection.Builder.
+ */
+ ICancellationSignal authenticate(in int cookie, in long operationId);
+
+ /**
+ * detectInteraction:
+ *
+ * A request to start looking for fingerprints without performing matching.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::DETECTING_INTERACTION.
+ *
+ * The framework will use this method in cases where determing user presence is required, but
+ * identifying/authentication is not. For example, when the device is encrypted (first boot) or
+ * in lockdown mode.
+ *
+ * At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
+ * the framework via ISessionCallback#onError with the applicable error, and then send
+ * ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent operation is
+ * in the queue.
+ *
+ * The implementation must only check for a fingerprint-like image was detected (e.g. to
+ * minimize interactions due to non-fingerprint objects), and the lockout counter must not
+ * be modified.
+ *
+ * Upon detecting any fingerprint, the implementation must invoke
+ * ISessionCallback#onInteractionDetected.
+ *
+ * The lifecycle of this operation ends when either
+ * 1) Any fingerprint is detected and the framework is notified via
+ * ISessionCallback#onInteractiondetected
+ * 2) The operation was cancelled by the framework (see ICancellationSignal)
+ * 3) The HAL ends the operation, for example when a subsequent operation pre-empts this one.
+ *
+ * Note that if the operation is canceled, the implementation must notify the framework via
+ * ISessionCallback#onError with Error::CANCELED.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ */
+ ICancellationSignal detectInteraction(in int cookie);
+
+ /*
+ * enumerateEnrollments:
+ *
+ * A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
+ * framework typically uses this to ensure that its cache is in sync with the HAL.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::ENUMERATING_ENROLLMENTS.
+ *
+ * The implementation must then notify the framework with a list of enrollments applicable
+ * for the current session via ISessionCallback#onEnrollmentsEnumerated.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ */
+ void enumerateEnrollments(in int cookie);
+
+ /**
+ * removeEnrollments:
+ *
+ * A request to remove the enrollments for this (sensorId, userId) pair.
+ *
+ * Once the HAL is able to start processing this request, it must notify the framework via
+ * ISessionCallback#onStateChanged with SessionState::REMOVING_ENROLLMENTS.
+ *
+ * After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
+ * etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path.
+ * The framework will guarantee that it is unique per ISession.
+ */
+ void removeEnrollments(in int cookie, in int[] enrollmentIds);
+
+ /**
+ * getAuthenticatorId:
+ *
+ * MUST return 0 via ISessionCallback#onAuthenticatorIdRetrieved for sensors that are configured
+ * as SensorStrength::WEAK or SensorStrength::CONVENIENCE.
+ *
+ * The following only applies to sensors that are configured as SensorStrength::STRONG.
+ *
+ * The authenticatorId is a (sensorId, user)-specific identifier which can be used during key
+ * generation and key import to to associate a key (in KeyStore / KeyMaster) with the current
+ * set of enrolled fingerprints. For example, the following public Android APIs allow for keys
+ * to be invalidated when the user adds a new enrollment after the key was created:
+ * KeyGenParameterSpec.Builder.setInvalidatedByBiometricEnrollment and
+ * KeyProtection.Builder.setInvalidatedByBiometricEnrollment.
+ *
+ * In addition, upon successful fingerprint authentication, the signed HAT that is returned to
+ * the framework via ISessionCallback#onAuthenticated must contain this identifier in the
+ * authenticatorId field.
+ *
+ * Returns an entropy-encoded random identifier associated with the current set of enrollments
+ * via ISessionCallback#onAuthenticatorIdRetrieved. The authenticatorId
+ * 1) MUST change whenever a new fingerprint is enrolled
+ * 2) MUST return 0 if no fingerprints are enrolled
+ * 3) MUST not change if a fingerprint is deleted.
+ * 4) MUST be an entropy-encoded random number
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path. The
+ * client must guarantee that it is unique per ISession.
+ */
+ void getAuthenticatorId(in int cookie);
+
+ /**
+ * invalidateAuthenticatorId:
+ *
+ * This method only applies to sensors that are configured as SensorStrength::STRONG. If invoked
+ * by the framework for sensor of other strengths, the HAL should immediately invoke
+ * ISessionCallback#onAuthenticatorIdInvalidated.
+ *
+ * The following only applies to sensors that are configured as SensorStrength::STRONG.
+ *
+ * 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
+ * ISessionCallback#onAuthenticatorInvalidated
+ *
+ * A practical use case of invalidation would be when the user adds a new enrollment to a sensor
+ * managed by a different HAL instance. The public android.security.keystore APIs bind keys to
+ * "all biometrics" rather than "fingerprint-only" or "face-only" (see #getAuthenticatorId
+ * for more details). As such, the framework would coordinate invalidation across multiple
+ * biometric HALs as necessary.
+ *
+ * @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);
+
+ /**
+ * resetLockout:
+ *
+ * Requests the implementation to clear the lockout counter. Upon receiving this request, the
+ * implementation must perform the following:
+ * 1) Verify the authenticity and integrity of the provided HAT
+ * 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
+ * order of minutes, not hours).
+ * If either of the checks fail, the HAL must invoke ISessionCallback#onError with
+ * Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in the
+ * queue.
+ *
+ * Upon successful verification, the HAL must clear the lockout counter and notify the framework
+ * via ISessionCallback#onLockoutCleared.
+ *
+ * Note that lockout is user AND sensor specific. In other words, there is a separate lockout
+ * state for each (user, sensor) pair. For example, the following is a valid state on a
+ * multi-sensor device:
+ * ------------------------------------------------------------------
+ * | SensorId | UserId | FailedAttempts | LockedOut | LockedUntil |
+ * |----------|--------|----------------|-----------|---------------|
+ * | 0 | 0 | 1 | false | x |
+ * | 1 | 0 | 5 | true | <future_time> |
+ * | 0 | 10 | 0 | false | x |
+ * | 1 | 10 | 0 | false | x |
+ * ------------------------------------------------------------------
+ *
+ * Lockout may be cleared in the following ways:
+ * 1) ISession#resetLockout
+ * 2) After a period of time, according to a rate-limiter.
+ *
+ * Note that the "FailedAttempts" counter must be cleared upon successful fingerprint
+ * authentication. For example, if SensorId=0 UserId=0 FailedAttempts=1, and a successful
+ * fingerprint authentication occurs, the counter for that (SensorId, UserId) pair must be reset
+ * to 0.
+ *
+ * In addition, lockout states MUST persist after device reboots, HAL crashes, etc.
+ *
+ * See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
+ * requirements.
+ *
+ * @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 See above documentation.
+ */
+ void resetLockout(in int cookie, in HardwareAuthToken hat);
+
+ /**
+ * Methods for notifying the under-display fingerprint sensor about external events.
+ */
+
+ /**
+ * onPointerDown:
+ *
+ * This method only applies to sensors that are configured as
+ * FingerprintSensorType::UNDER_DISPLAY_*. If invoked erroneously by the framework for sensors
+ * of other types, the HAL must treat this as a no-op and return immediately.
+ *
+ * For sensors of type FingerprintSensorType::UNDER_DISPLAY_*, this method is used to notify the
+ * HAL of display touches. This method can be invoked when the session is in one of the
+ * following states: SessionState::ENROLLING, SessionState::AUTHENTICATING, or
+ * SessionState::DETECTING_INTERACTION.
+ *
+ * Note that the framework will only invoke this method if the event occurred on the display on
+ * which this sensor is located.
+ *
+ * Note that for sensors which require illumination such as
+ * FingerprintSensorType::UNDER_DISPLAY_OPTICAL, and where illumination is handled below the
+ * framework, this is a good time to start illuminating.
+ *
+ * @param pointerId See android.view.MotionEvent#getPointerId
+ * @param x The distance in pixels from the left edge of the display.
+ * @param y The distance in pixels from the top edge of the display.
+ * @param minor See android.view.MotionEvent#getTouchMinor
+ * @param major See android.view.MotionEvent#getTouchMajor
+ */
+ void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
+
+ /**
+ * onPointerUp:
+ *
+ * This method only applies to sensors that are configured as
+ * FingerprintSensorType::UNDER_DISPLAY_*. If invoked for sensors of other types, the HAL must
+ * treat this as a no-op and return immediately.
+ *
+ * @param pointerId See android.view.MotionEvent#getPointerId
+ */
+ void onPointerUp(in int pointerId);
+
+ /*
+ * onUiReady:
+ *
+ * This method only applies to sensors that are configured as
+ * FingerprintSensorType::UNDER_DISPLAY_OPTICAL. If invoked for sensors of other types, the HAL
+ * must treat this as a no-op and return immediately.
+ *
+ * For FingerprintSensorType::UNDER_DISPLAY_OPTICAL where illumination is handled above the
+ * HAL, the framework will invoke this method to notify that the illumination has started.
+ */
+ void onUiReady();
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
new file mode 100644
index 0000000..4387f98
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.biometrics.fingerprint.Error;
+import android.hardware.biometrics.fingerprint.SessionState;
+import android.hardware.keymaster.HardwareAuthToken;
+
+@VintfStability
+interface ISessionCallback {
+ /**
+ * Used to notify the framework of session state changes. See ISession for more information.
+ */
+ void onStateChanged(in int cookie, in SessionState state);
+
+ /**
+ * Notifies the framework when a challenge is successfully generated.
+ */
+ void onChallengeGenerated(in long challenge);
+
+ /**
+ * Notifies the framework when a challenge has been revoked.
+ */
+ void onChallengeRevoked(in long challenge);
+
+ /**
+ * This method must only be used to notify the framework during the following states:
+ * 1) SessionState::ENROLLING
+ * 2) SessionState::AUTHENTICATING
+ * 3) SessionState::DETECTING_INTERACTION
+ *
+ * These messages may be used to provide user guidance multiple times if necessary per
+ * operation.
+ *
+ * @param info See the AcquiredInfo enum.
+ * @param vendorCode Only valid if info == AcquiredInfo::VENDOR. The vendorCode must be used to
+ * index into the configuration
+ * com.android.internal.R.array.fingerprint_acquired_vendor that's installed
+ * on the vendor partition.
+ */
+ void onAcquired(in AcquiredInfo info, in int vendorCode);
+
+ /**
+ * This method must only be used to notify the framework during the following states:
+ * 1) SessionState::ENROLLING
+ * 2) SessionState::AUTHENTICATING
+ * 3) SessionState::DETECTING_INTERACTION
+ * 4) SessionState::INVALIDATING_AUTHENTICATOR_ID
+ * 5) SessionState::RESETTING_LOCKOUT
+ *
+ * These messages may be used to notify the framework or user that a non-recoverable error
+ * has occurred. The operation is finished, and the HAL must proceed with the next operation
+ * or return to SessionState::IDLING if the queue is empty.
+ *
+ * Note that cancellation (see common::ICancellationSignal) and preemption most be followed with
+ * an Error::CANCELED message.
+ *
+ * @param error See the Error enum.
+ * @param vendorCode Only valid if error == Error::VENDOR. The vendorCode must be used to index
+ * into the configuration
+ * com.android.internal.R.fingerprint_error_vendor that's installed on the
+ * vendor partition.
+ */
+ void onError(in Error error, in int vendorCode);
+
+ /**
+ * This method must only be used to notify the framework during the following state:
+ * 1) SessionState::ENROLLING
+ *
+ * @param enrollmentId Unique stable identifier for the enrollment that's being added by this
+ * ISession#enroll invocation.
+ * @param remaining Remaining number of steps before enrollment is complete.
+ */
+ void onEnrollmentProgress(in int enrollmentId, int remaining);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Used to notify the framework upon successful authentication. Note that the authentication
+ * lifecycle ends when either 1) a fingerprint is accepted, or 2) an error occurred. The
+ * authentication lifecycle does NOT end when a fingerprint is rejected.
+ *
+ * @param enrollmentId Fingerprint that was accepted.
+ * @param hat If the sensor is configured as SensorStrength::STRONG, a non-null attestation that
+ * a fingerprint was accepted. The HardwareAuthToken's "challenge" field must be set
+ * with the operationId passed in during ISession#authenticate. If the sensor is NOT
+ * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
+ */
+ void onAuthenticationSucceeded(in int enrollmentId, in HardwareAuthToken hat);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Used to notify the framework upon rejected attempts. Note that the authentication
+ * lifecycle ends when either 1) a fingerprint is accepted, or 2) an occurred. The
+ * authentication lifecycle does NOT end when a fingerprint is rejected.
+ */
+ void onAuthenticationFailed();
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Authentication is locked out due to too many unsuccessful attempts. This is a rate-limiting
+ * lockout, and authentication can be restarted after a period of time. See
+ * ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ * @param durationMillis Remaining duration of the lockout.
+ */
+ void onLockoutTimed(in long durationMillis);
+
+ /**
+ * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+ *
+ * Authentication is disabled until the user unlocks with their device credential
+ * (PIN/Pattern/Password). See ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ */
+ void onLockoutPermanent();
+
+ /**
+ * Notifies the framework that lockout has been cleared for this (sensorId, userId) pair.
+ *
+ * Note that this method can be used to notify the framework during any state.
+ *
+ * Lockout can be cleared in the following scenarios:
+ * 1) A timed lockout has ended (e.g. durationMillis specified in previous #onLockoutTimed
+ * has expired.
+ * 2) See ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user's lockout is cleared.
+ * @param userId User for the sensor's lockout is cleared.
+ */
+ void onLockoutCleared();
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::DETECTING_INTERACTION
+ *
+ * Notifies the framework that user interaction occurred. See ISession#detectInteraction.
+ */
+ void onInteractionDetected();
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::ENUMERATING_ENROLLMENTS.
+ *
+ * Notifies the framework of the current enrollments. See ISession#enumerateEnrollments.
+ *
+ * @param enrollmentIds A list of enrollments for the session's (userId, sensorId) pair.
+ */
+ void onEnrollmentsEnumerated(in int[] enrollmentIds);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::REMOVING_ENROLLMENTS.
+ *
+ * Notifies the framework that the specified enrollments are removed.
+ *
+ * @param enrollmentIds The enrollments that were removed.
+ */
+ void onEnrollmentsRemoved(in int[] enrollmentIds);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::GETTING_AUTHENTICATOR_ID.
+ *
+ * Notifies the framework with the authenticatorId corresponding to this session's
+ * (userId, sensorId) pair.
+ *
+ * @param authenticatorId See the above documentation.
+ */
+ void onAuthenticatorIdRetrieved(in long authenticatorId);
+
+ /**
+ * This method must only be used to notify the framework during
+ * SessionState::INVALIDATING_AUTHENTICATOR_ID.
+ *
+ * See ISession#invalidateAuthenticatorId for more information.
+ */
+ void onAuthenticatorIdInvalidated();
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
new file mode 100644
index 0000000..ab70a58
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.fingerprint.FingerprintSensorType;
+
+@VintfStability
+parcelable SensorProps {
+ /**
+ * Statically configured properties that apply to this fingerprint sensor.
+ */
+ CommonProps commonProps;
+
+ /**
+ * A statically configured sensor type representing this fingerprint sensor.
+ */
+ FingerprintSensorType sensorType;
+
+ /**
+ * Must be set to true for sensors that support "swipe" gestures via
+ * android.view.KeyEvent#KEYCODE_SYSTEM_NAVIGATION_*.
+ */
+ boolean supportsNavigationGestures;
+
+ /**
+ * The location of the center of the sensor if applicable. For example, sensors of
+ * FingerprintSensorType::UNDER_DISPLAY_* would report this value as the distance in pixels,
+ * measured from the left edge of the screen.
+ */
+ int sensorLocationX;
+
+ /**
+ * The location of the center of the sensor if applicable. For example, sensors of
+ * FingerprintSensorType::UNDER_DISPLAY_* would report this value as the distance in pixels,
+ * measured from the top edge of the screen.
+ */
+ int sensorLocationY;
+
+ /**
+ * The radius of the sensor if applicable. For example, sensors of
+ * FingerprintSensorType::UNDER_DISPLAY_* would report this value as the radius of the sensor,
+ * in pixels.
+ */
+ int sensorRadius;
+
+ /**
+ * For sensors of FingerprintSensorType::UNDER_DISPLAY_*, this must correspond to the
+ * android.hardware.DisplayManager#getDisplay Android API.
+ */
+ int displayId;
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
new file mode 100644
index 0000000..1de01ad
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
@@ -0,0 +1,77 @@
+/*
+ * 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.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum SessionState {
+ /**
+ * The HAL is not processing any session requests.
+ */
+ IDLING,
+
+ /**
+ * The HAL is processing the ISession#generateChallenge request.
+ */
+ GENERATING_CHALLENGE,
+
+ /**
+ * The HAL is processing the ISession#revokeChallenge request.
+ */
+ REVOKING_CHALLENGE,
+
+ /**
+ * The HAL is processing the ISession#enroll request.
+ */
+ ENROLLING,
+
+ /**
+ * The HAL is processing the ISession#authenticate request.
+ */
+ AUTHENTICATING,
+
+ /**
+ * The HAL is processing the ISession#detectInteraction request.
+ */
+ DETECTING_INTERACTION,
+
+ /**
+ * The HAL is processing the ISession#enumerateEnrollments request.
+ */
+ ENUMERATING_ENROLLMENTS,
+
+ /**
+ * The HAL is processing the ISession#removeEnrollments request.
+ */
+ REMOVING_ENROLLMENTS,
+
+ /**
+ * The HAL is processing the ISession#getAuthenticatorId request.
+ */
+ GETTING_AUTHENTICATOR_ID,
+
+ /**
+ * The HAL is processing the ISession#invalidateAuthenticatorId request.
+ */
+ INVALIDATING_AUTHENTICATOR_ID,
+
+ /**
+ * The HAL is processing the ISession#resetLockout request.
+ */
+ RESETTING_LOCKOUT
+}
+
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
new file mode 100644
index 0000000..ce1ff59
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+ name: "android.hardware.biometrics.fingerprint-service.example",
+ relative_install_path: "hw",
+ init_rc: ["fingerprint-default.rc"],
+ vintf_fragments: ["fingerprint-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.biometrics.fingerprint-ndk_platform",
+ "android.hardware.biometrics.common-unstable-ndk_platform",
+ ],
+ srcs: [
+ "main.cpp",
+ "Fingerprint.cpp",
+ "Session.cpp",
+ ],
+}
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
new file mode 100644
index 0000000..18ce0c8
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -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.
+ */
+
+#include "Fingerprint.h"
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+const int kSensorId = 0;
+const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
+const int kMaxEnrollmentsPerUser = 5;
+const FingerprintSensorType kSensorType = FingerprintSensorType::REAR;
+const bool kSupportsNavigationGestures = true;
+const std::string kHwDeviceName = "fingerprintSensor";
+const std::string kHardwareVersion = "vendor/model/revision";
+const std::string kFirmwareVersion = "1.01";
+const std::string kSerialNumber = "00000001";
+
+ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* return_val) {
+ *return_val = std::vector<SensorProps>();
+
+ std::vector<common::HardwareInfo> hardwareInfos = std::vector<common::HardwareInfo>();
+ common::HardwareInfo sensorInfo = {kHwDeviceName,
+ kHardwareVersion,
+ kFirmwareVersion,
+ kSerialNumber
+ };
+ hardwareInfos.push_back(sensorInfo);
+ common::CommonProps commonProps = {kSensorId,
+ kSensorStrength,
+ kMaxEnrollmentsPerUser,
+ hardwareInfos};
+ SensorProps props = {commonProps,
+ kSensorType,
+ kSupportsNavigationGestures,
+ 0 /* sensorLocationX */,
+ 0 /* sensorLocationY */,
+ 0 /* sensorRadius */,
+ 0 /* displayId */};
+ return_val->push_back(props);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
+ const std::shared_ptr<ISessionCallback>& cb,
+ std::shared_ptr<ISession>* return_val) {
+ *return_val = SharedRefBase::make<Session>(cb);
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.h b/biometrics/fingerprint/aidl/default/Fingerprint.h
new file mode 100644
index 0000000..4e952ba
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class Fingerprint : public BnFingerprint {
+ public:
+ ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
+
+ ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
+ const std::shared_ptr<ISessionCallback>& cb,
+ std::shared_ptr<ISession>* _aidl_return) override;
+};
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
new file mode 100644
index 0000000..96f1e56
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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/android/hardware/biometrics/common/BnCancellationSignal.h>
+
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class CancellationSignal : public common::BnCancellationSignal {
+ public:
+ ndk::ScopedAStatus cancel() override { 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*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t /*challenge*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::enroll(int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
+ std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
+ std::shared_ptr<common::ICancellationSignal>* return_val) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::AUTHENTICATING);
+ }
+ *return_val = SharedRefBase::make<CancellationSignal>();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::detectInteraction(
+ int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
+ cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
+ }
+ 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>());
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
+ if (cb_) {
+ cb_->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
+ cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/,
+ const keymaster::HardwareAuthToken& /*hat*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
+ const keymaster::HardwareAuthToken& /*hat*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onPointerDown(int32_t /*pointerId*/, int32_t /*x*/, int32_t /*y*/,
+ float /*minor*/, float /*major*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onPointerUp(int32_t /*pointerId*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onUiReady() {
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.h b/biometrics/fingerprint/aidl/default/Session.h
new file mode 100644
index 0000000..05c570c
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Session.h
@@ -0,0 +1,69 @@
+/*
+ * 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/biometrics/fingerprint/BnSession.h>
+#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+namespace common = aidl::android::hardware::biometrics::common;
+namespace keymaster = aidl::android::hardware::keymaster;
+
+class Session : public BnSession {
+ public:
+ explicit Session(std::shared_ptr<ISessionCallback> cb);
+
+ ndk::ScopedAStatus generateChallenge(int32_t cookie, int32_t timeoutSec) override;
+
+ ndk::ScopedAStatus revokeChallenge(int32_t cookie, int64_t challenge) override;
+
+ ndk::ScopedAStatus enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
+ std::shared_ptr<common::ICancellationSignal>* return_val) override;
+
+ ndk::ScopedAStatus authenticate(
+ int32_t cookie, int64_t keystoreOperationId,
+ std::shared_ptr<common::ICancellationSignal>* return_val) override;
+
+ ndk::ScopedAStatus detectInteraction(
+ int32_t cookie, std::shared_ptr<common::ICancellationSignal>* return_val) override;
+
+ ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
+
+ ndk::ScopedAStatus removeEnrollments(int32_t cookie,
+ const std::vector<int32_t>& enrollmentIds) override;
+
+ ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
+
+ ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie,
+ const keymaster::HardwareAuthToken& hat) override;
+
+ ndk::ScopedAStatus resetLockout(int32_t cookie,
+ const keymaster::HardwareAuthToken& hat) override;
+
+ ndk::ScopedAStatus onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
+ float major) override;
+
+ ndk::ScopedAStatus onPointerUp(int32_t pointerId) override;
+
+ ndk::ScopedAStatus onUiReady() override;
+
+ private:
+ std::shared_ptr<ISessionCallback> cb_;
+};
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.rc b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
new file mode 100644
index 0000000..eb62c56
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
@@ -0,0 +1,5 @@
+service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.example
+ class hal
+ user nobody
+ group nobody
+
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.xml b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
new file mode 100644
index 0000000..89da765
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.biometrics.fingerprint</name>
+ <fqname>IFingerprint/default</fqname>
+ </hal>
+</manifest>
diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp
new file mode 100644
index 0000000..4690d73
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/main.cpp
@@ -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.
+ */
+
+#include "Fingerprint.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::biometrics::fingerprint::Fingerprint;
+
+int main() {
+ LOG(INFO) << "Fingerprint HAL started";
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Fingerprint> hal = ndk::SharedRefBase::make<Fingerprint>();
+
+ const std::string instance = std::string(Fingerprint::descriptor) + "/default";
+ binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
new file mode 100644
index 0000000..b441eb3
--- /dev/null
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+ name: "VtsHalBiometricsFingerprintTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ "android.hardware.biometrics.fingerprint-ndk_platform",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
new file mode 100644
index 0000000..adb98ac
--- /dev/null
+++ b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <future>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+namespace {
+
+constexpr int kSensorId = 0;
+constexpr int kUserId = 0;
+constexpr auto kCallbackTimeout = std::chrono::seconds(1);
+
+enum class SessionCallbackMethodName {
+ kOnStateChanged,
+};
+
+struct SessionCallbackInvocation {
+ SessionCallbackMethodName method_name;
+ SessionState state;
+};
+
+class SessionCallback : public BnSessionCallback {
+ public:
+ explicit SessionCallback(std::promise<SessionCallbackInvocation> invocation_promise)
+ : invocation_promise_(std::move(invocation_promise)) {}
+
+ ndk::ScopedAStatus onStateChanged(int32_t /*cookie*/, SessionState state) override {
+ SessionCallbackInvocation invocation = {};
+ invocation.method_name = SessionCallbackMethodName::kOnStateChanged;
+ invocation.state = state;
+ invocation_promise_.set_value(invocation);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onError(Error /*error*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
+ int32_t /*remaining*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
+ const keymaster::HardwareAuthToken& /*hat*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticationFailed() override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onLockoutTimed(int64_t /*durationMillis*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onLockoutPermanent() override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onLockoutCleared() override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus onEnrollmentsEnumerated(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onEnrollmentsRemoved(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus onAuthenticatorIdInvalidated() override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ private:
+ std::promise<SessionCallbackInvocation> invocation_promise_;
+};
+
+class Fingerprint : public testing::TestWithParam<std::string> {
+ protected:
+ void SetUp() override {
+ AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+ ASSERT_NE(binder, nullptr);
+ hal_ = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
+ }
+
+ std::shared_ptr<IFingerprint> hal_;
+};
+
+TEST_P(Fingerprint, AuthenticateTest) {
+ std::promise<SessionCallbackInvocation> invocation_promise;
+ std::future<SessionCallbackInvocation> invocation_future = invocation_promise.get_future();
+ std::shared_ptr<SessionCallback> session_cb =
+ ndk::SharedRefBase::make<SessionCallback>(std::move(invocation_promise));
+
+ std::shared_ptr<ISession> session;
+ ASSERT_TRUE(hal_->createSession(kSensorId, kUserId, session_cb, &session).isOk());
+
+ std::shared_ptr<common::ICancellationSignal> cancel_cb;
+ ASSERT_TRUE(session->authenticate(0, 0, &cancel_cb).isOk());
+ ASSERT_EQ(invocation_future.wait_for(kCallbackTimeout), std::future_status::ready);
+
+ SessionCallbackInvocation invocation = invocation_future.get();
+ EXPECT_EQ(invocation.method_name, SessionCallbackMethodName::kOnStateChanged);
+ EXPECT_EQ(invocation.state, SessionState::AUTHENTICATING);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);
+INSTANTIATE_TEST_SUITE_P(
+ IFingerprint, Fingerprint,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IFingerprint::descriptor)),
+ ::android::PrintInstanceNameToString);
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 44eccd3..aa5c48f 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -7587,6 +7587,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, CameraHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index 802dce1..f9977ff 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -12,6 +12,8 @@
"TypeConvert.cpp",
],
+ compile_multilib: "32",
+
shared_libs: [
"android.hardware.cas@1.0",
"android.hardware.cas.native@1.0",
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 0f16de5..7f5d988 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -837,6 +837,7 @@
} // anonymous namespace
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, MediaCasHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp
index dc42a42..66a1eb8 100644
--- a/cas/1.1/default/Android.bp
+++ b/cas/1.1/default/Android.bp
@@ -12,6 +12,8 @@
"TypeConvert.cpp",
],
+ compile_multilib: "32",
+
shared_libs: [
"android.hardware.cas@1.0",
"android.hardware.cas@1.1",
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 1b5797b..b657f07 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -549,6 +549,7 @@
} // anonymous namespace
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, MediaCasHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp
index 94d5b3d..9e53148 100644
--- a/cas/1.2/default/Android.bp
+++ b/cas/1.2/default/Android.bp
@@ -12,6 +12,8 @@
"TypeConvert.cpp",
],
+ compile_multilib: "32",
+
shared_libs: [
"android.hardware.cas@1.0",
"android.hardware.cas@1.1",
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
index 58e0f2e..f436b8b 100644
--- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -597,6 +597,7 @@
} // anonymous namespace
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, MediaCasHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index ea8d6ad..d1d254b 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -96,14 +96,28 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.biometrics.face</name>
+ <interface>
+ <name>IFace</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.biometrics.fingerprint</name>
- <version>2.1-2</version>
+ <version>2.1-3</version>
<interface>
<name>IBiometricsFingerprint</name>
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.biometrics.fingerprint</name>
+ <interface>
+ <name>IFingerprint</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.bluetooth</name>
<version>1.0-1</version>
@@ -170,7 +184,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.contexthub</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IContexthub</name>
<instance>default</instance>
@@ -207,6 +221,14 @@
<hal format="hidl" optional="true">
<name>android.hardware.gnss</name>
<version>2.0-1</version>
+ <version>3.0</version>
+ <interface>
+ <name>IGnss</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.gnss</name>
<interface>
<name>IGnss</name>
<instance>default</instance>
@@ -365,9 +387,8 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.power.stats</name>
- <version>1.0</version>
<interface>
<name>IPowerStats</name>
<instance>default</instance>
@@ -486,7 +507,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.tv.tuner</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>ITuner</name>
<instance>default</instance>
@@ -533,7 +554,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
- <version>1.3-4</version>
+ <version>1.3-5</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
@@ -541,7 +562,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.hostapd</name>
- <version>1.0-2</version>
+ <version>1.0-3</version>
<interface>
<name>IHostapd</name>
<instance>default</instance>
@@ -549,7 +570,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
- <version>1.2-3</version>
+ <version>1.2-4</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 849df94..6725a98 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -51,6 +51,7 @@
"android.hardware.media.bufferpool@2.0",
"android.hardware.radio.config@1.2",
// AIDL
+ "android.hardware.biometrics.common",
"android.hardware.common",
"android.hardware.common.fmq",
"android.hardware.graphics.common",
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 161b2f0..1a33a9e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -5,4 +5,3 @@
#VTS team
dshi@google.com
-trong@google.com
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index ada232b..8a90173 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -261,9 +261,11 @@
EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubTxnTest);
INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/contexthub/1.1/default/Android.bp b/contexthub/1.1/default/Android.bp
index 86858c0..5c9ec4e 100644
--- a/contexthub/1.1/default/Android.bp
+++ b/contexthub/1.1/default/Android.bp
@@ -38,5 +38,8 @@
"liblog",
"libutils",
],
+ header_libs: [
+ "android.hardware.contexthub@1.X-common-impl",
+ ],
vintf_fragments: ["android.hardware.contexthub@1.1.xml"],
}
diff --git a/contexthub/1.1/default/Contexthub.cpp b/contexthub/1.1/default/Contexthub.cpp
index 19cc262..e7fde84 100644
--- a/contexthub/1.1/default/Contexthub.cpp
+++ b/contexthub/1.1/default/Contexthub.cpp
@@ -23,81 +23,6 @@
namespace V1_1 {
namespace implementation {
-using ::android::hardware::contexthub::V1_0::ContextHub;
-using ::android::hardware::contexthub::V1_0::HubAppInfo;
-using ::android::hardware::contexthub::V1_0::Result;
-
-namespace {
-
-constexpr uint32_t kMockHubId = 0;
-
-} // anonymous namespace
-
-Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
- ContextHub hub = {};
- hub.name = "Mock Context Hub";
- hub.vendor = "AOSP";
- hub.toolchain = "n/a";
- hub.platformVersion = 1;
- hub.toolchainVersion = 1;
- hub.hubId = kMockHubId;
- hub.peakMips = 1;
- hub.peakPowerDrawMw = 1;
- hub.maxSupportedMsgLen = 4096;
- hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
- hub.chreApiMajorVersion = 1;
- hub.chreApiMinorVersion = 4;
-
- // Report a single mock hub
- std::vector<ContextHub> hubs;
- hubs.push_back(hub);
-
- _hidl_cb(hubs);
- return Void();
-}
-
-Return<Result> Contexthub::registerCallback(uint32_t hubId, const sp<IContexthubCallback>& cb) {
- if (hubId == kMockHubId) {
- mCallback = cb;
- return Result::OK;
- }
- return Result::BAD_PARAMS;
-}
-
-// We don't expose any nanoapps, therefore all nanoapp-related API calls return with BAD_PARAMS
-Return<Result> Contexthub::sendMessageToHub(uint32_t /*hubId*/, const ContextHubMsg& /*msg*/) {
- return Result::BAD_PARAMS;
-}
-
-Return<Result> Contexthub::loadNanoApp(uint32_t /*hubId*/, const NanoAppBinary& /*appBinary*/,
- uint32_t /*transactionId*/) {
- return Result::BAD_PARAMS;
-}
-
-Return<Result> Contexthub::unloadNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
- uint32_t /*transactionId*/) {
- return Result::BAD_PARAMS;
-}
-
-Return<Result> Contexthub::enableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
- uint32_t /*transactionId*/) {
- return Result::BAD_PARAMS;
-}
-
-Return<Result> Contexthub::disableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
- uint32_t /*transactionId*/) {
- return Result::BAD_PARAMS;
-}
-
-Return<Result> Contexthub::queryApps(uint32_t hubId) {
- if (hubId == kMockHubId && mCallback != nullptr) {
- std::vector<HubAppInfo> nanoapps;
- mCallback->handleAppsInfo(nanoapps);
- return Result::OK;
- }
- return Result::BAD_PARAMS;
-}
-
Return<void> Contexthub::onSettingChanged(Setting /*setting*/, SettingValue /*newValue*/) {
return Void();
}
diff --git a/contexthub/1.1/default/Contexthub.h b/contexthub/1.1/default/Contexthub.h
index 0da61d1..1468fcf 100644
--- a/contexthub/1.1/default/Contexthub.h
+++ b/contexthub/1.1/default/Contexthub.h
@@ -15,6 +15,8 @@
*/
#pragma once
+#include "ContextHub.h"
+
#include <android/hardware/contexthub/1.1/IContexthub.h>
namespace android {
@@ -23,30 +25,11 @@
namespace V1_1 {
namespace implementation {
-class Contexthub : public V1_1::IContexthub {
- using ContextHubMsg = ::android::hardware::contexthub::V1_0::ContextHubMsg;
- using IContexthubCallback = ::android::hardware::contexthub::V1_0::IContexthubCallback;
- using NanoAppBinary = ::android::hardware::contexthub::V1_0::NanoAppBinary;
- using Result = ::android::hardware::contexthub::V1_0::Result;
-
+class Contexthub
+ : public ::android::hardware::contexthub::V1_X::implementation::ContextHub<IContexthub> {
public:
- // Methods from V1_0::IContexthub
- Return<void> getHubs(getHubs_cb _hidl_cb) override;
- Return<Result> registerCallback(uint32_t hubId,
- const ::android::sp<IContexthubCallback>& cb) override;
- Return<Result> sendMessageToHub(uint32_t hubId, const ContextHubMsg& msg) override;
- Return<Result> loadNanoApp(uint32_t hubId, const NanoAppBinary& appBinary,
- uint32_t transactionId) override;
- Return<Result> unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
- Return<Result> enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
- Return<Result> disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
- Return<Result> queryApps(uint32_t hubId) override;
-
// Methods from V1_1::IContexthub
Return<void> onSettingChanged(Setting setting, SettingValue newValue) override;
-
- private:
- sp<IContexthubCallback> mCallback;
};
} // namespace implementation
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
index 161b2f0..1a33a9e 100644
--- a/contexthub/1.1/vts/functional/OWNERS
+++ b/contexthub/1.1/vts/functional/OWNERS
@@ -5,4 +5,3 @@
#VTS team
dshi@google.com
-trong@google.com
diff --git a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
index f2fcdfc..5f1dad9 100644
--- a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
+++ b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
@@ -54,6 +54,7 @@
ASSERT_OK(registerCallback(nullptr));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/contexthub/1.2/Android.bp b/contexthub/1.2/Android.bp
new file mode 100644
index 0000000..e819482
--- /dev/null
+++ b/contexthub/1.2/Android.bp
@@ -0,0 +1,16 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.contexthub@1.2",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IContexthub.hal",
+ ],
+ interfaces: [
+ "android.hardware.contexthub@1.0",
+ "android.hardware.contexthub@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/contexthub/1.2/IContexthub.hal b/contexthub/1.2/IContexthub.hal
new file mode 100644
index 0000000..819fc1d
--- /dev/null
+++ b/contexthub/1.2/IContexthub.hal
@@ -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.contexthub@1.2;
+
+import @1.1::IContexthub;
+import @1.1::SettingValue;
+
+interface IContexthub extends @1.1::IContexthub {
+ /**
+ * Notification sent by the framework to indicate that the user
+ * has changed a setting.
+ *
+ * @param setting User setting that has been modified.
+ * @param newValue The update value of the user setting.
+ */
+ onSettingChanged_1_2(Setting setting, @1.1::SettingValue newValue);
+};
diff --git a/contexthub/1.2/default/Android.bp b/contexthub/1.2/default/Android.bp
new file mode 100644
index 0000000..49b54fc
--- /dev/null
+++ b/contexthub/1.2/default/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * 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.contexthub@1.2-service.mock",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.contexthub@1.2-service.rc"],
+ srcs: [
+ "Contexthub.cpp",
+ "service.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "android.hardware.contexthub@1.0",
+ "android.hardware.contexthub@1.1",
+ "android.hardware.contexthub@1.2",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ header_libs: [
+ "android.hardware.contexthub@1.X-common-impl",
+ ],
+ vintf_fragments: ["android.hardware.contexthub@1.2.xml"],
+}
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.h b/contexthub/1.2/default/Contexthub.cpp
similarity index 62%
copy from wifi/1.4/default/wifi_legacy_hal_stubs.h
copy to contexthub/1.2/default/Contexthub.cpp
index 577a545..d7ac7bf 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.h
+++ b/contexthub/1.2/default/Contexthub.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.
@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "Contexthub.h"
-#ifndef WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
+#include <vector>
namespace android {
namespace hardware {
-namespace wifi {
-namespace V1_4 {
+namespace contexthub {
+namespace V1_2 {
namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-} // namespace legacy_hal
+Return<void> Contexthub::onSettingChanged(SettingV1_1 /*setting*/, SettingValue /*newValue*/) {
+ return Void();
+}
+
+Return<void> Contexthub::onSettingChanged_1_2(Setting /*setting*/, SettingValue /*newValue*/) {
+ return Void();
+}
+
} // namespace implementation
-} // namespace V1_4
-} // namespace wifi
+} // namespace V1_2
+} // namespace contexthub
} // namespace hardware
} // namespace android
-
-#endif // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/contexthub/1.2/default/Contexthub.h b/contexthub/1.2/default/Contexthub.h
new file mode 100644
index 0000000..d2f8d69
--- /dev/null
+++ b/contexthub/1.2/default/Contexthub.h
@@ -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.
+ */
+#pragma once
+
+#include "ContextHub.h"
+
+#include <android/hardware/contexthub/1.2/IContexthub.h>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_2 {
+namespace implementation {
+
+class Contexthub
+ : public ::android::hardware::contexthub::V1_X::implementation::ContextHub<IContexthub> {
+ using SettingValue = ::android::hardware::contexthub::V1_1::SettingValue;
+ using SettingV1_1 = ::android::hardware::contexthub::V1_1::Setting;
+
+ public:
+ // Methods from V1_1::IContexthub
+ Return<void> onSettingChanged(SettingV1_1 setting, SettingValue newValue) override;
+
+ // Methods from V1_2::IContexthub
+ Return<void> onSettingChanged_1_2(Setting setting, SettingValue newValue) override;
+};
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace contexthub
+} // namespace hardware
+} // namespace android
diff --git a/contexthub/1.2/default/OWNERS b/contexthub/1.2/default/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/contexthub/1.2/default/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/contexthub/1.2/default/android.hardware.contexthub@1.2-service.rc b/contexthub/1.2/default/android.hardware.contexthub@1.2-service.rc
new file mode 100644
index 0000000..936222a
--- /dev/null
+++ b/contexthub/1.2/default/android.hardware.contexthub@1.2-service.rc
@@ -0,0 +1,7 @@
+service vendor.contexthub-hal-1.2-mock /vendor/bin/hw/android.hardware.contexthub@1.2-service.mock
+ interface android.hardware.contexthub@1.0::IContexthub default
+ interface android.hardware.contexthub@1.1::IContexthub default
+ interface android.hardware.contexthub@1.2::IContexthub default
+ class hal
+ user context_hub
+ group context_hub
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/contexthub/1.2/default/android.hardware.contexthub@1.2.xml
similarity index 63%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to contexthub/1.2/default/android.hardware.contexthub@1.2.xml
index b5d25cd..ec6c684 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/contexthub/1.2/default/android.hardware.contexthub@1.2.xml
@@ -1,10 +1,10 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.wifi</name>
+ <name>android.hardware.contexthub</name>
<transport>hwbinder</transport>
- <version>1.4</version>
+ <version>1.2</version>
<interface>
- <name>IWifi</name>
+ <name>IContexthub</name>
<instance>default</instance>
</interface>
</hal>
diff --git a/contexthub/1.2/default/service.cpp b/contexthub/1.2/default/service.cpp
new file mode 100644
index 0000000..41cb753
--- /dev/null
+++ b/contexthub/1.2/default/service.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.
+ */
+
+#define LOG_TAG "android.hardware.contexthub@1.2-service"
+
+#include <android/hardware/contexthub/1.2/IContexthub.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "Contexthub.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::contexthub::V1_2::IContexthub;
+using ::android::hardware::contexthub::V1_2::implementation::Contexthub;
+
+int main() {
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ ::android::sp<IContexthub> contexthub = new Contexthub();
+ if (contexthub->registerAsService() != ::android::OK) {
+ ALOGE("Failed to register Contexthub HAL instance");
+ return 1;
+ }
+
+ joinRpcThreadpool();
+ ALOGE("Service exited");
+ return 1;
+}
diff --git a/contexthub/1.2/types.hal b/contexthub/1.2/types.hal
new file mode 100644
index 0000000..38f9f7a
--- /dev/null
+++ b/contexthub/1.2/types.hal
@@ -0,0 +1,34 @@
+/*
+ * 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.contexthub@1.2;
+
+import @1.1::Setting;
+
+/**
+ * Used to indicate the type of user setting that has changed.
+ */
+enum Setting : @1.1::Setting {
+ /**
+ * Indicates that the WiFi capabilities can be used in CHRE. This setting
+ * follows the overall availability of WiFi-related functionality within
+ * the Android framework, for example if WiFi is disabled for connectivity
+ * purposes but is enabled for location purposes (scanning), then
+ * WIFI_AVAILABLE is enabled.
+ */
+ WIFI_AVAILABLE,
+ AIRPLANE_MODE,
+};
diff --git a/contexthub/1.2/vts/functional/Android.bp b/contexthub/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..6e425be
--- /dev/null
+++ b/contexthub/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: "VtsHalContexthubV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalContexthubV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.contexthub@1.0",
+ "android.hardware.contexthub@1.1",
+ "android.hardware.contexthub@1.2",
+ "VtsHalContexthubUtils",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..1a33a9e
--- /dev/null
+++ b/contexthub/1.2/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+#Context Hub team
+arthuri@google.com
+bduddie@google.com
+stange@google.com
+
+#VTS team
+dshi@google.com
diff --git a/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
new file mode 100644
index 0000000..77883c2
--- /dev/null
+++ b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "contexthub_hidl_hal_test"
+
+#include "ContexthubCallbackBase.h"
+#include "ContexthubHidlTestBase.h"
+#include "VtsHalContexthubUtils.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <android/hardware/contexthub/1.1/IContexthub.h>
+#include <android/hardware/contexthub/1.2/IContexthub.h>
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <cinttypes>
+
+using ::android::hardware::contexthub::V1_1::SettingValue;
+using ::android::hardware::contexthub::V1_2::IContexthub;
+using ::android::hardware::contexthub::V1_2::Setting;
+using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase;
+using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
+using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
+
+namespace {
+
+const std::vector<std::tuple<std::string, std::string>> kTestParameters =
+ getHalAndHubIdList<IContexthub>();
+
+class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
+
+// In VTS, we only test that sending the values doesn't cause things to blow up - other test
+// suites verify the expected E2E behavior in CHRE
+TEST_P(ContexthubHidlTest, TestOnWifiSettingChanged) {
+ ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+ hubApi->onSettingChanged_1_2(Setting::WIFI_AVAILABLE, SettingValue::DISABLED);
+ hubApi->onSettingChanged_1_2(Setting::WIFI_AVAILABLE, SettingValue::ENABLED);
+ ASSERT_OK(registerCallback(nullptr));
+}
+
+TEST_P(ContexthubHidlTest, TestOnAirplaneModeSettingChanged) {
+ ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+ hubApi->onSettingChanged_1_2(Setting::AIRPLANE_MODE, SettingValue::DISABLED);
+ hubApi->onSettingChanged_1_2(Setting::AIRPLANE_MODE, SettingValue::ENABLED);
+ ASSERT_OK(registerCallback(nullptr));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+} // anonymous namespace
diff --git a/contexthub/common/default/1.X/Android.bp b/contexthub/common/default/1.X/Android.bp
new file mode 100644
index 0000000..691a1b7
--- /dev/null
+++ b/contexthub/common/default/1.X/Android.bp
@@ -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.
+
+cc_library_headers {
+ name: "android.hardware.contexthub@1.X-common-impl",
+ vendor_available: true,
+ defaults: ["hidl_defaults"],
+ export_include_dirs: ["."],
+ shared_libs: [
+ "android.hardware.contexthub@1.0",
+ "libbinder",
+ "libcutils",
+ "libhidlbase",
+ "libutils",
+ ],
+}
diff --git a/contexthub/common/default/1.X/ContextHub.h b/contexthub/common/default/1.X/ContextHub.h
new file mode 100644
index 0000000..73d0631
--- /dev/null
+++ b/contexthub/common/default/1.X/ContextHub.h
@@ -0,0 +1,117 @@
+/*
+ * 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_CONTEXTHUB_V1_X_CONTEXTHUB_H
+#define ANDROID_HARDWARE_CONTEXTHUB_V1_X_CONTEXTHUB_H
+
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <android/hardware/contexthub/1.0/types.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_X {
+namespace implementation {
+
+template <class IContextHubInterface>
+struct ContextHub : public IContextHubInterface {
+ using ContextHubMsg = ::android::hardware::contexthub::V1_0::ContextHubMsg;
+ using HubAppInfo = ::android::hardware::contexthub::V1_0::HubAppInfo;
+ using IContexthubCallback = ::android::hardware::contexthub::V1_0::IContexthubCallback;
+ using NanoAppBinary = ::android::hardware::contexthub::V1_0::NanoAppBinary;
+ using Result = ::android::hardware::contexthub::V1_0::Result;
+ using getHubs_cb = ::android::hardware::contexthub::V1_0::IContexthub::getHubs_cb;
+
+ public:
+ Return<void> getHubs(getHubs_cb _hidl_cb) override {
+ ::android::hardware::contexthub::V1_0::ContextHub hub = {};
+ hub.name = "Mock Context Hub";
+ hub.vendor = "AOSP";
+ hub.toolchain = "n/a";
+ hub.platformVersion = 1;
+ hub.toolchainVersion = 1;
+ hub.hubId = kMockHubId;
+ hub.peakMips = 1;
+ hub.peakPowerDrawMw = 1;
+ hub.maxSupportedMsgLen = 4096;
+ hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
+ hub.chreApiMajorVersion = 1;
+ hub.chreApiMinorVersion = 4;
+
+ // Report a single mock hub
+ std::vector<::android::hardware::contexthub::V1_0::ContextHub> hubs;
+ hubs.push_back(hub);
+
+ _hidl_cb(hubs);
+ return Void();
+ }
+
+ Return<Result> registerCallback(uint32_t hubId, const sp<IContexthubCallback>& cb) override {
+ if (hubId == kMockHubId) {
+ mCallback = cb;
+ return Result::OK;
+ }
+ return Result::BAD_PARAMS;
+ }
+
+ // We don't expose any nanoapps, therefore all nanoapp-related API calls return with BAD_PARAMS
+ Return<Result> sendMessageToHub(uint32_t /*hubId*/, const ContextHubMsg& /*msg*/) override {
+ return Result::BAD_PARAMS;
+ }
+
+ Return<Result> loadNanoApp(uint32_t /*hubId*/, const NanoAppBinary& /*appBinary*/,
+ uint32_t /*transactionId*/) override {
+ return Result::BAD_PARAMS;
+ }
+
+ Return<Result> unloadNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+ uint32_t /*transactionId*/) override {
+ return Result::BAD_PARAMS;
+ }
+
+ Return<Result> enableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+ uint32_t /*transactionId*/) override {
+ return Result::BAD_PARAMS;
+ }
+
+ Return<Result> disableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+ uint32_t /*transactionId*/) override {
+ return Result::BAD_PARAMS;
+ }
+
+ Return<Result> queryApps(uint32_t hubId) override {
+ if (hubId == kMockHubId && mCallback != nullptr) {
+ std::vector<HubAppInfo> nanoapps;
+ mCallback->handleAppsInfo(nanoapps);
+ return Result::OK;
+ }
+ return Result::BAD_PARAMS;
+ }
+
+ private:
+ static constexpr uint32_t kMockHubId = 0;
+
+ sp<IContexthubCallback> mCallback;
+};
+
+} // namespace implementation
+} // namespace V1_X
+} // namespace contexthub
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CONTEXTHUB_V1_X_CONTEXTHUB_H
diff --git a/current.txt b/current.txt
index d10adca..d8ca42c 100644
--- a/current.txt
+++ b/current.txt
@@ -772,7 +772,11 @@
9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
7da2707d4cf93818eaf8038eb65e2180116a399c310e594a00935c5c981aa340 android.hardware.radio@1.0::types
+38d65fb20c60a5b823298560fc0825457ecdc49603a4b4e94bf81511790737da android.hardware.radio@1.4::types
+954c334efd80e8869b66d1ce5fe2755712d96ba4b3c38d415739c330af5fb4cb android.hardware.radio@1.5::types
# HALs released in Android S
# NOTE: waiting to freeze HALs until later in the release
# NOTE: new HALs are recommended to be in AIDL
+6e64b33f1b720b66b0deb5e08dee37a99deaa94e2e9ebf7806703cabab56e21d android.hardware.contexthub@1.2::IContexthub
+3fb83f4539cab2c7bf9fdbecf7265d1c1dd6e8de9694046fe512b493c127ccea android.hardware.contexthub@1.2::types
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
index b8f64c0..8abba69 100644
--- a/drm/1.3/vts/functional/drm_hal_test_main.cpp
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -94,27 +94,34 @@
testing::ValuesIn(kAllInstances),
drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyFactoryTest);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
testing::ValuesIn(kAllInstances),
drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyPluginTest);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
testing::ValuesIn(kAllInstances),
drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyDecryptTest);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
testing::ValuesIn(kAllInstances),
drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyTest);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
testing::ValuesIn(kAllInstances),
PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalTest);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
testing::ValuesIn(kAllInstances),
PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyTestV1_2);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
testing::ValuesIn(kAllInstances),
PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalTestV1_3);
INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
testing::ValuesIn(kAllInstances),
PrintParamInstanceToString);
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
index 1bef663..dac43e3 100644
--- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -321,6 +321,7 @@
DisableVerboseLogging();
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateHidl1_1GeneralTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, DumpstateHidl1_1GeneralTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
@@ -334,6 +335,7 @@
"_" + toString(std::get<1>(info.param));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateHidl1_1PerModeTest);
INSTANTIATE_TEST_SUITE_P(
PerInstanceAndMode, DumpstateHidl1_1PerModeTest,
testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/gnss/1.1/default/GnssDebug.cpp b/gnss/1.1/default/GnssDebug.cpp
index 471ed24..252f4e6 100644
--- a/gnss/1.1/default/GnssDebug.cpp
+++ b/gnss/1.1/default/GnssDebug.cpp
@@ -20,6 +20,7 @@
#include "Constants.h"
#include "GnssDebug.h"
+#include "MockLocation.h"
using namespace ::android::hardware::gnss::common;
@@ -32,17 +33,17 @@
// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
Return<void> GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) {
PositionDebug positionDebug = {
- .valid = true,
- .latitudeDegrees = kMockLatitudeDegrees,
- .longitudeDegrees = kMockLongitudeDegrees,
- .altitudeMeters = kMockAltitudeMeters,
- .speedMetersPerSec = kMockSpeedMetersPerSec,
- .bearingDegrees = kMockBearingDegrees,
- .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
- .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
- .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
- .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
- .ageSeconds = 0.99};
+ .valid = true,
+ .latitudeDegrees = gMockLatitudeDegrees,
+ .longitudeDegrees = gMockLongitudeDegrees,
+ .altitudeMeters = gMockAltitudeMeters,
+ .speedMetersPerSec = kMockSpeedMetersPerSec,
+ .bearingDegrees = kMockBearingDegrees,
+ .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
+ .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
+ .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
+ .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
+ .ageSeconds = 0.99};
TimeDebug timeDebug = {.timeEstimate = kMockTimestamp,
.timeUncertaintyNs = 1000,
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index 4a0a7f9..e33ff58 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -23,6 +23,7 @@
using android::hardware::gnss::V1_1::IGnss;
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GnssHalTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index 2c74fa3..54f5652 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -23,6 +23,7 @@
using android::hardware::gnss::V2_0::IGnss;
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GnssHalTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index c4dc8fd..7739f90 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -21,12 +21,6 @@
vendor: true,
vintf_fragments: ["android.hardware.gnss@2.1-service.xml"],
srcs: [
- "Gnss.cpp",
- "GnssAntennaInfo.cpp",
- "GnssDebug.cpp",
- "GnssMeasurement.cpp",
- "GnssMeasurementCorrections.cpp",
- "GnssConfiguration.cpp",
"service.cpp",
],
shared_libs: [
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
deleted file mode 100644
index 2b327a9..0000000
--- a/gnss/2.1/default/Gnss.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "Gnss"
-
-#include "Gnss.h"
-#include "GnssAntennaInfo.h"
-#include "GnssDebug.h"
-#include "GnssMeasurement.h"
-#include "GnssMeasurementCorrections.h"
-#include "Utils.h"
-
-#include <log/log.h>
-
-using ::android::hardware::gnss::common::Utils;
-using ::android::hardware::gnss::measurement_corrections::V1_1::implementation::
- GnssMeasurementCorrections;
-
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
-
-sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
-sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
-sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
-sp<V1_0::IGnssCallback> Gnss::sGnssCallback_1_0 = nullptr;
-
-Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
-
-Gnss::~Gnss() {
- stop();
-}
-
-Return<bool> Gnss::start() {
- ALOGD("start");
- if (mIsActive) {
- ALOGW("Gnss has started. Restarting...");
- stop();
- }
-
- mIsActive = true;
- mThread = std::thread([this]() {
- while (mIsActive == true) {
- auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
- this->reportSvStatus(svStatus);
-
- if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
- const auto location = Utils::getMockLocationV2_0();
- this->reportLocation(location);
- } else {
- const auto location = Utils::getMockLocationV1_0();
- this->reportLocation(location);
- }
-
- std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
- }
- });
- return true;
-}
-
-hidl_vec<GnssSvInfo> Gnss::filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList) {
- for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
- if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
- gnssSvInfoList[i].v2_0.v1_0.svFlag &=
- ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
- }
- }
- return gnssSvInfoList;
-}
-
-Return<bool> Gnss::stop() {
- ALOGD("stop");
- mIsActive = false;
- if (mThread.joinable()) {
- mThread.join();
- }
- return true;
-}
-
-// Methods from V1_0::IGnss follow.
-Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
- if (callback == nullptr) {
- ALOGE("%s: Null callback ignored", __func__);
- return false;
- }
-
- sGnssCallback_1_0 = callback;
-
- uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
- V1_0::IGnssCallback::Capabilities::SCHEDULING;
- auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
-
- ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- return true;
-}
-
-Return<void> Gnss::cleanup() {
- sGnssCallback_2_1 = nullptr;
- sGnssCallback_2_0 = nullptr;
- return Void();
-}
-
-Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) {
- return true;
-}
-
-Return<bool> Gnss::injectLocation(double, double, float) {
- return true;
-}
-
-Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) {
- // TODO implement
- return Void();
-}
-
-Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode,
- V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
- uint32_t, uint32_t) {
- mMinIntervalMs = minIntervalMs;
- return true;
-}
-
-Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
- // TODO implement
- return ::android::sp<V1_0::IAGnssRil>{};
-}
-
-Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
- // TODO implement
- return ::android::sp<V1_0::IGnssGeofencing>{};
-}
-
-Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
- // TODO implement
- return ::android::sp<V1_0::IAGnss>{};
-}
-
-Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
- // TODO implement
- return ::android::sp<V1_0::IGnssNi>{};
-}
-
-Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
- ALOGD("Gnss::getExtensionGnssMeasurement");
- return new GnssMeasurement();
-}
-
-Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
- // TODO implement
- return ::android::sp<V1_0::IGnssNavigationMessage>{};
-}
-
-Return<sp<V1_0::IGnssXtra>> Gnss::getExtensionXtra() {
- // TODO implement
- return ::android::sp<V1_0::IGnssXtra>{};
-}
-
-Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
- // TODO implement
- return ::android::sp<V1_0::IGnssConfiguration>{};
-}
-
-Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
- return new V1_1::implementation::GnssDebug();
-}
-
-Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
- // TODO implement
- return ::android::sp<V1_0::IGnssBatching>{};
-}
-
-// Methods from V1_1::IGnss follow.
-Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
- if (callback == nullptr) {
- ALOGE("%s: Null callback ignored", __func__);
- return false;
- }
-
- sGnssCallback_1_1 = callback;
-
- uint32_t capabilities = 0x0;
- auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
-
- ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- auto gnssName = "Google Mock GNSS Implementation v2.1";
- ret = sGnssCallback_1_1->gnssNameCb(gnssName);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- return true;
-}
-
-Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
- V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
- uint32_t, uint32_t, bool) {
- mMinIntervalMs = minIntervalMs;
- return true;
-}
-
-Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
- // TODO implement
- return ::android::sp<V1_1::IGnssConfiguration>{};
-}
-
-Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
- // TODO implement
- return ::android::sp<V1_1::IGnssMeasurement>{};
-}
-
-Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) {
- return true;
-}
-
-// Methods from V2_0::IGnss follow.
-Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
- ALOGD("Gnss::setCallback_2_0");
- if (callback == nullptr) {
- ALOGE("%s: Null callback ignored", __func__);
- return false;
- }
-
- sGnssCallback_2_0 = callback;
-
- using Capabilities = V2_0::IGnssCallback::Capabilities;
- const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
- Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
- auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
-
- ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- auto gnssName = "Google Mock GNSS Implementation v2.1";
- ret = sGnssCallback_2_0->gnssNameCb(gnssName);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- return true;
-}
-
-Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
- ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
- return mGnssConfiguration;
-}
-
-Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IGnssDebug>{};
-}
-
-Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IAGnss>{};
-}
-
-Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IAGnssRil>{};
-}
-
-Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
- ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
- return new GnssMeasurement();
-}
-
-Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
-Gnss::getExtensionMeasurementCorrections() {
- ALOGD("Gnss::getExtensionMeasurementCorrections()");
- return new GnssMeasurementCorrections();
-}
-
-Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
- // TODO implement
- return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
-}
-
-Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IGnssBatching>{};
-}
-
-Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
- // TODO(b/124012850): Implement function.
- return bool{};
-}
-
-// Methods from V2_1::IGnss follow.
-Return<bool> Gnss::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
- ALOGD("Gnss::setCallback_2_1");
- if (callback == nullptr) {
- ALOGE("%s: Null callback ignored", __func__);
- return false;
- }
-
- sGnssCallback_2_1 = callback;
-
- using Capabilities = V2_1::IGnssCallback::Capabilities;
- const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
- Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST |
- Capabilities::ANTENNA_INFO;
- auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
-
- ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- auto gnssName = "Android Mock GNSS Implementation v2.1";
- ret = sGnssCallback_2_1->gnssNameCb(gnssName);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-
- return true;
-}
-
-Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
- ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
- return new GnssMeasurement();
-}
-
-Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
- ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
- return mGnssConfiguration;
-}
-
-Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
-Gnss::getExtensionMeasurementCorrections_1_1() {
- ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
- return new GnssMeasurementCorrections();
-}
-
-Return<sp<V2_1::IGnssAntennaInfo>> Gnss::getExtensionGnssAntennaInfo() {
- ALOGD("Gnss::getExtensionGnssAntennaInfo");
- return new GnssAntennaInfo();
-}
-
-void Gnss::reportSvStatus(const hidl_vec<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) {
- ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
- return;
- }
- auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
- }
-}
-
-void Gnss::reportLocation(const V1_0::GnssLocation& location) const {
- std::unique_lock<std::mutex> lock(mMutex);
- if (sGnssCallback_1_1 != nullptr) {
- auto ret = sGnssCallback_1_1->gnssLocationCb(location);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback v1.1", __func__);
- }
- return;
- }
- if (sGnssCallback_1_0 == nullptr) {
- ALOGE("%s: No non-null callback", __func__);
- return;
- }
- auto ret = sGnssCallback_1_0->gnssLocationCb(location);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback v1.0", __func__);
- }
-}
-
-void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
- std::unique_lock<std::mutex> lock(mMutex);
- if (sGnssCallback_2_1 != nullptr) {
- auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback v2.1", __func__);
- }
- return;
- }
- if (sGnssCallback_2_0 == nullptr) {
- ALOGE("%s: No non-null callback", __func__);
- return;
- }
- auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
- if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback v2.0", __func__);
- }
-}
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
deleted file mode 100644
index bd5e6e8..0000000
--- a/gnss/2.1/default/Gnss.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <android/hardware/gnss/2.1/IGnss.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <atomic>
-#include <mutex>
-#include <thread>
-#include "GnssAntennaInfo.h"
-#include "GnssConfiguration.h"
-
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-
-using GnssSvInfo = IGnssCallback::GnssSvInfo;
-
-namespace implementation {
-
-struct Gnss : public IGnss {
- Gnss();
- ~Gnss();
- // Methods from V1_0::IGnss follow.
- Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
- Return<bool> start() override;
- Return<bool> stop() override;
- Return<void> cleanup() override;
- Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
- int32_t uncertaintyMs) override;
- Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
- float accuracyMeters) override;
- Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
- Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
- V1_0::IGnss::GnssPositionRecurrence recurrence,
- uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
- uint32_t preferredTimeMs) override;
- Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
- Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
- Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
- Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
- Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
- Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
- Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
- Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
- Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
- Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
-
- // Methods from V1_1::IGnss follow.
- Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
- Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
- V1_0::IGnss::GnssPositionRecurrence recurrence,
- uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
- uint32_t preferredTimeMs, bool lowPowerMode) override;
- Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
- Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
- Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
-
- // Methods from V2_0::IGnss follow.
- Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
- Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
- Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
- Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
- Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
- Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
- Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
- getExtensionMeasurementCorrections() override;
- Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
- override;
- Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
- Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
-
- // Methods from V2_1::IGnss follow.
- Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
- Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
- Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
- Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
- getExtensionMeasurementCorrections_1_1() override;
- Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
-
- private:
- void reportLocation(const V2_0::GnssLocation&) const;
- void reportLocation(const V1_0::GnssLocation&) const;
- void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
-
- static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
- static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
- static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
- static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
- std::atomic<long> mMinIntervalMs;
- sp<GnssConfiguration> mGnssConfiguration;
- std::atomic<bool> mIsActive;
- std::thread mThread;
- mutable std::mutex mMutex;
- hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
-};
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
diff --git a/gnss/2.1/default/service.cpp b/gnss/2.1/default/service.cpp
index 5e004d5..4f282cf 100644
--- a/gnss/2.1/default/service.cpp
+++ b/gnss/2.1/default/service.cpp
@@ -18,17 +18,17 @@
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
-#include "Gnss.h"
+#include "v2_1/GnssTemplate.h"
using ::android::OK;
using ::android::sp;
using ::android::hardware::configureRpcThreadpool;
using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::common::implementation::GnssTemplate;
using ::android::hardware::gnss::V2_1::IGnss;
-using ::android::hardware::gnss::V2_1::implementation::Gnss;
int main(int /* argc */, char* /* argv */[]) {
- sp<IGnss> gnss = new Gnss();
+ sp<IGnss> gnss = new GnssTemplate<IGnss>();
configureRpcThreadpool(1, true /* will join */);
if (gnss->registerAsService() != OK) {
ALOGE("Could not register gnss 2.1 service.");
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index b3051d4..175bc75 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -18,7 +18,6 @@
name: "VtsHalGnssV2_1TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
- "gnss_hal_test.cpp",
"gnss_hal_test_cases.cpp",
"VtsHalGnssV2_1TargetTest.cpp",
],
diff --git a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
index e61d885..89a9781 100644
--- a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
+++ b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
@@ -23,6 +23,7 @@
using android::hardware::gnss::V2_1::IGnss;
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GnssHalTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
deleted file mode 100644
index da7a62b..0000000
--- a/gnss/2.1/vts/functional/gnss_hal_test.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "GnssHalTest"
-
-#include <gnss_hal_test.h>
-#include <chrono>
-#include "Utils.h"
-
-#include <gtest/gtest.h>
-
-using ::android::hardware::gnss::common::Utils;
-
-// Implementations for the main test class for GNSS HAL
-void GnssHalTest::SetUp() {
- gnss_hal_ = IGnss::getService(GetParam());
- ASSERT_NE(gnss_hal_, nullptr);
-
- SetUpGnssCallback();
-}
-
-void GnssHalTest::TearDown() {
- if (gnss_hal_ != nullptr) {
- gnss_hal_->cleanup();
- gnss_hal_ = nullptr;
- }
-
- // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
- gnss_cb_ = nullptr;
-}
-
-void GnssHalTest::SetUpGnssCallback() {
- gnss_cb_ = new GnssCallback();
- ASSERT_NE(gnss_cb_, nullptr);
-
- auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
- if (!result.isOk()) {
- ALOGE("result of failed setCallback %s", result.description().c_str());
- }
-
- ASSERT_TRUE(result.isOk());
- ASSERT_TRUE(result);
-
- /*
- * All capabilities, name and systemInfo callbacks should trigger
- */
- EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
- EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
- EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
-
- EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
- EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
- EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
-}
-
-void GnssHalTest::StopAndClearLocations() {
- const auto result = gnss_hal_->stop();
-
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(result);
-
- /*
- * Clear notify/waiting counter, allowing up till the timeout after
- * the last reply for final startup messages to arrive (esp. system
- * info.)
- */
- while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
- }
- gnss_cb_->location_cbq_.reset();
-}
-
-void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
- const int kPreferredAccuracy = 0; // Ideally perfect (matches GnssLocationProvider)
- const int kPreferredTimeMsec = 0; // Ideally immediate
-
- const auto result = gnss_hal_->setPositionMode_1_1(
- IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
- min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
-
- ASSERT_TRUE(result.isOk());
- EXPECT_TRUE(result);
-}
-
-bool GnssHalTest::StartAndCheckFirstLocation() {
- const auto result = gnss_hal_->start();
-
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(result);
-
- /*
- * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
- * so allow time to demodulate ephemeris over the air.
- */
- const int kFirstGnssLocationTimeoutSeconds = 75;
-
- EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
- kFirstGnssLocationTimeoutSeconds));
- int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
- EXPECT_EQ(locationCalledCount, 1);
-
- if (locationCalledCount > 0) {
- // don't require speed on first fix
- CheckLocation(gnss_cb_->last_location_, false);
- return true;
- }
- return false;
-}
-
-void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) {
- const bool check_more_accuracies =
- (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
-
- Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
-}
-
-void GnssHalTest::StartAndCheckLocations(int count) {
- const int kMinIntervalMsec = 500;
- const int kLocationTimeoutSubsequentSec = 2;
- const bool kLowPowerMode = false;
-
- SetPositionMode(kMinIntervalMsec, kLowPowerMode);
-
- EXPECT_TRUE(StartAndCheckFirstLocation());
-
- for (int i = 1; i < count; i++) {
- EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
- kLocationTimeoutSubsequentSec));
- int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
- EXPECT_EQ(locationCalledCount, i + 1);
- // Don't cause confusion by checking details if no location yet
- if (locationCalledCount > 0) {
- // Should be more than 1 location by now, but if not, still don't check first fix speed
- CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
- }
- }
-}
-
-GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
- const int locations_to_await, const int gnss_sv_info_list_timeout) {
- gnss_cb_->location_cbq_.reset();
- StartAndCheckLocations(locations_to_await);
- const int location_called_count = gnss_cb_->location_cbq_.calledCount();
-
- // Tolerate 1 less sv status to handle edge cases in reporting.
- int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
- EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
- ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
- sv_info_list_cbq_size, locations_to_await, location_called_count);
-
- // Find first non-GPS constellation to blacklist
- GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
- for (int i = 0; i < sv_info_list_cbq_size; ++i) {
- hidl_vec<IGnssCallback_2_1::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)) {
- // found a non-GPS constellation
- constellation_to_blacklist = gnss_sv.v2_0.constellation;
- break;
- }
- }
- if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
- break;
- }
- }
-
- if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
- ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
- // Proceed functionally to blacklist something.
- constellation_to_blacklist = GnssConstellationType::GLONASS;
- }
-
- return constellation_to_blacklist;
-}
-
-GnssHalTest::GnssCallback::GnssCallback()
- : info_cbq_("system_info"),
- name_cbq_("name"),
- capabilities_cbq_("capabilities"),
- location_cbq_("location"),
- sv_info_list_cbq_("sv_info") {}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
- const IGnssCallback_1_0::GnssSystemInfo& info) {
- ALOGI("Info received, year %d", info.yearOfHw);
- info_cbq_.store(info);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
- ALOGI("Capabilities received %d", capabilities);
- capabilities_cbq_.store(capabilities);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
- ALOGI("Capabilities (v2.0) received %d", capabilities);
- capabilities_cbq_.store(capabilities);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
- ALOGI("Capabilities (v2.1) received %d", capabilities);
- capabilities_cbq_.store(capabilities);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
- ALOGI("Name received: %s", name.c_str());
- name_cbq_.store(name);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
- ALOGI("Location received");
- GnssLocation_2_0 location_v2_0;
- location_v2_0.v1_0 = location;
- return gnssLocationCbImpl(location_v2_0);
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
- ALOGI("Location (v2.0) received");
- return gnssLocationCbImpl(location);
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
- location_cbq_.store(location);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
- ALOGI("gnssSvStatusCb");
- return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_1(
- const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) {
- ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
- sv_info_list_cbq_.store(svInfoList);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1(
- const IGnssMeasurementCallback_2_1::GnssData& data) {
- ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
- measurement_cbq_.store(data);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
- uint32_t capabilities) {
- ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
- capabilities_cbq_.store(capabilities);
- return Void();
-}
-
-Return<void> GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb(
- const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
- ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
- antenna_info_cbq_.store(gnssAntennaInfos);
- return Void();
-}
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index 9e6e162..c28e248 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 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.
@@ -14,221 +14,12 @@
* limitations under the License.
*/
-#ifndef GNSS_HAL_TEST_H_
-#define GNSS_HAL_TEST_H_
+#pragma once
#include <android/hardware/gnss/2.1/IGnss.h>
-#include "GnssCallbackEventQueue.h"
+#include "v2_1/gnss_hal_test_template.h"
-#include <gtest/gtest.h>
-
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-
-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::IGnss;
-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
// The main test class for GNSS HAL.
-class GnssHalTest : public testing::TestWithParam<std::string> {
- public:
- virtual void SetUp() override;
-
- virtual void TearDown() override;
-
- /* Callback class for data & Event. */
- class GnssCallback : public IGnssCallback_2_1 {
- public:
- IGnssCallback_1_0::GnssSystemInfo last_info_;
- android::hardware::hidl_string last_name_;
- uint32_t last_capabilities_;
- GnssLocation_2_0 last_location_;
-
- GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
- GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
- GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
- GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
- GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
-
- GnssCallback();
- virtual ~GnssCallback() = default;
-
- // Dummy callback handlers
- Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
- return Void();
- }
- Return<void> gnssNmeaCb(int64_t /* timestamp */,
- const android::hardware::hidl_string& /* nmea */) override {
- return Void();
- }
- Return<void> gnssAcquireWakelockCb() override { return Void(); }
- Return<void> gnssReleaseWakelockCb() override { return Void(); }
- Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
- return Void();
- }
- Return<void> gnssRequestTimeCb() override { return Void(); }
- // Actual (test) callback handlers
- Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
- Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
- Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
- Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
- Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
-
- // New in v2.0
- Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
- Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
- bool /* isUserEmergency */) override {
- return Void();
- }
- Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
- Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
- return Void();
- }
-
- // New in v2.1
- Return<void> gnssSvStatusCb_2_1(
- const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
- Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
-
- private:
- Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
- };
-
- /* Callback class for GnssMeasurement. */
- class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
- public:
- GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::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();
- }
-
- // Methods from V1_1::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
- return Void();
- }
-
- // Methods from V2_0::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
- return Void();
- }
-
- // Methods from V2_1::IGnssMeasurementCallback follow.
- Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
- };
-
- /* Callback class for GnssMeasurementCorrections. */
- class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
- public:
- uint32_t last_capabilities_;
- GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
-
- GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
- virtual ~GnssMeasurementCorrectionsCallback() = default;
-
- // Methods from V1_0::IMeasurementCorrectionsCallback follow.
- Return<void> setCapabilitiesCb(uint32_t capabilities) override;
- };
-
- /* Callback class for GnssAntennaInfo. */
- class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
- public:
- GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
- antenna_info_cbq_;
-
- GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
- virtual ~GnssAntennaInfoCallback() = default;
-
- // Methods from V2_1::GnssAntennaInfoCallback follow.
- Return<void> gnssAntennaInfoCb(
- const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
- };
-
- /*
- * SetUpGnssCallback:
- * Set GnssCallback and verify the result.
- */
- void SetUpGnssCallback();
-
- /*
- * StartAndCheckFirstLocation:
- * Helper function to start location, and check the first one.
- *
- * <p> Note this leaves the Location request active, to enable Stop call vs. other call
- * reordering tests.
- *
- * returns true if a location was successfully generated
- */
- bool StartAndCheckFirstLocation();
-
- /*
- * CheckLocation:
- * Helper function to vet Location fields
- *
- * check_speed: true if speed related fields are also verified.
- */
- void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
-
- /*
- * StartAndCheckLocations:
- * Helper function to collect, and check a number of
- * normal ~1Hz locations.
- *
- * Note this leaves the Location request active, to enable Stop call vs. other call
- * reordering tests.
- */
- void StartAndCheckLocations(int count);
-
- /*
- * StopAndClearLocations:
- * Helper function to stop locations, and clear any remaining notifications
- */
- void StopAndClearLocations();
-
- /*
- * SetPositionMode:
- * Helper function to set positioning mode and verify output
- */
- void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
-
- /*
- * startLocationAndGetNonGpsConstellation:
- * 1. Start location
- * 2. Find and return first non-GPS constellation
- *
- * Note that location is not stopped in this method. The client should call
- * StopAndClearLocations() after the call.
- */
- GnssConstellationType startLocationAndGetNonGpsConstellation(
- const int locations_to_await, const int gnss_sv_info_list_timeout);
-
- sp<IGnss> gnss_hal_; // GNSS HAL to call into
- sp<GnssCallback> gnss_cb_; // Primary callback interface
-};
-
-#endif // GNSS_HAL_TEST_H_
+class GnssHalTest : public GnssHalTestTemplate<IGnss> {};
diff --git a/gnss/3.0/Android.bp b/gnss/3.0/Android.bp
new file mode 100644
index 0000000..dada17c
--- /dev/null
+++ b/gnss/3.0/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.gnss@3.0",
+ root: "android.hardware",
+ srcs: [
+ "IGnss.hal",
+ "IGnssPsds.hal",
+ "IGnssPsdsCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/gnss/3.0/IGnss.hal b/gnss/3.0/IGnss.hal
new file mode 100644
index 0000000..18e5a9d
--- /dev/null
+++ b/gnss/3.0/IGnss.hal
@@ -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@3.0;
+
+import @2.1::IGnss;
+import IGnssPsds;
+
+/**
+ * Represents the standard GNSS (Global Navigation Satellite System) interface.
+ */
+interface IGnss extends @2.1::IGnss {
+ /**
+ * This method returns the IGnssPsds interface.
+ *
+ * @return psdsIface Handle to the IGnssPsds interface.
+ */
+ getExtensionPsds() generates (IGnssPsds psdsIface);
+};
diff --git a/gnss/3.0/IGnssPsds.hal b/gnss/3.0/IGnssPsds.hal
new file mode 100644
index 0000000..5004570
--- /dev/null
+++ b/gnss/3.0/IGnssPsds.hal
@@ -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.
+ */
+
+package android.hardware.gnss@3.0;
+
+import @1.0::IGnssXtra;
+import IGnssPsdsCallback;
+
+/**
+ * This interface is used by the GNSS HAL to request the framework to download Predicted Satellite
+ * Data Service data.
+ */
+interface IGnssPsds extends @1.0::IGnssXtra {
+ /**
+ * Opens the PSDS interface and provides the callback routines to the implementation of this
+ * interface.
+ *
+ * @param callback Handle to the IGnssPsdsCallback interface.
+ *
+ * @return success True if the operation is successful.
+ */
+ setCallback_3_0(IGnssPsdsCallback callback) generates (bool success);
+
+ /**
+ * Inject the downloaded PSDS data into the GNSS receiver.
+ *
+ * @param psdsType Type of PSDS as defined in IGnssPsdsCallback.hal
+ * @param psdsData GNSS PSDS data. Framework must not parse the data since the data format is
+ * opaque to framework.
+ *
+ * @return success True if the operation is successful.
+ */
+ injectPsdsData_3_0(int32_t psdsType, string psdsData) generates (bool success);
+};
+
diff --git a/gnss/3.0/IGnssPsdsCallback.hal b/gnss/3.0/IGnssPsdsCallback.hal
new file mode 100644
index 0000000..d91385f
--- /dev/null
+++ b/gnss/3.0/IGnssPsdsCallback.hal
@@ -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.gnss@3.0;
+
+import @1.0::IGnssXtraCallback;
+
+/**
+ * This interface is used by the GNSS HAL to request download data from Predicted Satellite Data
+ * Service (PSDS).
+ */
+interface IGnssPsdsCallback extends @1.0::IGnssXtraCallback {
+ /**
+ * Callback to request the client to download PSDS data. The client should
+ * download PSDS data and inject it by calling injectPsdsData().
+ *
+ * psdsType represents the type of PSDS data requested.
+ * - Value 1 represents the Long-Term type PSDS data, which lasts for many hours to several days
+ * and often provides satellite orbit and clock accuracy of 2 - 20 meters.
+ * - Value 2 represents the Normal type PSDS data, which is similar to broadcast ephemeris in
+ * longevity - lasting for hours and providings satellite orbit and clock accuracy of 1 - 2
+ * meters.
+ * - Value 3 represents the Real-Time type PSDS data, which lasts for minutes and provides brief
+ * satellite status information such as temporary malfunction, but does not include satellite
+ * orbit or clock information.
+ */
+ downloadRequestCb_3_0(int32_t psdsType);
+};
diff --git a/gnss/3.0/default/Android.bp b/gnss/3.0/default/Android.bp
new file mode 100644
index 0000000..2b33b32
--- /dev/null
+++ b/gnss/3.0/default/Android.bp
@@ -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.
+ */
+
+cc_binary {
+ name: "android.hardware.gnss@3.0-service",
+ init_rc: ["android.hardware.gnss@3.0-service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ vintf_fragments: ["android.hardware.gnss@3.0-service.xml"],
+ srcs: [
+ "Gnss.cpp",
+ "GnssPsds.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@3.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.measurement_corrections@1.0",
+ ],
+ static_libs: [
+ "android.hardware.gnss@common-default-lib",
+ ],
+}
diff --git a/gnss/3.0/default/Gnss.cpp b/gnss/3.0/default/Gnss.cpp
new file mode 100644
index 0000000..5f2ca4f
--- /dev/null
+++ b/gnss/3.0/default/Gnss.cpp
@@ -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.
+ */
+
+#define LOG_TAG "Gnss"
+
+#include "Gnss.h"
+#include <log/log.h>
+#include "GnssPsds.h"
+#include "Utils.h"
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+// Methods from V3_0::IGnss follow.
+Return<sp<V3_0::IGnssPsds>> Gnss::getExtensionPsds() {
+ ALOGD("Gnss::getExtensionPsds");
+ return new GnssPsds();
+}
+
+} // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/Gnss.h b/gnss/3.0/default/Gnss.h
new file mode 100644
index 0000000..7ae562a
--- /dev/null
+++ b/gnss/3.0/default/Gnss.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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/3.0/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include "v2_1/GnssTemplate.h"
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::gnss::common::implementation::GnssTemplate;
+
+struct Gnss : public GnssTemplate<IGnss> {
+ Gnss(){};
+ ~Gnss(){};
+
+ // Methods from V3_0::IGnss follow.
+ Return<sp<V3_0::IGnssPsds>> getExtensionPsds() override;
+};
+
+} // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/GnssPsds.cpp b/gnss/3.0/default/GnssPsds.cpp
new file mode 100644
index 0000000..44e096e
--- /dev/null
+++ b/gnss/3.0/default/GnssPsds.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.
+ */
+
+#define LOG_TAG "GnssPsds"
+
+#include "GnssPsds.h"
+
+#include <log/log.h>
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+sp<V3_0::IGnssPsdsCallback> GnssPsds::sCallback_3_0 = nullptr;
+
+// Methods from V1_0::IGnssXtra follow.
+Return<bool> GnssPsds::setCallback(const sp<V1_0::IGnssXtraCallback>&) {
+ // TODO implement
+ return bool{};
+}
+
+Return<bool> GnssPsds::injectXtraData(const hidl_string&) {
+ // TODO implement
+ return bool{};
+}
+
+// Methods from V3_0::IGnssPsds follow.
+Return<bool> GnssPsds::setCallback_3_0(const sp<V3_0::IGnssPsdsCallback>& callback) {
+ ALOGD("setCallback_3_0");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback_3_0 = callback;
+ return true;
+}
+
+Return<bool> GnssPsds::injectPsdsData_3_0(int32_t psdsType, const hidl_string& psdsData) {
+ ALOGD("injectPsdsData_3_0. psdsType: %d, psdsData: %s", psdsType, psdsData.c_str());
+ return true;
+}
+} // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/GnssPsds.h b/gnss/3.0/default/GnssPsds.h
new file mode 100644
index 0000000..4053bf1
--- /dev/null
+++ b/gnss/3.0/default/GnssPsds.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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/3.0/IGnssPsds.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android::hardware::gnss::V3_0::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;
+
+struct GnssPsds : public V3_0::IGnssPsds {
+ // Methods from V1_0::IGnssXtra follow.
+ Return<bool> setCallback(const sp<V1_0::IGnssXtraCallback>& callback) override;
+ Return<bool> injectXtraData(const hidl_string& xtraData) override;
+
+ // Methods from V3_0::IGnssPsds follow.
+ Return<bool> setCallback_3_0(const sp<V3_0::IGnssPsdsCallback>& callback) override;
+ Return<bool> injectPsdsData_3_0(int32_t psdsType, const hidl_string& psdsData) override;
+
+ private:
+ // Guarded by mMutex
+ static sp<V3_0::IGnssPsdsCallback> sCallback_3_0;
+
+ // Synchronization lock for sCallback_3_0
+ mutable std::mutex mMutex;
+};
+
+} // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/OWNERS b/gnss/3.0/default/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/3.0/default/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/3.0/default/android.hardware.gnss@3.0-service.rc b/gnss/3.0/default/android.hardware.gnss@3.0-service.rc
new file mode 100644
index 0000000..c2bfb91
--- /dev/null
+++ b/gnss/3.0/default/android.hardware.gnss@3.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.gnss-3-0 /vendor/bin/hw/android.hardware.gnss@3.0-service
+ class hal
+ user system
+ group system
diff --git a/gnss/3.0/default/android.hardware.gnss@3.0-service.xml b/gnss/3.0/default/android.hardware.gnss@3.0-service.xml
new file mode 100644
index 0000000..6709e0c
--- /dev/null
+++ b/gnss/3.0/default/android.hardware.gnss@3.0-service.xml
@@ -0,0 +1,13 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gnss</name>
+ <transport>hwbinder</transport>
+ <version>3.0</version>
+ <version>2.1</version>
+ <version>1.1</version>
+ <interface>
+ <name>IGnss</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/gnss/3.0/default/service.cpp b/gnss/3.0/default/service.cpp
new file mode 100644
index 0000000..87b4580
--- /dev/null
+++ b/gnss/3.0/default/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.
+ */
+
+#define LOG_TAG "android.hardware.gnss@3.0-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "Gnss.h"
+
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V3_0::IGnss;
+using ::android::hardware::gnss::V3_0::implementation::Gnss;
+
+int main(int /* argc */, char* /* argv */[]) {
+ sp<IGnss> gnss = new Gnss();
+ configureRpcThreadpool(1, true /* will join */);
+ if (gnss->registerAsService() != OK) {
+ ALOGE("Could not register gnss 3.0 service.");
+ return 1;
+ }
+ joinRpcThreadpool();
+
+ ALOGE("Service exited!");
+ return 1;
+}
\ No newline at end of file
diff --git a/gnss/3.0/vts/OWNERS b/gnss/3.0/vts/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/3.0/vts/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/3.0/vts/functional/Android.bp b/gnss/3.0/vts/functional/Android.bp
new file mode 100644
index 0000000..584424c
--- /dev/null
+++ b/gnss/3.0/vts/functional/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_test {
+ name: "VtsHalGnssV3_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "gnss_hal_test_cases.cpp",
+ "VtsHalGnssV3_0TargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@3.0",
+ "android.hardware.gnss@common-vts-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.cpp b/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.cpp
new file mode 100644
index 0000000..31e6164
--- /dev/null
+++ b/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.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.
+ */
+#define LOG_TAG "VtsHalGnssV3_0TargetTest"
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "gnss_hal_test.h"
+
+using android::hardware::gnss::V3_0::IGnss;
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/3.0/vts/functional/gnss_hal_test.h b/gnss/3.0/vts/functional/gnss_hal_test.h
new file mode 100644
index 0000000..387214e
--- /dev/null
+++ b/gnss/3.0/vts/functional/gnss_hal_test.h
@@ -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.
+ */
+
+#pragma once
+
+#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
diff --git a/gnss/3.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/3.0/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..cc5341c
--- /dev/null
+++ b/gnss/3.0/vts/functional/gnss_hal_test_cases.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.
+ */
+
+#define LOG_TAG "GnssHalTestCases"
+
+#include <gnss_hal_test.h>
+#include <cmath>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::common::Utils;
+
+using android::hardware::gnss::V3_0::IGnssPsds;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * TestPsdsExtension:
+ * Gets the PsdsExtension and verifies that it returns a non-null extension.
+ */
+TEST_P(GnssHalTest, TestPsdsExtension) {
+ auto psds = gnss_hal_->getExtensionPsds();
+ ASSERT_TRUE(psds.isOk());
+ sp<IGnssPsds> iPsds = psds;
+ ASSERT_TRUE(iPsds != nullptr);
+}
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
new file mode 100644
index 0000000..c503190
--- /dev/null
+++ b/gnss/aidl/Android.bp
@@ -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.
+ */
+
+aidl_interface {
+ name: "android.hardware.gnss",
+ vendor_available: true,
+ srcs: ["android/hardware/gnss/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/gnss/aidl/OWNERS b/gnss/aidl/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/aidl/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
new file mode 100644
index 0000000..89f5d53
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.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
+parcelable BlocklistedSource {
+ android.hardware.gnss.GnssConstellationType constellation;
+ int svid;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
new file mode 100644
index 0000000..30d0227
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.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;
+@Backing(type="int") @VintfStability
+enum GnssConstellationType {
+ UNKNOWN = 0,
+ GPS = 1,
+ SBAS = 2,
+ GLONASS = 3,
+ QZSS = 4,
+ BEIDOU = 5,
+ GALILEO = 6,
+ IRNSS = 7,
+}
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
new file mode 100644
index 0000000..146577e
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.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
+interface IGnss {
+ void setCallback(in android.hardware.gnss.IGnssCallback callback);
+ void close();
+ android.hardware.gnss.IGnssPsds getExtensionPsds();
+ android.hardware.gnss.IGnssConfiguration getExtensionGnssConfiguration();
+ const int ERROR_INVALID_ARGUMENT = 1;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
new file mode 100644
index 0000000..62870d6
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.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 IGnssCallback {
+ void gnssSetCapabilitiesCb(in int capabilities);
+ const int CAPABILITY_SATELLITE_BLOCKLIST = 1;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
new file mode 100644
index 0000000..5af30cf
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.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.gnss;
+@VintfStability
+interface IGnssConfiguration {
+ void setSuplVersion(in int version);
+ void setSuplMode(in int mode);
+ void setLppProfile(in int lppProfile);
+ void setGlonassPositioningProtocol(in int protocol);
+ void setEmergencySuplPdn(in boolean enable);
+ void setEsExtensionSec(in int emergencyExtensionSeconds);
+ void setBlocklist(in android.hardware.gnss.BlocklistedSource[] blocklist);
+ const int SUPL_MODE_MSB = 1;
+ const int SUPL_MODE_MSA = 2;
+ const int LPP_PROFILE_USER_PLANE = 1;
+ const int LPP_PROFILE_CONTROL_PLANE = 2;
+ const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 1;
+ const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 2;
+ const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 4;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
new file mode 100644
index 0000000..ddef928
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.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 IGnssPsds {
+ void injectPsdsData(in android.hardware.gnss.PsdsType psdsType, in byte[] psdsData);
+ void setCallback(in android.hardware.gnss.IGnssPsdsCallback callback);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
new file mode 100644
index 0000000..8413d2c
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.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 IGnssPsdsCallback {
+ void downloadRequestCb(in android.hardware.gnss.PsdsType psdsType);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
new file mode 100644
index 0000000..9d1984e
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.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 PsdsType {
+ LONG_TERM = 1,
+ NORMAL = 2,
+ REALTIME = 3,
+}
diff --git a/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
new file mode 100644
index 0000000..2fde5b2
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/BlocklistedSource.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.gnss;
+
+import android.hardware.gnss.GnssConstellationType;
+
+/**
+ * Represents a blocklisted source.
+ */
+@VintfStability
+parcelable BlocklistedSource {
+ /**
+ * Defines the constellation of the given satellite(s).
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid, or 0 to blocklist all
+ * svid's for the specified constellation.
+ */
+ int svid;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
new file mode 100644
index 0000000..af3e089
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssConstellationType.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.gnss;
+
+/**
+ * GNSS constellation type
+ *
+ * This is to specify the navigation satellite system, for example, as listed in Section 3.5 in
+ * RINEX Version 3.04.
+ */
+@VintfStability
+@Backing(type="int")
+enum GnssConstellationType {
+ UNKNOWN = 0,
+ /** Global Positioning System. */
+ GPS = 1,
+ /** Satellite-Based Augmentation System. */
+ SBAS = 2,
+ /** Global Navigation Satellite System. */
+ GLONASS = 3,
+ /** Quasi-Zenith Satellite System. */
+ QZSS = 4,
+ /** BeiDou Navigation Satellite System. */
+ BEIDOU = 5,
+ /** Galileo Navigation Satellite System. */
+ GALILEO = 6,
+ /** Indian Regional Navigation Satellite System. */
+ IRNSS = 7,
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
new file mode 100644
index 0000000..24632aa
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -0,0 +1,78 @@
+/*
+ * 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.IGnssCallback;
+import android.hardware.gnss.IGnssPsds;
+import android.hardware.gnss.IGnssConfiguration;
+
+/**
+ * Represents the standard GNSS (Global Navigation Satellite System) interface.
+ */
+@VintfStability
+interface IGnss {
+
+ /**
+ * All GNSS Binder calls may return a ServiceSpecificException with the following error
+ * codes.
+ */
+ const int ERROR_INVALID_ARGUMENT = 1;
+
+ /**
+ * Opens the interface and provides the callback routines to the implementation of this
+ * interface.
+ *
+ * The framework calls this method to instruct the GPS engine to prepare for serving requests
+ * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
+ * framework upon successful return from this method until cleanup() method is called to
+ * close this interface.
+ *
+ * @param callback Callback interface for IGnss.
+ */
+ void setCallback(in IGnssCallback callback);
+
+ /**
+ * Closes the interface.
+ *
+ * The close() method is called by the framework to tell the GNSS HAL implementation to
+ * clear the callback and not expect any GNSS requests in the immediate future - e.g. this may
+ * be called when location is disabled by a user setting or low battery conditions. The GNSS HAL
+ * implementation must immediately stop responding to any existing requests until the
+ * setCallback() method is called again and the requests are re-initiated by the framework.
+ *
+ * After this method is called, the GNSS HAL implementation may choose to modify GNSS hardware
+ * states to save power. It is expected that when setCallback() method is called again to
+ * reopen this interface, to serve requests, there may be some minor delays in GNSS response
+ * requests as hardware readiness states are restored, not to exceed those that occur on normal
+ * device boot up.
+ */
+ void close();
+
+ /**
+ * This method returns the IGnssPsds interface.
+ *
+ * @return Handle to the IGnssPsds interface.
+ */
+ IGnssPsds getExtensionPsds();
+
+ /**
+ * This method returns the IGnssConfiguration interface.
+ *
+ * @return Handle to the IGnssConfiguration interface.
+ */
+ IGnssConfiguration getExtensionGnssConfiguration();
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
new file mode 100644
index 0000000..a46a018
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.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.IGnssPsds;
+import android.hardware.gnss.IGnssConfiguration;
+
+/**
+ * This interface is required for the HAL to communicate certain information
+ * like status and location info back to the framework, the framework implements
+ * the interfaces and passes a handle to the HAL.
+ */
+@VintfStability
+interface IGnssCallback {
+
+ /** Capability bit mask indicating GNSS supports blocklisting satellites */
+ const int CAPABILITY_SATELLITE_BLOCKLIST = 1 << 0;
+
+ /**
+ * Callback to inform framework of the GNSS HAL implementation's capabilities.
+ *
+ * @param capabilities Capability parameter is a bit field of the Capability bit masks.
+ */
+ void gnssSetCapabilitiesCb(in int capabilities);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
new file mode 100644
index 0000000..e0ad357
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
@@ -0,0 +1,122 @@
+/*
+ * 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.BlocklistedSource;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+@VintfStability
+interface IGnssConfiguration {
+
+ /** SUPL mode bitmask for Mobile Station Based. */
+ const int SUPL_MODE_MSB = 0x01;
+
+ /** SUPL mode bitmask for Mobile Station Assisted. */
+ const int SUPL_MODE_MSA = 0x02;
+
+ /** LPP profile settings bitmask for enabling LTE Positioning Protocol User Plane. */
+ const int LPP_PROFILE_USER_PLANE = 0x01;
+
+ /** LPP profile settings bitmask for enabling LTE Positioning Protocol Control Plane. */
+ const int LPP_PROFILE_CONTROL_PLANE = 0x02;
+
+ /** A-Glonass positioning protocol bitmask for Radio Resource Control (RRC) Control Plane. */
+ const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 0x01;
+
+ /** A-Glonass positioning protocol bitmask for Radio Resource Location User Plane. */
+ const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 0x02;
+
+ /** A-Glonass positioning protocol bitmask for LTE Positioning Protocol User Plane. */
+ const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 0x04;
+
+ /**
+ * This method sets the SUPL version requested by Carrier. The GNSS HAL must use this version
+ * of the SUPL protocol if supported.
+ *
+ * @param version SUPL version requested by carrier. This is a bit mask with bits 0:7
+ * representing a service indicator field, bits 8:15 representing the minor version and bits
+ * 16:23 representing the major version.
+ */
+ void setSuplVersion(in int version);
+
+ /**
+ * This method sets the SUPL mode.
+ *
+ * @param mode Bitmask that specifies the SUPL mode which is set with the SUPL_MODE_* constants.
+ */
+ void setSuplMode(in int mode);
+
+ /**
+ * This method sets the LTE Positioning Profile configuration.
+ *
+ * @param lppProfile Bitmask that specifies the LTE Positioning Profile configuration to be set
+ * as per the LPP_PROFILE_* constants. If none of the bits are set, the default setting is
+ * Radio Resource Location Protocol (RRLP).
+ */
+ void setLppProfile(in int lppProfile);
+
+ /**
+ * This method selects positioning protocol on A-Glonass system.
+ *
+ * @param protocol Bitmask that specifies the positioning protocol to be set as per
+ * GLONASS_POS_PROTOCOL_* constants.
+ */
+ void setGlonassPositioningProtocol(in int protocol);
+
+ /**
+ * This method configures which PDN to use.
+ *
+ * @param enable Use emergency PDN if true and regular PDN if false.
+ */
+ void setEmergencySuplPdn(in boolean enable);
+
+ /**
+ * This method sets the emergency session extension duration. The GNSS HAL
+ * implementation must serve emergency SUPL and Control Plane network initiated
+ * location requests for this extra duration after the user initiated emergency
+ * session ends.
+ *
+ * @param emergencyExtensionSeconds Number of seconds to extend the emergency
+ * session duration post emergency call.
+ */
+ void setEsExtensionSec(in int emergencyExtensionSeconds);
+
+ /**
+ * Injects a vector of BlocklistedSource(s) which the HAL must not use to calculate the
+ * GNSS location output.
+ *
+ * The superset of all satellite sources provided, including wildcards, in the latest call
+ * to this method, is the set of satellites sources that must not be used in calculating
+ * location.
+ *
+ * All measurements from the specified satellites, across frequency bands, are blocklisted
+ * together.
+ *
+ * If this method is never called after the IGnssConfiguration.hal connection is made on boot,
+ * or is called with an empty vector, then no satellites are to be blocklisted as a result of
+ * this API.
+ *
+ * This blocklist must be considered as an additional source of which satellites
+ * should not be trusted for location on top of existing sources of similar information
+ * such as satellite broadcast health being unhealthy and measurement outlier removal.
+ *
+ * @param blocklist The BlocklistedSource(s) of satellites the HAL must not use.
+ */
+ void setBlocklist(in BlocklistedSource[] blocklist);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
new file mode 100644
index 0000000..7c46096
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssPsds.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.gnss;
+
+import android.hardware.gnss.IGnssPsdsCallback;
+import android.hardware.gnss.PsdsType;
+
+/**
+ * This interface is used by the GNSS HAL to request the framework to download Predicted Satellite
+ * Data Service data.
+ */
+@VintfStability
+interface IGnssPsds {
+
+ /**
+ * Inject the downloaded PSDS data into the GNSS receiver.
+ *
+ * @param psdsType Type of PSDS data.
+ * @param psdsData GNSS PSDS data. Framework must not parse the data since the data format is
+ * opaque to framework.
+ */
+ void injectPsdsData(in PsdsType psdsType, in byte[] psdsData);
+
+ /**
+ * Opens the PSDS interface and provides the callback routines to the implementation of this
+ * interface.
+ *
+ * @param callback Handle to the IGnssPsdsCallback interface.
+ */
+ void setCallback(in IGnssPsdsCallback callback);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl
new file mode 100644
index 0000000..72b693b
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.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.gnss;
+
+import android.hardware.gnss.PsdsType;
+
+/**
+ * This interface is used by the GNSS HAL to request download data from Predicted Satellite Data
+ * Service (PSDS).
+ */
+@VintfStability
+interface IGnssPsdsCallback {
+
+ /**
+ * Callback to request the client to download PSDS data from one of the URLs defined in the
+ * framework specified by psdsType. The URLs must be specified via properties on the vendor
+ * partitions. E.g., LONGTERM_PSDS_SERVER_1, NORMAL_PSDS_SERVER, or REALTIME_PSDS_SERVER. The
+ * client must download PSDS data and inject it by calling injectPsdsData().
+ *
+ * @param psdsType Type of PSDS data.
+ */
+ void downloadRequestCb(in PsdsType psdsType);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/PsdsType.aidl b/gnss/aidl/android/hardware/gnss/PsdsType.aidl
new file mode 100644
index 0000000..d4fec77
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/PsdsType.aidl
@@ -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.
+ */
+
+package android.hardware.gnss;
+
+/** The type of PSDS data. */
+@VintfStability
+@Backing(type="int")
+enum PsdsType {
+
+ /**
+ * Long-Term type PSDS data, which lasts for many hours to several days and often provides
+ * satellite orbit and clock accuracy of 2 - 20 meters.
+ */
+ LONG_TERM = 1,
+
+ /**
+ * Normal type PSDS data, which is similar to broadcast ephemeris in longevity - lasting for
+ * hours and providings satellite orbit and clock accuracy of 1 - 2 meters.
+ */
+ NORMAL = 2,
+
+ /**
+ * Real-Time type PSDS data, which lasts for minutes and provides brief satellite status
+ * information such as temporary malfunction, but does not include satellite orbit or clock
+ * information.
+ */
+ REALTIME = 3,
+}
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
new file mode 100644
index 0000000..1fe43c3
--- /dev/null
+++ b/gnss/aidl/default/Android.bp
@@ -0,0 +1,57 @@
+/*
+ * 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.gnss-service.example",
+ relative_install_path: "hw",
+ init_rc: [
+ "gnss-default.rc",
+ ],
+ vintf_fragments: [
+ "gnss-default.xml",
+ "gnss@2.1-service.xml",
+ ],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss-ndk_platform",
+ ],
+ srcs: [
+ "Gnss.cpp",
+ "GnssHidlHal.cpp",
+ "GnssPsds.cpp",
+ "GnssConfiguration.cpp",
+ "service.cpp",
+ ],
+ static_libs: [
+ "android.hardware.gnss@common-default-lib",
+ ],
+}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
new file mode 100644
index 0000000..b4d92fd
--- /dev/null
+++ b/gnss/aidl/default/Gnss.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "GnssAidl"
+
+#include "Gnss.h"
+#include <log/log.h>
+#include "GnssConfiguration.h"
+#include "GnssPsds.h"
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IGnssCallback> Gnss::sGnssCallback = nullptr;
+
+ndk::ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) {
+ ALOGD("Gnss::setCallback");
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
+ }
+
+ sGnssCallback = callback;
+
+ int capabilities = (int)IGnssCallback::CAPABILITY_SATELLITE_BLOCKLIST;
+ auto status = sGnssCallback->gnssSetCapabilitiesCb(capabilities);
+ if (!status.isOk()) {
+ ALOGE("%s: Unable to invoke callback.gnssSetCapabilities", __func__);
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::close() {
+ ALOGD("Gnss::close");
+ sGnssCallback = nullptr;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) {
+ ALOGD("Gnss::getExtensionPsds");
+ *iGnssPsds = SharedRefBase::make<GnssPsds>();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionGnssConfiguration(
+ std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) {
+ ALOGD("Gnss::getExtensionGnssConfiguration");
+ if (mGnssConfiguration == nullptr) {
+ mGnssConfiguration = SharedRefBase::make<GnssConfiguration>();
+ }
+ *iGnssConfiguration = mGnssConfiguration;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
new file mode 100644
index 0000000..61d7cf7
--- /dev/null
+++ b/gnss/aidl/default/Gnss.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 <aidl/android/hardware/gnss/BnGnss.h>
+#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
+#include <aidl/android/hardware/gnss/BnGnssPsds.h>
+#include "GnssConfiguration.h"
+
+namespace aidl::android::hardware::gnss {
+
+class Gnss : public BnGnss {
+ public:
+ ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssCallback>& callback) override;
+ ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) override;
+ ndk::ScopedAStatus getExtensionGnssConfiguration(
+ std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) override;
+
+ std::shared_ptr<GnssConfiguration> mGnssConfiguration;
+
+ private:
+ static std::shared_ptr<IGnssCallback> sGnssCallback;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssConfiguration.cpp b/gnss/aidl/default/GnssConfiguration.cpp
new file mode 100644
index 0000000..30e0d8c
--- /dev/null
+++ b/gnss/aidl/default/GnssConfiguration.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 "GnssConfigurationAidl"
+
+#include "GnssConfiguration.h"
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+ndk::ScopedAStatus GnssConfiguration::setBlocklist(const vector<BlocklistedSource>& sourceList) {
+ ALOGD("GnssConfiguration::setBlocklist");
+ std::unique_lock<std::recursive_mutex> lock(mMutex);
+ mBlocklistedConstellationSet.clear();
+ mBlocklistedSourceSet.clear();
+ for (const auto& source : sourceList) {
+ if (source.svid == 0) {
+ // Wildcard blocklist, i.e., blocklist entire constellation.
+ mBlocklistedConstellationSet.insert(source.constellation);
+ } else {
+ mBlocklistedSourceSet.insert(source);
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+bool GnssConfiguration::isBlocklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const {
+ std::unique_lock<std::recursive_mutex> lock(mMutex);
+ if (mBlocklistedConstellationSet.find(static_cast<GnssConstellationType>(
+ gnssSvInfo.v2_0.constellation)) != mBlocklistedConstellationSet.end()) {
+ return true;
+ }
+ BlocklistedSource source = {
+ .constellation = static_cast<GnssConstellationType>(gnssSvInfo.v2_0.constellation),
+ .svid = gnssSvInfo.v2_0.v1_0.svid};
+ return (mBlocklistedSourceSet.find(source) != mBlocklistedSourceSet.end());
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssConfiguration.h b/gnss/aidl/default/GnssConfiguration.h
new file mode 100644
index 0000000..25fa16e
--- /dev/null
+++ b/gnss/aidl/default/GnssConfiguration.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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
+#include <android/hardware/gnss/2.1/IGnssCallback.h>
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+
+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);
+ }
+};
+
+struct BlocklistedSourceEqual {
+ inline bool operator()(const BlocklistedSource& s1, const BlocklistedSource& s2) const {
+ return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
+ }
+};
+
+using GnssSvInfoV2_1 = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
+using std::vector;
+using BlocklistedSourceSet =
+ std::unordered_set<BlocklistedSource, BlocklistedSourceHash, BlocklistedSourceEqual>;
+using BlocklistedConstellationSet = std::unordered_set<GnssConstellationType>;
+
+struct GnssConfiguration : public BnGnssConfiguration {
+ public:
+ ndk::ScopedAStatus setSuplVersion(int) override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus setSuplMode(int) override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus setLppProfile(int) override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus setGlonassPositioningProtocol(int) override {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus setEmergencySuplPdn(bool) override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus setEsExtensionSec(int) override { return ndk::ScopedAStatus::ok(); }
+
+ ndk::ScopedAStatus setBlocklist(const vector<BlocklistedSource>& blocklist) override;
+
+ bool isBlocklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+
+ private:
+ BlocklistedSourceSet mBlocklistedSourceSet;
+ BlocklistedConstellationSet mBlocklistedConstellationSet;
+ mutable std::recursive_mutex mMutex;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.cpp b/gnss/aidl/default/GnssHidlHal.cpp
new file mode 100644
index 0000000..11fc806
--- /dev/null
+++ b/gnss/aidl/default/GnssHidlHal.cpp
@@ -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.
+ */
+
+#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;
+
+GnssHidlHal::GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl) : mGnssAidl(gnssAidl) {
+ Gnss* iGnss = mGnssAidl.get();
+ std::shared_ptr<IGnssConfiguration> iGnssConfiguration;
+ auto status = iGnss->getExtensionGnssConfiguration(&iGnssConfiguration);
+ if (!status.isOk()) {
+ ALOGE("Failed to getExtensionGnssConfiguration.");
+ } else {
+ mGnssConfigurationAidl = iGnss->mGnssConfiguration;
+ }
+};
+
+hidl_vec<GnssSvInfo> GnssHidlHal::filterBlocklistedSatellitesV2_1(
+ hidl_vec<GnssSvInfo> gnssSvInfoList) {
+ ALOGD("filterBlocklistSatellitesV2_1 - overridden by GnssHidlHal class");
+ if (mGnssConfigurationAidl == nullptr) {
+ ALOGE("Handle to AIDL GnssConfiguration is not available.");
+ return gnssSvInfoList;
+ }
+ for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+ 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);
+ }
+ }
+ return gnssSvInfoList;
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.h b/gnss/aidl/default/GnssHidlHal.h
new file mode 100644
index 0000000..50aad3a
--- /dev/null
+++ b/gnss/aidl/default/GnssHidlHal.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 "Gnss.h"
+#include "GnssConfiguration.h"
+#include "v2_1/GnssTemplate.h"
+
+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> {
+ public:
+ GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl);
+
+ private:
+ hidl_vec<GnssSvInfo> filterBlocklistedSatellitesV2_1(
+ hidl_vec<GnssSvInfo> gnssSvInfoList) override;
+
+ std::shared_ptr<Gnss> mGnssAidl;
+ std::shared_ptr<GnssConfiguration> mGnssConfigurationAidl;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPsds.cpp b/gnss/aidl/default/GnssPsds.cpp
new file mode 100644
index 0000000..6512af6
--- /dev/null
+++ b/gnss/aidl/default/GnssPsds.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 "GnssPsdsAidl"
+
+#include "GnssPsds.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IGnssPsdsCallback> GnssPsds::sCallback = nullptr;
+
+ndk::ScopedAStatus GnssPsds::setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback) {
+ ALOGD("setCallback");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssPsds::injectPsdsData(PsdsType psdsType,
+ const std::vector<uint8_t>& psdsData) {
+ ALOGD("injectPsdsData. psdsType: %d, psdsData: %d bytes", static_cast<int>(psdsType),
+ static_cast<int>(psdsData.size()));
+ if (psdsData.size() > 0) {
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return ndk::ScopedAStatus::fromServiceSpecificError(IGnss::ERROR_INVALID_ARGUMENT);
+ }
+}
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPsds.h b/gnss/aidl/default/GnssPsds.h
new file mode 100644
index 0000000..de9e68f
--- /dev/null
+++ b/gnss/aidl/default/GnssPsds.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/BnGnssPsds.h>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssPsds : public BnGnssPsds {
+ public:
+ ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback) override;
+ ndk::ScopedAStatus injectPsdsData(PsdsType psdsType,
+ const std::vector<uint8_t>& psdsData) override;
+
+ private:
+ // Guarded by mMutex
+ static std::shared_ptr<IGnssPsdsCallback> sCallback;
+
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/gnss-default.rc b/gnss/aidl/default/gnss-default.rc
new file mode 100644
index 0000000..fe179c3
--- /dev/null
+++ b/gnss/aidl/default/gnss-default.rc
@@ -0,0 +1,4 @@
+service vendor.gnss-default /vendor/bin/hw/android.hardware.gnss-service.example
+ class hal
+ user nobody
+ group nobody
diff --git a/gnss/aidl/default/gnss-default.xml b/gnss/aidl/default/gnss-default.xml
new file mode 100644
index 0000000..2b06cd2
--- /dev/null
+++ b/gnss/aidl/default/gnss-default.xml
@@ -0,0 +1,9 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.gnss</name>
+ <interface>
+ <name>IGnss</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/gnss/aidl/default/gnss@2.1-service.xml
similarity index 60%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to gnss/aidl/default/gnss@2.1-service.xml
index b5d25cd..12a1fdf 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/gnss/aidl/default/gnss@2.1-service.xml
@@ -1,10 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.wifi</name>
+ <name>android.hardware.gnss</name>
<transport>hwbinder</transport>
- <version>1.4</version>
+ <version>2.1</version>
+ <version>1.1</version>
<interface>
- <name>IWifi</name>
+ <name>IGnss</name>
<instance>default</instance>
</interface>
</hal>
diff --git a/gnss/aidl/default/service.cpp b/gnss/aidl/default/service.cpp
new file mode 100644
index 0000000..09f1ad2
--- /dev/null
+++ b/gnss/aidl/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "Gnss-main"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <pthread.h>
+#include "Gnss.h"
+#include "GnssHidlHal.h"
+
+using aidl::android::hardware::gnss::Gnss;
+using aidl::android::hardware::gnss::GnssHidlHal;
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V2_1::IGnss;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<Gnss> gnssAidl = ndk::SharedRefBase::make<Gnss>();
+ const std::string instance = std::string() + Gnss::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(gnssAidl->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ sp<IGnss> gnss = new GnssHidlHal(gnssAidl);
+ configureRpcThreadpool(1, true /* will join */);
+ if (gnss->registerAsService() != OK) {
+ ALOGE("Could not register gnss 2.1 service.");
+ return 0;
+ }
+
+ joinRpcThreadpool();
+ ABinderProcess_joinThreadPool();
+
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
new file mode 100644
index 0000000..48a0e21
--- /dev/null
+++ b/gnss/aidl/vts/Android.bp
@@ -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.
+
+cc_test {
+ name: "VtsHalGnssTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "gnss_hal_test.cpp",
+ "gnss_hal_test_cases.cpp",
+ "GnssCallbackAidl.cpp",
+ "VtsHalGnssTargetTest.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@1.0",
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.gnss-cpp",
+ "android.hardware.gnss@common-vts-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
new file mode 100644
index 0000000..f5c745b
--- /dev/null
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "GnssCallbackAidl.h"
+#include <log/log.h>
+
+android::binder::Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
new file mode 100644
index 0000000..7f802ea
--- /dev/null
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnGnssCallback.h>
+#include "GnssCallbackEventQueue.h"
+
+/* Callback class for data & Event. */
+class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
+ public:
+ GnssCallbackAidl() : capabilities_cbq_("capabilities"){};
+ ~GnssCallbackAidl(){};
+
+ android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+
+ int last_capabilities_;
+ android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+};
\ No newline at end of file
diff --git a/gnss/aidl/vts/VtsHalGnssTargetTest.cpp b/gnss/aidl/vts/VtsHalGnssTargetTest.cpp
new file mode 100644
index 0000000..4bba92b
--- /dev/null
+++ b/gnss/aidl/vts/VtsHalGnssTargetTest.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.
+ */
+
+#include "gnss_hal_test.h"
+
+#include <android/hardware/gnss/IGnss.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::ProcessState;
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
+INSTANTIATE_TEST_SUITE_P(, GnssHalTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IGnssAidl::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
new file mode 100644
index 0000000..2447bf8
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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 "gnss_hal_test.h"
+#include <hidl/ServiceManagement.h>
+
+using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+
+void GnssHalTest::SetUp() {
+ // Get AIDL handle
+ aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
+ ASSERT_NE(aidl_gnss_hal_, nullptr);
+
+ const auto& hidlInstanceNames = android::hardware::getAllHalInstanceNames(
+ android::hardware::gnss::V2_1::IGnss::descriptor);
+ gnss_hal_ = IGnss_V2_1::getService(hidlInstanceNames[0]);
+ ASSERT_NE(gnss_hal_, nullptr);
+
+ SetUpGnssCallback();
+}
+
+void GnssHalTest::SetUpGnssCallback() {
+ aidl_gnss_cb_ = new GnssCallbackAidl();
+ ASSERT_NE(aidl_gnss_cb_, nullptr);
+
+ auto status = aidl_gnss_hal_->setCallback(aidl_gnss_cb_);
+ if (!status.isOk()) {
+ ALOGE("Failed to setCallback");
+ }
+
+ ASSERT_TRUE(status.isOk());
+
+ /*
+ * Capabilities callback should trigger.
+ */
+ EXPECT_TRUE(aidl_gnss_cb_->capabilities_cbq_.retrieve(aidl_gnss_cb_->last_capabilities_,
+ TIMEOUT_SEC));
+
+ EXPECT_EQ(aidl_gnss_cb_->capabilities_cbq_.calledCount(), 1);
+
+ // Invoke the super method.
+ GnssHalTestTemplate<IGnss_V2_1>::SetUpGnssCallback();
+}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
new file mode 100644
index 0000000..eb5301e
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test.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.
+ */
+
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/gnss/IGnss.h>
+#include <binder/IServiceManager.h>
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include "GnssCallbackAidl.h"
+#include "v2_1/gnss_hal_test_template.h"
+
+using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using IGnssAidl = android::hardware::gnss::IGnss;
+using android::hardware::gnss::BlocklistedSource;
+using android::hardware::gnss::IGnssConfiguration;
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public GnssHalTestTemplate<IGnss_V2_1> {
+ public:
+ GnssHalTest(){};
+ ~GnssHalTest(){};
+ virtual void SetUp() override;
+ virtual void SetUpGnssCallback() override;
+
+ sp<IGnssAidl> aidl_gnss_hal_;
+ sp<GnssCallbackAidl> aidl_gnss_cb_; // Primary callback interface
+};
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..2b8a447
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -0,0 +1,450 @@
+/*
+ * 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 "GnssHalTestCases"
+
+#include <android/hardware/gnss/IGnssPsds.h>
+#include "gnss_hal_test.h"
+
+using android::sp;
+using android::hardware::gnss::BlocklistedSource;
+using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::IGnssConfiguration;
+using android::hardware::gnss::IGnssPsds;
+using android::hardware::gnss::PsdsType;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * 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.
+ */
+TEST_P(GnssHalTest, TestPsdsExtension) {
+ sp<IGnssPsds> iGnssPsds;
+ auto status = aidl_gnss_hal_->getExtensionPsds(&iGnssPsds);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssPsds != nullptr);
+
+ status = iGnssPsds->injectPsdsData(PsdsType::LONG_TERM, std::vector<uint8_t>());
+ ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ * or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+BlocklistedSource FindStrongFrequentNonGpsSource(
+ const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
+ const int min_observations) {
+ struct ComparableBlocklistedSource {
+ BlocklistedSource id;
+
+ ComparableBlocklistedSource() {
+ id.constellation = GnssConstellationTypeAidl::UNKNOWN;
+ id.svid = 0;
+ }
+
+ bool operator<(const ComparableBlocklistedSource& compare) const {
+ return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+ (id.constellation < compare.id.constellation)));
+ }
+ };
+
+ struct SignalCounts {
+ int observations;
+ float max_cn0_dbhz;
+ };
+
+ std::map<ComparableBlocklistedSource, SignalCounts> mapSignals;
+
+ for (const auto& sv_info_vec : sv_info_list) {
+ 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::GPS)) {
+ ComparableBlocklistedSource source;
+ source.id.svid = gnss_sv.v2_0.v1_0.svid;
+ source.id.constellation =
+ static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation);
+
+ const auto& itSignal = mapSignals.find(source);
+ if (itSignal == mapSignals.end()) {
+ SignalCounts counts;
+ counts.observations = 1;
+ counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+ mapSignals.insert(
+ std::pair<ComparableBlocklistedSource, SignalCounts>(source, counts));
+ } else {
+ itSignal->second.observations++;
+ if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
+ itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+ }
+ }
+ }
+ }
+ }
+
+ float max_cn0_dbhz_with_sufficient_count = 0.;
+ int total_observation_count = 0;
+ int blocklisted_source_count_observation = 0;
+
+ ComparableBlocklistedSource source_to_blocklist; // initializes to zero = UNKNOWN constellation
+ for (auto const& pairSignal : mapSignals) {
+ total_observation_count += pairSignal.second.observations;
+ if ((pairSignal.second.observations >= min_observations) &&
+ (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+ source_to_blocklist = pairSignal.first;
+ blocklisted_source_count_observation = pairSignal.second.observations;
+ max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+ }
+ }
+ ALOGD("Among %d observations, chose svid %d, constellation %d, "
+ "with %d observations at %.1f max CNo",
+ total_observation_count, source_to_blocklist.id.svid,
+ (int)source_to_blocklist.id.constellation, blocklisted_source_count_observation,
+ max_cn0_dbhz_with_sufficient_count);
+
+ return source_to_blocklist.id;
+}
+
+/*
+ * BlocklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blocklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blocklist.
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
+ */
+TEST_P(GnssHalTest, BlocklistIndividualSatellites) {
+ if (!(aidl_gnss_cb_->last_capabilities_ &
+ (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+ ALOGI("Test BlocklistIndividualSatellites skipped. SATELLITE_BLOCKLIST capability not "
+ "supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+ const int kRetriesToUnBlocklist = 10;
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+ int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+ /*
+ * Identify strongest SV seen at least kLocationsToAwait -1 times
+ * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+ * observability (one epoch RF null)
+ */
+
+ const int kGnssSvInfoListTimeout = 2;
+ std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+ int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
+ kGnssSvInfoListTimeout);
+
+ ASSERT_EQ(count, sv_info_list_cbq_size);
+
+ BlocklistedSource source_to_blocklist =
+ FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+
+ if (source_to_blocklist.constellation == GnssConstellationTypeAidl::UNKNOWN) {
+ // Cannot find a non-GPS satellite. Let the test pass.
+ ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
+ return;
+ }
+
+ // Stop locations, blocklist the common SV
+ StopAndClearLocations();
+
+ sp<IGnssConfiguration> gnss_configuration_hal;
+ auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ std::vector<BlocklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blocklist;
+
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+
+ // retry and ensure satellite not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // early exit if test is being run with insufficient signal
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+ }
+ ASSERT_TRUE(location_called_count > 0);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
+ (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clear blocklist and restart - this time updating the blocklist while location is still on
+ sources.resize(0);
+
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+
+ bool strongest_sv_is_reobserved = false;
+ // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+ int unblocklist_loops_remaining = kRetriesToUnBlocklist;
+ while (!strongest_sv_is_reobserved && (unblocklist_loops_remaining-- > 0)) {
+ StopAndClearLocations();
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // early exit loop if test is being run with insufficient signal
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+ }
+ ASSERT_TRUE(location_called_count > 0);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Clear blocklist, observed %d GnssSvInfo, while awaiting %d Locations"
+ ", tries remaining %d",
+ sv_info_list_cbq_size, kLocationsToAwait, unblocklist_loops_remaining);
+
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ 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.svid == source_to_blocklist.svid) &&
+ (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
+ strongest_sv_is_reobserved = true;
+ break;
+ }
+ }
+ if (strongest_sv_is_reobserved) break;
+ }
+ }
+ EXPECT_TRUE(strongest_sv_is_reobserved);
+ StopAndClearLocations();
+}
+
+/*
+ * BlocklistConstellationLocationOff:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blocklist first non-GPS constellations.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blocklist.
+ */
+TEST_P(GnssHalTest, BlocklistConstellationLocationOff) {
+ if (!(aidl_gnss_cb_->last_capabilities_ &
+ (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+ ALOGI("Test BlocklistConstellationLocationOff skipped. SATELLITE_BLOCKLIST capability not "
+ "supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+ const int kGnssSvInfoListTimeout = 2;
+
+ // Find first non-GPS constellation to blocklist
+ GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+
+ // Turns off location
+ StopAndClearLocations();
+
+ BlocklistedSource source_to_blocklist_1;
+ source_to_blocklist_1.constellation = constellation_to_blocklist;
+ source_to_blocklist_1.svid = 0; // documented wildcard for all satellites in this constellation
+
+ // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
+ // supported.
+ BlocklistedSource source_to_blocklist_2;
+ source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
+ source_to_blocklist_2.svid = 0; // documented wildcard for all satellites in this constellation
+
+ sp<IGnssConfiguration> gnss_configuration_hal;
+ auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<BlocklistedSource> sources;
+ sources.resize(2);
+ sources[0] = source_to_blocklist_1;
+ sources[1] = source_to_blocklist_2;
+
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+
+ // retry and ensure constellation not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+ kLocationsToAwait);
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist_1.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist_2.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * BlocklistConstellationLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blocklist first non-GPS constellation, and turn off location.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blocklist.
+ */
+TEST_P(GnssHalTest, BlocklistConstellationLocationOn) {
+ if (!(aidl_gnss_cb_->last_capabilities_ &
+ (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+ ALOGI("Test BlocklistConstellationLocationOn skipped. SATELLITE_BLOCKLIST capability not "
+ "supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+ const int kGnssSvInfoListTimeout = 2;
+
+ // Find first non-GPS constellation to blocklist
+ GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+
+ BlocklistedSource source_to_blocklist_1;
+ source_to_blocklist_1.constellation = constellation_to_blocklist;
+ source_to_blocklist_1.svid = 0; // documented wildcard for all satellites in this constellation
+
+ // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
+ // supported.
+ BlocklistedSource source_to_blocklist_2;
+ source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
+ source_to_blocklist_2.svid = 0; // documented wildcard for all satellites in this constellation
+
+ sp<IGnssConfiguration> gnss_configuration_hal;
+ auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<BlocklistedSource> sources;
+ sources.resize(2);
+ sources[0] = source_to_blocklist_1;
+ sources[1] = source_to_blocklist_2;
+
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+
+ // Turns off location
+ StopAndClearLocations();
+
+ // retry and ensure constellation not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+ kLocationsToAwait);
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist_1.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+ source_to_blocklist_2.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ status = gnss_configuration_hal->setBlocklist(sources);
+ ASSERT_TRUE(status.isOk());
+}
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 577f6ae..730de4b 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -24,7 +24,14 @@
"-Werror",
],
srcs: [
+ "v2_1/GnssAntennaInfo.cpp",
+ "v2_1/GnssConfiguration.cpp",
+ "v2_1/GnssDebug.cpp",
+ "v2_1/GnssMeasurement.cpp",
+ "v2_1/GnssMeasurementCorrections.cpp",
+ "MockLocation.cpp",
"Utils.cpp",
+ "NmeaFixInfo.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
@@ -33,5 +40,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@2.0",
"android.hardware.gnss@2.1",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.measurement_corrections@1.0",
],
}
diff --git a/gnss/common/utils/default/MockLocation.cpp b/gnss/common/utils/default/MockLocation.cpp
new file mode 100644
index 0000000..2d8e7c5
--- /dev/null
+++ b/gnss/common/utils/default/MockLocation.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 "MockLocation.h"
+
+namespace android::hardware::gnss::common {
+
+float gMockLatitudeDegrees{37.4219999};
+float gMockLongitudeDegrees{-122.0840575};
+float gMockAltitudeMeters{1.60062531};
+
+} // namespace android::hardware::gnss::common
diff --git a/gnss/common/utils/default/NmeaFixInfo.cpp b/gnss/common/utils/default/NmeaFixInfo.cpp
new file mode 100644
index 0000000..43e008b
--- /dev/null
+++ b/gnss/common/utils/default/NmeaFixInfo.cpp
@@ -0,0 +1,266 @@
+/*
+ * 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 "NmeaFixInfo"
+
+#include <Constants.h>
+#include <NmeaFixInfo.h>
+#include <Utils.h>
+#include <log/log.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/SystemClock.h>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+NmeaFixInfo::NmeaFixInfo() : hasGMCRecord(false), hasGGARecord(false) {}
+
+float NmeaFixInfo::getAltitudeMeters() const {
+ return altitudeMeters;
+}
+
+float NmeaFixInfo::checkAndConvertToFloat(const std::string& sentence) {
+ if (sentence.empty()) {
+ return std::numeric_limits<float>::quiet_NaN();
+ }
+ return std::stof(sentence);
+}
+
+float NmeaFixInfo::getBearingAccuracyDegrees() const {
+ // Current NMEA doesn't contains beaing accuracy inforamtion
+ return kMockBearingAccuracyDegrees;
+}
+float NmeaFixInfo::getBearingDegrees() const {
+ return bearingDegrees;
+}
+
+float NmeaFixInfo::getHorizontalAccuracyMeters() const {
+ // Current NMEA doesn't contains horizontal accuracy inforamtion
+ return kMockHorizontalAccuracyMeters;
+}
+
+float NmeaFixInfo::getLatDeg() const {
+ return latDeg;
+}
+
+float NmeaFixInfo::getLngDeg() const {
+ return lngDeg;
+}
+
+float NmeaFixInfo::getSpeedAccuracyMetersPerSecond() const {
+ // Current NMEA doesn't contains speed accuracy inforamtion
+ return kMockSpeedAccuracyMetersPerSecond;
+}
+
+float NmeaFixInfo::getSpeedMetersPerSec() const {
+ return speedMetersPerSec;
+}
+
+int64_t NmeaFixInfo::getTimestamp() const {
+ return timestamp;
+}
+
+float NmeaFixInfo::getVerticalAccuracyMeters() const {
+ // Current NMEA doesn't contains vertical accuracy inforamtion
+ return kMockVerticalAccuracyMeters;
+}
+
+int64_t NmeaFixInfo::nmeaPartsToTimestamp(const std::string& timeStr, const std::string& dateStr) {
+ /**
+ * In NMEA format, the full time can only get from the $GPRMC record, see
+ * the following example:
+ * $GPRMC,213204.00,A,3725.371240,N,12205.589239,W,000.0,000.0,290819,,,A*49
+ * the datetime is stored in two parts, 213204 and 290819, which means
+ * 2019/08/29 21:32:04, however for in unix the year starts from 1900, we
+ * need to add the offset.
+ */
+ struct tm tm;
+ const int32_t unixYearOffset = 100;
+ tm.tm_mday = std::stoi(dateStr.substr(0, 2).c_str());
+ tm.tm_mon = std::stoi(dateStr.substr(2, 2).c_str()) - 1;
+ tm.tm_year = std::stoi(dateStr.substr(4, 2).c_str()) + unixYearOffset;
+ tm.tm_hour = std::stoi(timeStr.substr(0, 2).c_str());
+ tm.tm_min = std::stoi(timeStr.substr(2, 2).c_str());
+ tm.tm_sec = std::stoi(timeStr.substr(4, 2).c_str());
+ return static_cast<int64_t>(mktime(&tm) - timezone);
+}
+
+bool NmeaFixInfo::isValidFix() const {
+ return hasGMCRecord && hasGGARecord;
+}
+
+void NmeaFixInfo::parseGGALine(const std::vector<std::string>& sentenceValues) {
+ if (sentenceValues.size() == 0 || sentenceValues[0].compare(GPGA_RECORD_TAG) != 0) {
+ return;
+ }
+ // LatDeg, need covert to degree, if it is 'N', should be negative value
+ this->latDeg = std::stof(sentenceValues[2].substr(0, 2)) +
+ (std::stof(sentenceValues[2].substr(2)) / 60.0);
+ if (sentenceValues[3].compare("N") != 0) {
+ this->latDeg *= -1;
+ }
+
+ // LngDeg, need covert to degree, if it is 'E', should be negative value
+ this->lngDeg = std::stof(sentenceValues[4].substr(0, 3)) +
+ std::stof(sentenceValues[4].substr(3)) / 60.0;
+ if (sentenceValues[5].compare("E") != 0) {
+ this->lngDeg *= -1;
+ }
+
+ this->altitudeMeters = std::stof(sentenceValues[9]);
+
+ this->hDop = sentenceValues[8].empty() ? std::numeric_limits<float>::quiet_NaN()
+ : std::stof(sentenceValues[8]);
+ this->hasGGARecord = true;
+}
+
+void NmeaFixInfo::parseRMCLine(const std::vector<std::string>& sentenceValues) {
+ if (sentenceValues.size() == 0 || sentenceValues[0].compare(GPRMC_RECORD_TAG) != 0) {
+ return;
+ }
+ this->speedMetersPerSec = checkAndConvertToFloat(sentenceValues[7]);
+ this->bearingDegrees = checkAndConvertToFloat(sentenceValues[8]);
+ this->timestamp = nmeaPartsToTimestamp(sentenceValues[1], sentenceValues[9]);
+ this->hasGMCRecord = true;
+}
+
+/** invalid the current NmeaFixInfo */
+void NmeaFixInfo::reset() {
+ this->altitudeMeters = 0;
+ this->bearingDegrees = 0;
+ this->fixId = 0;
+ this->hasGMCRecord = false;
+ this->hasGGARecord = false;
+ this->latDeg = 0;
+ this->lngDeg = 0;
+ this->hDop = 0;
+ this->vDop = 0;
+ this->satelliteCount = 0;
+ this->speedMetersPerSec = 0;
+ this->timestamp = 0;
+}
+
+void NmeaFixInfo::splitStr(const std::string& line, const char& delimiter,
+ std::vector<std::string>& out) {
+ std::istringstream iss(line);
+ std::string item;
+ while (std::getline(iss, item, delimiter)) {
+ out.push_back(item);
+ }
+}
+
+NmeaFixInfo& NmeaFixInfo::operator=(const NmeaFixInfo& rhs) {
+ if (this == &rhs) return *this;
+ this->altitudeMeters = rhs.altitudeMeters;
+ this->bearingDegrees = rhs.bearingDegrees;
+ this->fixId = rhs.fixId;
+ this->hasGMCRecord = rhs.hasGMCRecord;
+ this->hasGGARecord = rhs.hasGGARecord;
+ this->hDop = rhs.hDop;
+ this->vDop = rhs.vDop;
+ this->latDeg = rhs.latDeg;
+ this->lngDeg = rhs.lngDeg;
+ this->satelliteCount = rhs.satelliteCount;
+ this->speedMetersPerSec = rhs.speedMetersPerSec;
+ this->timestamp = rhs.timestamp;
+
+ return *this;
+}
+
+/**
+ * Parses the input string in NMEA format and convert to GnssLocation.
+ * Currently version only cares about $GPGGA and $GPRMC records. but we
+ * can easily extend to other types supported by NMEA if needed.
+ */
+std::unique_ptr<V2_0::GnssLocation> NmeaFixInfo::getLocationFromInputStr(
+ const std::string& inputStr) {
+ std::vector<std::string> nmeaRecords;
+ splitStr(inputStr, LINE_SEPARATOR, nmeaRecords);
+ NmeaFixInfo nmeaFixInfo;
+ NmeaFixInfo candidateFixInfo;
+ uint32_t fixId = 0;
+ double lastTimeStamp = 0;
+ for (const auto& line : nmeaRecords) {
+ std::vector<std::string> sentenceValues;
+ splitStr(line, COMMA_SEPARATOR, sentenceValues);
+ double currentTimeStamp = std::stof(sentenceValues[1]);
+ // If see a new timestamp, report correct location.
+ if ((currentTimeStamp - lastTimeStamp) > TIMESTAMP_EPSILON &&
+ candidateFixInfo.isValidFix()) {
+ nmeaFixInfo = candidateFixInfo;
+ candidateFixInfo.reset();
+ fixId++;
+ }
+ if (line.compare(0, strlen(GPGA_RECORD_TAG), GPGA_RECORD_TAG) == 0) {
+ candidateFixInfo.fixId = fixId;
+ candidateFixInfo.parseGGALine(sentenceValues);
+ } else if (line.compare(0, strlen(GPRMC_RECORD_TAG), GPRMC_RECORD_TAG) == 0) {
+ candidateFixInfo.parseRMCLine(sentenceValues);
+ }
+ }
+ if (candidateFixInfo.isValidFix()) {
+ nmeaFixInfo = candidateFixInfo;
+ candidateFixInfo.reset();
+ }
+ if (!nmeaFixInfo.isValidFix()) {
+ return nullptr;
+ }
+ return nmeaFixInfo.toGnssLocation();
+}
+
+/**
+ * Parses the input string in NMEA format and convert to GnssLocation.
+ */
+std::unique_ptr<V2_0::GnssLocation> NmeaFixInfo::toGnssLocation() const {
+ const V2_0::ElapsedRealtime currentOsTimestamp = {
+ .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+ V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = static_cast<uint64_t>(::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};
+
+ V1_0::GnssLocation locationV1 = {
+ .gnssLocationFlags = 0xFF,
+ .latitudeDegrees = this->getLatDeg(),
+ .longitudeDegrees = this->getLngDeg(),
+ .altitudeMeters = this->getAltitudeMeters(),
+ .speedMetersPerSec = this->getSpeedMetersPerSec(),
+ .bearingDegrees = this->getBearingDegrees(),
+ .horizontalAccuracyMeters = this->getHorizontalAccuracyMeters(),
+ .verticalAccuracyMeters = this->getVerticalAccuracyMeters(),
+ .speedAccuracyMetersPerSecond = this->getSpeedAccuracyMetersPerSecond(),
+ .bearingAccuracyDegrees = this->getBearingAccuracyDegrees(),
+ .timestamp = this->getTimestamp()};
+
+ V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = currentOsTimestamp};
+
+ return std::make_unique<V2_0::GnssLocation>(locationV2);
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 386090e..fa83634 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -15,6 +15,7 @@
*/
#include <Constants.h>
+#include <MockLocation.h>
#include <Utils.h>
#include <utils/SystemClock.h>
@@ -141,9 +142,9 @@
V1_0::GnssLocation Utils::getMockLocationV1_0() {
V1_0::GnssLocation location = {
.gnssLocationFlags = 0xFF,
- .latitudeDegrees = kMockLatitudeDegrees,
- .longitudeDegrees = kMockLongitudeDegrees,
- .altitudeMeters = kMockAltitudeMeters,
+ .latitudeDegrees = gMockLatitudeDegrees,
+ .longitudeDegrees = gMockLongitudeDegrees,
+ .altitudeMeters = gMockAltitudeMeters,
.speedMetersPerSec = kMockSpeedMetersPerSec,
.bearingDegrees = kMockBearingDegrees,
.horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h
index 000a9ec..ad4e0eb 100644
--- a/gnss/common/utils/default/include/Constants.h
+++ b/gnss/common/utils/default/include/Constants.h
@@ -24,9 +24,6 @@
namespace gnss {
namespace common {
-const float kMockLatitudeDegrees = 37.4219999;
-const float kMockLongitudeDegrees = -122.0840575;
-const float kMockAltitudeMeters = 1.60062531;
const float kMockSpeedMetersPerSec = 0;
const float kMockBearingDegrees = 0;
const float kMockHorizontalAccuracyMeters = 5;
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp b/gnss/common/utils/default/include/MockLocation.h
similarity index 60%
copy from wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
copy to gnss/common/utils/default/include/MockLocation.h
index b1fa432..cd8cb5d 100644
--- a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
+++ b/gnss/common/utils/default/include/MockLocation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 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.
@@ -14,22 +14,23 @@
* limitations under the License.
*/
-#include <gmock/gmock.h>
+#ifndef android_hardware_gnss_common_MockLocation_H_
+#define android_hardware_gnss_common_MockLocation_H_
-#include "mock_wifi_feature_flags.h"
+#include <cstdint>
namespace android {
namespace hardware {
-namespace wifi {
-namespace V1_4 {
-namespace implementation {
-namespace feature_flags {
+namespace gnss {
+namespace common {
-MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+extern float gMockLatitudeDegrees;
+extern float gMockLongitudeDegrees;
+extern float gMockAltitudeMeters;
-} // namespace feature_flags
-} // namespace implementation
-} // namespace V1_4
-} // namespace wifi
+} // namespace common
+} // namespace gnss
} // namespace hardware
} // namespace android
+
+#endif // android_hardware_gnss_common_MockLocation_H_
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
new file mode 100644
index 0000000..fb2c1a4
--- /dev/null
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -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.
+ */
+
+#pragma once
+
+#include <Constants.h>
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <hidl/Status.h>
+#include <ctime>
+#include <string>
+namespace android {
+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";
+constexpr char LINE_SEPARATOR = '\n';
+constexpr char COMMA_SEPARATOR = ',';
+constexpr double TIMESTAMP_EPSILON = 0.001;
+
+/** Helper class to parse and store the GNSS fix details information. */
+class NmeaFixInfo {
+ private:
+ float altitudeMeters;
+ float bearingDegrees;
+ uint32_t fixId;
+ bool hasGMCRecord;
+ bool hasGGARecord;
+ float hDop;
+ float vDop;
+ float latDeg;
+ float lngDeg;
+ uint32_t satelliteCount;
+ float speedMetersPerSec;
+ int64_t timestamp;
+
+ public:
+ static std::unique_ptr<V2_0::GnssLocation> getLocationFromInputStr(const std::string& inputStr);
+
+ private:
+ static void splitStr(const std::string& line, const char& delimiter,
+ std::vector<std::string>& out);
+ static float checkAndConvertToFloat(const std::string& sentence);
+ static int64_t nmeaPartsToTimestamp(const std::string& timeStr, const std::string& dateStr);
+
+ NmeaFixInfo();
+ void parseGGALine(const std::vector<std::string>& sentenceValues);
+ void parseRMCLine(const std::vector<std::string>& sentenceValues);
+ std::unique_ptr<V2_0::GnssLocation> toGnssLocation() const;
+
+ // Getters
+ float getAltitudeMeters() const;
+ float getBearingAccuracyDegrees() const;
+ float getBearingDegrees() const;
+ uint32_t getFixId() const;
+ float getHorizontalAccuracyMeters() const;
+ float getLatDeg() const;
+ float getLngDeg() const;
+ float getSpeedAccuracyMetersPerSecond() const;
+ float getSpeedMetersPerSec() const;
+ int64_t getTimestamp() const;
+ float getVerticalAccuracyMeters() const;
+
+ bool isValidFix() const;
+ void reset();
+ NmeaFixInfo& operator=(const NmeaFixInfo& rhs);
+};
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
similarity index 79%
rename from gnss/2.1/default/GnssAntennaInfo.h
rename to gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
index 94b2111..e74ff54 100644
--- a/gnss/2.1/default/GnssAntennaInfo.h
+++ b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
@@ -14,23 +14,20 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
-#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+#pragma once
#include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
#include <mutex>
#include <thread>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+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 {
GnssAntennaInfo();
@@ -58,10 +55,4 @@
mutable std::mutex mMutex;
};
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
similarity index 89%
rename from gnss/2.1/default/GnssConfiguration.h
rename to gnss/common/utils/default/include/v2_1/GnssConfiguration.h
index 662d61d..8463a5c 100644
--- a/gnss/2.1/default/GnssConfiguration.h
+++ b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
-#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+#pragma once
#include <android/hardware/gnss/2.1/IGnssCallback.h>
#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
@@ -24,11 +23,7 @@
#include <mutex>
#include <unordered_set>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
@@ -92,10 +87,4 @@
BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet;
};
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssDebug.h b/gnss/common/utils/default/include/v2_1/GnssDebug.h
similarity index 76%
rename from gnss/2.1/default/GnssDebug.h
rename to gnss/common/utils/default/include/v2_1/GnssDebug.h
index 969d337..8580989 100644
--- a/gnss/2.1/default/GnssDebug.h
+++ b/gnss/common/utils/default/include/v2_1/GnssDebug.h
@@ -14,17 +14,12 @@
* limitations under the License.
*/
-#ifndef android_hardware_gnss_V1_1_GnssDebug_H_
-#define android_hardware_gnss_V1_1_GnssDebug_H_
+#pragma once
#include <android/hardware/gnss/1.0/IGnssDebug.h>
#include <hidl/Status.h>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::V1_1::implementation {
using ::android::sp;
using ::android::hardware::hidl_string;
@@ -42,10 +37,4 @@
Return<void> getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) override;
};
-} // namespace implementation
-} // namespace V1_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
-
-#endif // android_hardware_gnss_V1_1_GnssDebug_H_
+} // namespace android::hardware::gnss::V1_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
similarity index 91%
rename from gnss/2.1/default/GnssMeasurement.h
rename to gnss/common/utils/default/include/v2_1/GnssMeasurement.h
index d446419..1d1fc9d 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
@@ -23,11 +23,7 @@
#include <mutex>
#include <thread>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
@@ -80,8 +76,4 @@
mutable std::mutex mMutex;
};
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
similarity index 72%
rename from gnss/2.1/default/GnssMeasurementCorrections.h
rename to gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
index 036e855..eaa7659 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
@@ -20,22 +20,15 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace measurement_corrections {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::measurement_corrections::V1_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;
struct GnssMeasurementCorrections : public IMeasurementCorrections {
+ GnssMeasurementCorrections();
+ ~GnssMeasurementCorrections();
+
// Methods from V1_0::IMeasurementCorrections follow.
Return<bool> setCorrections(const V1_0::MeasurementCorrections& corrections) override;
Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
@@ -44,9 +37,4 @@
Return<bool> setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override;
};
-} // namespace implementation
-} // namespace V1_1
-} // namespace measurement_corrections
-} // namespace gnss
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::gnss::measurement_corrections::V1_1::implementation
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
new file mode 100644
index 0000000..7c3c58a
--- /dev/null
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -0,0 +1,703 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+#include <sys/epoll.h>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "GnssAntennaInfo.h"
+#include "GnssConfiguration.h"
+#include "GnssDebug.h"
+#include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
+#include "MockLocation.h"
+#include "NmeaFixInfo.h"
+#include "Utils.h"
+
+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";
+
+template <class T_IGnss>
+struct GnssTemplate : public T_IGnss {
+ GnssTemplate();
+ ~GnssTemplate();
+ // Methods from V1_0::IGnss follow.
+ Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+ Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+ Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+ Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
+ Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+ Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+ // Methods from V1_1::IGnss follow.
+ Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+ Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) override;
+ Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+ Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+ Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
+
+ // Methods from V2_0::IGnss follow.
+ Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+ Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+ Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+ Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+ Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+ Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+ Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections() override;
+ Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
+ override;
+ Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+ Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
+
+ // Methods from V2_1::IGnss follow.
+ Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
+ Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
+ Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
+ Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections_1_1() override;
+ Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
+
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+ private:
+ 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;
+
+ Return<void> help(const hidl_handle& fd);
+ Return<void> setLocation(const hidl_handle& fd, const hidl_vec<hidl_string>& options);
+
+ static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
+ static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
+ static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
+ static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
+
+ std::atomic<long> mMinIntervalMs;
+ sp<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);
+};
+
+template <class T_IGnss>
+sp<V2_1::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_2_1 = nullptr;
+template <class T_IGnss>
+sp<V2_0::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_2_0 = nullptr;
+template <class T_IGnss>
+sp<V1_1::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_1_1 = nullptr;
+template <class T_IGnss>
+sp<V1_0::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_1_0 = nullptr;
+
+template <class T_IGnss>
+GnssTemplate<T_IGnss>::GnssTemplate()
+ : mMinIntervalMs(1000),
+ mGnssConfiguration{new GnssConfiguration()},
+ mHardwareModeChecked(false),
+ mGnssFd(-1) {}
+
+template <class T_IGnss>
+GnssTemplate<T_IGnss>::~GnssTemplate() {
+ stop();
+}
+
+template <class T_IGnss>
+std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
+ char inputBuffer[INPUT_BUFFER_SIZE];
+ if (!mHardwareModeChecked) {
+ mGnssFd = open(GNSS_PATH, O_RDWR | O_NONBLOCK);
+ if (mGnssFd == -1) {
+ ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
+ }
+ mHardwareModeChecked = true;
+ }
+
+ if (mGnssFd == -1) {
+ return nullptr;
+ }
+
+ int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION));
+ if (bytes_write <= 0) {
+ return nullptr;
+ }
+
+ struct epoll_event ev, events[1];
+ ev.data.fd = mGnssFd;
+ ev.events = EPOLLIN;
+ int epoll_fd = epoll_create1(0);
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev);
+ int bytes_read = -1;
+ std::string inputStr = "";
+ int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs);
+
+ if (epoll_ret == -1) {
+ return nullptr;
+ }
+ while (true) {
+ bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
+ if (bytes_read <= 0) {
+ break;
+ }
+ inputStr += std::string(inputBuffer, bytes_read);
+ }
+ return NmeaFixInfo::getLocationFromInputStr(inputStr);
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::start() {
+ if (mIsActive) {
+ ALOGW("Gnss has started. Restarting...");
+ stop();
+ }
+
+ mIsActive = true;
+ mThread = std::thread([this]() {
+ while (mIsActive == true) {
+ auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
+ this->reportSvStatus(svStatus);
+ auto currentLocation = getLocationFromHW();
+ if (mGnssFd != -1 && currentLocation != nullptr) {
+ // Only report location if the return from hardware is valid
+ this->reportLocation(*currentLocation);
+ } else {
+ if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
+ const auto location = Utils::getMockLocationV2_0();
+ this->reportLocation(location);
+ } else {
+ const auto location = Utils::getMockLocationV1_0();
+ this->reportLocation(location);
+ }
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+ }
+ });
+ return true;
+}
+
+template <class T_IGnss>
+hidl_vec<GnssSvInfo> GnssTemplate<T_IGnss>::filterBlocklistedSatellitesV2_1(
+ hidl_vec<GnssSvInfo> gnssSvInfoList) {
+ ALOGD("filterBlocklistedSatellitesV2_1");
+ for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+ if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
+ gnssSvInfoList[i].v2_0.v1_0.svFlag &=
+ ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+ }
+ }
+ return gnssSvInfoList;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::stop() {
+ ALOGD("stop");
+ mIsActive = false;
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+ if (mGnssFd != -1) {
+ close(mGnssFd);
+ mGnssFd = -1;
+ }
+ return true;
+}
+
+// Methods from V1_0::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_1_0 = callback;
+
+ uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
+ V1_0::IGnssCallback::Capabilities::SCHEDULING;
+ auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+ ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::cleanup() {
+ sGnssCallback_2_1 = nullptr;
+ sGnssCallback_2_0 = nullptr;
+ return Void();
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectTime(int64_t, int64_t, int32_t) {
+ return true;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectLocation(double, double, float) {
+ return true;
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::deleteAidingData(V1_0::IGnss::GnssAidingData) {
+ // TODO implement
+ return Void();
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setPositionMode(V1_0::IGnss::GnssPositionMode,
+ V1_0::IGnss::GnssPositionRecurrence,
+ uint32_t minIntervalMs, uint32_t, uint32_t) {
+ mMinIntervalMs = minIntervalMs;
+ return true;
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IAGnssRil>> GnssTemplate<T_IGnss>::getExtensionAGnssRil() {
+ // TODO implement
+ return ::android::sp<V1_0::IAGnssRil>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssGeofencing>> GnssTemplate<T_IGnss>::getExtensionGnssGeofencing() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssGeofencing>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IAGnss>> GnssTemplate<T_IGnss>::getExtensionAGnss() {
+ // TODO implement
+ return ::android::sp<V1_0::IAGnss>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssNi>> GnssTemplate<T_IGnss>::getExtensionGnssNi() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssNi>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement() {
+ ALOGD("Gnss::getExtensionGnssMeasurement");
+ return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssNavigationMessage>>
+GnssTemplate<T_IGnss>::getExtensionGnssNavigationMessage() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssNavigationMessage>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssXtra>> GnssTemplate<T_IGnss>::getExtensionXtra() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssXtra>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssConfiguration>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssDebug>> GnssTemplate<T_IGnss>::getExtensionGnssDebug() {
+ return new V1_1::implementation::GnssDebug();
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssBatching>> GnssTemplate<T_IGnss>::getExtensionGnssBatching() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssBatching>{};
+}
+
+// Methods from V1_1::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_1_1 = callback;
+
+ uint32_t capabilities = 0x0;
+ auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+ ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Google Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_1_1->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
+ V1_0::IGnss::GnssPositionRecurrence,
+ uint32_t minIntervalMs, uint32_t, uint32_t,
+ bool) {
+ mMinIntervalMs = minIntervalMs;
+ return true;
+}
+
+template <class T_IGnss>
+Return<sp<V1_1::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_1_1() {
+ // TODO implement
+ return ::android::sp<V1_1::IGnssConfiguration>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_1::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_1_1() {
+ // TODO implement
+ return ::android::sp<V1_1::IGnssMeasurement>{};
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectBestLocation(const V1_0::GnssLocation&) {
+ return true;
+}
+
+// Methods from V2_0::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+ ALOGD("Gnss::setCallback_2_0");
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_2_0 = callback;
+
+ using Capabilities = V2_0::IGnssCallback::Capabilities;
+ const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+ Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
+ auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
+
+ ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Google Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_2_0->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_2_0() {
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
+ return mGnssConfiguration;
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssDebug>> GnssTemplate<T_IGnss>::getExtensionGnssDebug_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IGnssDebug>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IAGnss>> GnssTemplate<T_IGnss>::getExtensionAGnss_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IAGnss>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IAGnssRil>> GnssTemplate<T_IGnss>::getExtensionAGnssRil_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IAGnssRil>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_0() {
+ ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+ return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections() {
+ ALOGD("Gnss::getExtensionMeasurementCorrections()");
+ return new GnssMeasurementCorrections();
+}
+
+template <class T_IGnss>
+Return<sp<visibility_control::V1_0::IGnssVisibilityControl>>
+GnssTemplate<T_IGnss>::getExtensionVisibilityControl() {
+ // TODO implement
+ return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssBatching>> GnssTemplate<T_IGnss>::getExtensionGnssBatching_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IGnssBatching>{};
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectBestLocation_2_0(const V2_0::GnssLocation&) {
+ // TODO(b/124012850): Implement function.
+ return bool{};
+}
+
+// Methods from V2_1::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
+ ALOGD("Gnss::setCallback_2_1");
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_2_1 = callback;
+
+ using Capabilities = V2_1::IGnssCallback::Capabilities;
+ const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+ Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST |
+ Capabilities::ANTENNA_INFO;
+ auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
+
+ ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Android Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_2_1->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_1() {
+ ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
+ return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_2_1() {
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
+ return mGnssConfiguration;
+}
+
+template <class T_IGnss>
+Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections_1_1() {
+ ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
+ return new GnssMeasurementCorrections();
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssAntennaInfo>> GnssTemplate<T_IGnss>::getExtensionGnssAntennaInfo() {
+ ALOGD("Gnss::getExtensionGnssAntennaInfo");
+ return new GnssAntennaInfo();
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportSvStatus(const hidl_vec<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) {
+ ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportLocation(const V1_0::GnssLocation& location) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sGnssCallback_1_1 != nullptr) {
+ auto ret = sGnssCallback_1_1->gnssLocationCb(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v1.1", __func__);
+ }
+ return;
+ }
+ if (sGnssCallback_1_0 == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_1_0->gnssLocationCb(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v1.0", __func__);
+ }
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportLocation(const V2_0::GnssLocation& location) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sGnssCallback_2_1 != nullptr) {
+ auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v2.1", __func__);
+ }
+ return;
+ }
+ if (sGnssCallback_2_0 == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v2.0", __func__);
+ }
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::setLocation(const hidl_handle& fd,
+ const hidl_vec<hidl_string>& options) {
+ auto lat = gMockLatitudeDegrees;
+ auto lon = gMockLongitudeDegrees;
+ auto ele = gMockAltitudeMeters;
+
+ for (size_t i = 1; i < options.size(); ++i) {
+ std::string option = options[i];
+ if (option.rfind("lat=", 0) == 0) {
+ option = option.substr(4);
+ lat = stof(option);
+ } else if (option.rfind("lon=", 0) == 0) {
+ option = option.substr(4);
+ lon = stof(option);
+ } else if (option.rfind("ele=", 0) == 0) {
+ option = option.substr(4);
+ ele = stof(option);
+ } else {
+ dprintf(fd->data[0], "unsupported location argument: %s\n", option.c_str());
+ }
+ }
+
+ gMockLatitudeDegrees = lat;
+ gMockLongitudeDegrees = lon;
+ gMockAltitudeMeters = ele;
+
+ dprintf(fd->data[0], "mock location updated to lat=%f lon=%f ele=%f\n", gMockLatitudeDegrees,
+ gMockLongitudeDegrees, gMockAltitudeMeters);
+
+ return Void();
+}
+
+template <class T_IGnss>
+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");
+ return Void();
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::debug(const hidl_handle& fd,
+ const hidl_vec<hidl_string>& options) {
+ if (options.size() == 0) {
+ return help(fd);
+ } else if (options[0] == "location") {
+ return setLocation(fd, options);
+ } else {
+ return help(fd);
+ }
+
+ return Void();
+}
+
+} // namespace android::hardware::gnss::common::implementation
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
similarity index 91%
rename from gnss/2.1/default/GnssAntennaInfo.cpp
rename to gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
index ed183a9..962451c 100644
--- a/gnss/2.1/default/GnssAntennaInfo.cpp
+++ b/gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
@@ -16,18 +16,14 @@
#define LOG_TAG "GnssAntennaInfo"
-#include "GnssAntennaInfo.h"
+#include "v2_1/GnssAntennaInfo.h"
#include "Utils.h"
#include <log/log.h>
using ::android::hardware::gnss::common::Utils;
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
sp<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
@@ -102,8 +98,4 @@
}
}
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
\ No newline at end of file
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
similarity index 92%
rename from gnss/2.1/default/GnssConfiguration.cpp
rename to gnss/common/utils/default/v2_1/GnssConfiguration.cpp
index cd8f07f..8b30701 100644
--- a/gnss/2.1/default/GnssConfiguration.cpp
+++ b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
@@ -16,14 +16,10 @@
#define LOG_TAG "GnssConfiguration"
-#include "GnssConfiguration.h"
+#include "v2_1/GnssConfiguration.h"
#include <log/log.h>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setSuplEs(bool enable) {
@@ -99,8 +95,4 @@
return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end());
}
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
\ No newline at end of file
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssDebug.cpp b/gnss/common/utils/default/v2_1/GnssDebug.cpp
similarity index 80%
rename from gnss/2.1/default/GnssDebug.cpp
rename to gnss/common/utils/default/v2_1/GnssDebug.cpp
index a9f7ded..d78b0b6 100644
--- a/gnss/2.1/default/GnssDebug.cpp
+++ b/gnss/common/utils/default/v2_1/GnssDebug.cpp
@@ -19,23 +19,20 @@
#include <log/log.h>
#include "Constants.h"
-#include "GnssDebug.h"
+#include "MockLocation.h"
+#include "v2_1/GnssDebug.h"
using namespace ::android::hardware::gnss::common;
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::V1_1::implementation {
// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
Return<void> GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) {
PositionDebug positionDebug = {
.valid = true,
- .latitudeDegrees = kMockLatitudeDegrees,
- .longitudeDegrees = kMockLongitudeDegrees,
- .altitudeMeters = kMockAltitudeMeters,
+ .latitudeDegrees = gMockLatitudeDegrees,
+ .longitudeDegrees = gMockLongitudeDegrees,
+ .altitudeMeters = gMockAltitudeMeters,
.speedMetersPerSec = kMockSpeedMetersPerSec,
.bearingDegrees = kMockBearingDegrees,
.horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
@@ -55,8 +52,4 @@
return Void();
}
-} // namespace implementation
-} // namespace V1_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::gnss::V1_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
similarity index 94%
rename from gnss/2.1/default/GnssMeasurement.cpp
rename to gnss/common/utils/default/v2_1/GnssMeasurement.cpp
index 63bbc0a..7d3a002 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
@@ -16,19 +16,14 @@
#define LOG_TAG "GnssMeasurement"
-#include "GnssMeasurement.h"
+#include "v2_1/GnssMeasurement.h"
#include <log/log.h>
#include "Utils.h"
-namespace android {
-namespace hardware {
-namespace gnss {
+namespace android::hardware::gnss::V2_1::implementation {
using common::Utils;
-namespace V2_1 {
-namespace implementation {
-
sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
@@ -145,8 +140,4 @@
}
}
-} // namespace implementation
-} // namespace V2_1
-} // namespace gnss
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
similarity index 93%
rename from gnss/2.1/default/GnssMeasurementCorrections.cpp
rename to gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
index accf62b..9be7e23 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.cpp
+++ b/gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
@@ -16,15 +16,14 @@
#define LOG_TAG "GnssMeasurementCorrections"
-#include "GnssMeasurementCorrections.h"
+#include "v2_1/GnssMeasurementCorrections.h"
#include <log/log.h>
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace measurement_corrections {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::measurement_corrections::V1_1::implementation {
+
+GnssMeasurementCorrections::GnssMeasurementCorrections() {}
+
+GnssMeasurementCorrections::~GnssMeasurementCorrections() {}
// Methods from V1_0::IMeasurementCorrections follow.
Return<bool> GnssMeasurementCorrections::setCorrections(
@@ -101,9 +100,4 @@
return true;
}
-} // namespace implementation
-} // namespace V1_1
-} // namespace measurement_corrections
-} // namespace gnss
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::gnss::measurement_corrections::V1_1::implementation
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 4c6d443..e36b656 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -25,11 +25,14 @@
],
srcs: [
"Utils.cpp",
+ "v2_1/GnssCallback.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
"android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.measurement_corrections@1.1",
],
diff --git a/gnss/common/utils/vts/include/v2_1/GnssCallback.h b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
new file mode 100644
index 0000000..ab1375d
--- /dev/null
+++ b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
@@ -0,0 +1,107 @@
+/*
+ * 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/2.1/IGnss.h>
+#include "GnssCallbackEventQueue.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+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 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 {
+
+/* Callback class for data & Event. */
+class GnssCallback : public IGnssCallback_2_1 {
+ public:
+ IGnssCallback_1_0::GnssSystemInfo last_info_;
+ android::hardware::hidl_string last_name_;
+ uint32_t last_capabilities_;
+ GnssLocation_2_0 last_location_;
+
+ GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+ GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
+
+ GnssCallback();
+ virtual ~GnssCallback() = default;
+
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override { return Void(); }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+ // Actual (test) callback handlers
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
+ Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
+
+ // New in v2.0
+ Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
+ Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
+ bool /* isUserEmergency */) override {
+ return Void();
+ }
+ Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+ Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
+ return Void();
+ }
+
+ // New in v2.1
+ Return<void> gnssSvStatusCb_2_1(
+ const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
+ Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
+
+ private:
+ Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
+};
+
+} // namespace android::hardware::gnss::common
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
new file mode 100644
index 0000000..1439158
--- /dev/null
+++ b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
@@ -0,0 +1,381 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "GnssCallbackEventQueue.h"
+#include "Utils.h"
+#include "v2_1/GnssCallback.h"
+
+#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
+
+// The main test class for GNSS HAL.
+template <class T_IGnss>
+class GnssHalTestTemplate : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override;
+
+ virtual void TearDown() override;
+
+ /* Callback class for GnssMeasurement. */
+ class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
+ public:
+ GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::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();
+ }
+
+ // Methods from V1_1::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+ return Void();
+ }
+
+ // Methods from V2_0::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
+ return Void();
+ }
+
+ // Methods from V2_1::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
+ };
+
+ /* Callback class for GnssMeasurementCorrections. */
+ class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ public:
+ uint32_t last_capabilities_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+
+ GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+ virtual ~GnssMeasurementCorrectionsCallback() = default;
+
+ // Methods from V1_0::IMeasurementCorrectionsCallback follow.
+ Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+ };
+
+ /* Callback class for GnssAntennaInfo. */
+ class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
+ public:
+ GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+ antenna_info_cbq_;
+
+ GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
+ virtual ~GnssAntennaInfoCallback() = default;
+
+ // Methods from V2_1::GnssAntennaInfoCallback follow.
+ Return<void> gnssAntennaInfoCb(
+ const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
+ };
+
+ /*
+ * SetUpGnssCallback:
+ * Set GnssCallback and verify the result.
+ */
+ virtual void SetUpGnssCallback();
+
+ /*
+ * StartAndCheckFirstLocation:
+ * Helper function to start location, and check the first one.
+ *
+ * <p> Note this leaves the Location request active, to enable Stop call vs. other call
+ * reordering tests.
+ *
+ * returns true if a location was successfully generated
+ */
+ bool StartAndCheckFirstLocation();
+
+ /*
+ * CheckLocation:
+ * Helper function to vet Location fields
+ *
+ * check_speed: true if speed related fields are also verified.
+ */
+ void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
+
+ /*
+ * StartAndCheckLocations:
+ * Helper function to collect, and check a number of
+ * normal ~1Hz locations.
+ *
+ * Note this leaves the Location request active, to enable Stop call vs. other call
+ * reordering tests.
+ */
+ void StartAndCheckLocations(int count);
+
+ /*
+ * StopAndClearLocations:
+ * Helper function to stop locations, and clear any remaining notifications
+ */
+ void StopAndClearLocations();
+
+ /*
+ * SetPositionMode:
+ * Helper function to set positioning mode and verify output
+ */
+ void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+
+ /*
+ * startLocationAndGetNonGpsConstellation:
+ * 1. Start location
+ * 2. Find and return first non-GPS constellation
+ *
+ * Note that location is not stopped in this method. The client should call
+ * StopAndClearLocations() after the call.
+ */
+ GnssConstellationType startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout);
+
+ sp<T_IGnss> gnss_hal_; // GNSS HAL to call into
+ sp<GnssCallback> gnss_cb_; // Primary callback interface
+};
+
+using ::android::hardware::gnss::common::Utils;
+
+// Implementations for the main test class for GNSS HAL
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetUp() {
+ gnss_hal_ = T_IGnss::getService(GetParam());
+ ASSERT_NE(gnss_hal_, nullptr);
+
+ SetUpGnssCallback();
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::TearDown() {
+ if (gnss_hal_ != nullptr) {
+ gnss_hal_->cleanup();
+ gnss_hal_ = nullptr;
+ }
+
+ // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+ gnss_cb_ = nullptr;
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetUpGnssCallback() {
+ gnss_cb_ = new GnssCallback();
+ ASSERT_NE(gnss_cb_, nullptr);
+
+ auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
+ if (!result.isOk()) {
+ ALOGE("result of failed setCallback %s", result.description().c_str());
+ }
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ /*
+ * All capabilities, name and systemInfo callbacks should trigger
+ */
+ EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
+
+ EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::StopAndClearLocations() {
+ const auto result = gnss_hal_->stop();
+
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ /*
+ * Clear notify/waiting counter, allowing up till the timeout after
+ * the last reply for final startup messages to arrive (esp. system
+ * info.)
+ */
+ while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
+ }
+ gnss_cb_->location_cbq_.reset();
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetPositionMode(const int min_interval_msec,
+ const bool low_power_mode) {
+ const int kPreferredAccuracy = 0; // Ideally perfect (matches GnssLocationProvider)
+ const int kPreferredTimeMsec = 0; // Ideally immediate
+
+ const auto result = gnss_hal_->setPositionMode_1_1(
+ T_IGnss::GnssPositionMode::MS_BASED,
+ T_IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, min_interval_msec,
+ kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
+
+template <class T_IGnss>
+bool GnssHalTestTemplate<T_IGnss>::StartAndCheckFirstLocation() {
+ const auto result = gnss_hal_->start();
+
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ /*
+ * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
+ * so allow time to demodulate ephemeris over the air.
+ */
+ const int kFirstGnssLocationTimeoutSeconds = 75;
+
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kFirstGnssLocationTimeoutSeconds));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, 1);
+
+ if (locationCalledCount > 0) {
+ // don't require speed on first fix
+ CheckLocation(gnss_cb_->last_location_, false);
+ return true;
+ }
+ return false;
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::CheckLocation(const GnssLocation_2_0& location,
+ bool check_speed) {
+ const bool check_more_accuracies =
+ (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
+
+ Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::StartAndCheckLocations(int count) {
+ const int kMinIntervalMsec = 500;
+ const int kLocationTimeoutSubsequentSec = 2;
+ const bool kLowPowerMode = false;
+
+ SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+ EXPECT_TRUE(StartAndCheckFirstLocation());
+
+ for (int i = 1; i < count; i++) {
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, i + 1);
+ // Don't cause confusion by checking details if no location yet
+ if (locationCalledCount > 0) {
+ // Should be more than 1 location by now, but if not, still don't check first fix speed
+ CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
+ }
+ }
+}
+
+template <class T_IGnss>
+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);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, locations_to_await, location_called_count);
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::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)) {
+ // found a non-GPS constellation
+ constellation_to_blacklist = gnss_sv.v2_0.constellation;
+ break;
+ }
+ }
+ if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+ break;
+ }
+ }
+
+ if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+ ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+ // Proceed functionally to blacklist something.
+ constellation_to_blacklist = GnssConstellationType::GLONASS;
+ }
+
+ return constellation_to_blacklist;
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssMeasurementCallback::gnssMeasurementCb_2_1(
+ const IGnssMeasurementCallback_2_1::GnssData& data) {
+ ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
+ measurement_cbq_.store(data);
+ return Void();
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
+ uint32_t capabilities) {
+ ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssAntennaInfoCallback::gnssAntennaInfoCb(
+ const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+ ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
+ antenna_info_cbq_.store(gnssAntennaInfos);
+ return Void();
+}
diff --git a/gnss/common/utils/vts/v2_1/GnssCallback.cpp b/gnss/common/utils/vts/v2_1/GnssCallback.cpp
new file mode 100644
index 0000000..3b96fb8
--- /dev/null
+++ b/gnss/common/utils/vts/v2_1/GnssCallback.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.
+ */
+
+#define LOG_TAG "GnssCallback"
+
+#include "v2_1/GnssCallback.h"
+#include <chrono>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+namespace android::hardware::gnss::common {
+
+GnssCallback::GnssCallback()
+ : info_cbq_("system_info"),
+ name_cbq_("name"),
+ capabilities_cbq_("capabilities"),
+ location_cbq_("location"),
+ sv_info_list_cbq_("sv_info") {}
+
+Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) {
+ ALOGI("Info received, year %d", info.yearOfHw);
+ info_cbq_.store(info);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+ ALOGI("Capabilities (v2.0) received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
+ ALOGI("Capabilities (v2.1) received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGI("Name received: %s", name.c_str());
+ name_cbq_.store(name);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
+ ALOGI("Location received");
+ GnssLocation_2_0 location_v2_0;
+ location_v2_0.v1_0 = location;
+ return gnssLocationCbImpl(location_v2_0);
+}
+
+Return<void> GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
+ ALOGI("Location (v2.0) received");
+ return gnssLocationCbImpl(location);
+}
+
+Return<void> GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
+ location_cbq_.store(location);
+ return Void();
+}
+
+Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
+ ALOGI("gnssSvStatusCb");
+ return Void();
+}
+
+Return<void> GnssCallback::gnssSvStatusCb_2_1(
+ const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+ ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
+ sv_info_list_cbq_.store(svInfoList);
+ return Void();
+}
+
+} // namespace android::hardware::gnss::common
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 47ead41..3d74af4 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -87,19 +87,28 @@
class HalEventCallback : public Hal::EventCallback {
public:
- HalEventCallback(const sp<IComposerCallback> callback, ComposerResources* resources)
- : mCallback(callback), mResources(resources) {}
+ HalEventCallback(Hal* hal, const sp<IComposerCallback> callback,
+ ComposerResources* resources)
+ : mHal(hal), mCallback(callback), mResources(resources) {}
- void onHotplug(Display display, IComposerCallback::Connection connected) {
- if (connected == IComposerCallback::Connection::CONNECTED) {
- mResources->addPhysicalDisplay(display);
- } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
- mResources->removeDisplay(display);
- }
+ void onHotplug(Display display, IComposerCallback::Connection connected) {
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ if (mResources->hasDisplay(display)) {
+ // This is a subsequent hotplug "connected" for a display. This signals a
+ // display change and thus the framework may want to reallocate buffers. We
+ // need to free all cached handles, since they are holding a strong reference
+ // to the underlying buffers.
+ cleanDisplayResources(display);
+ mResources->removeDisplay(display);
+ }
+ mResources->addPhysicalDisplay(display);
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mResources->removeDisplay(display);
+ }
- auto ret = mCallback->onHotplug(display, connected);
- ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
- }
+ auto ret = mCallback->onHotplug(display, connected);
+ ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
+ }
void onRefresh(Display display) {
mResources->setDisplayMustValidateState(display, true);
@@ -113,13 +122,64 @@
}
protected:
- const sp<IComposerCallback> mCallback;
- ComposerResources* const mResources;
+ Hal* const mHal;
+ const sp<IComposerCallback> mCallback;
+ ComposerResources* const mResources;
+
+ void cleanDisplayResources(Display display) {
+ size_t cacheSize;
+ Error err = mResources->getDisplayClientTargetCacheSize(display, &cacheSize);
+ if (err == Error::NONE) {
+ for (int slot = 0; slot < cacheSize; slot++) {
+ ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
+ // Replace the buffer slots with NULLs. Keep the old handle until it is
+ // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
+ const native_handle_t* clientTarget = nullptr;
+ err = mResources->getDisplayClientTarget(display, slot, /*useCache*/ true,
+ /*rawHandle*/ nullptr, &clientTarget,
+ &replacedBuffer);
+ if (err != Error::NONE) {
+ continue;
+ }
+ const std::vector<hwc_rect_t> damage;
+ err = mHal->setClientTarget(display, clientTarget, /*fence*/ -1, 0, damage);
+ ALOGE_IF(err != Error::NONE,
+ "Can't clean slot %d of the client target buffer"
+ "cache for display %" PRIu64,
+ slot, display);
+ }
+ } else {
+ ALOGE("Can't clean client target cache for display %" PRIu64, display);
+ }
+
+ err = mResources->getDisplayOutputBufferCacheSize(display, &cacheSize);
+ if (err == Error::NONE) {
+ for (int slot = 0; slot < cacheSize; slot++) {
+ // Replace the buffer slots with NULLs. Keep the old handle until it is
+ // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
+ ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
+ const native_handle_t* outputBuffer = nullptr;
+ err = mResources->getDisplayOutputBuffer(display, slot, /*useCache*/ true,
+ /*rawHandle*/ nullptr, &outputBuffer,
+ &replacedBuffer);
+ if (err != Error::NONE) {
+ continue;
+ }
+ err = mHal->setOutputBuffer(display, outputBuffer, /*fence*/ -1);
+ ALOGE_IF(err != Error::NONE,
+ "Can't clean slot %d of the output buffer cache"
+ "for display %" PRIu64,
+ slot, display);
+ }
+ } else {
+ ALOGE("Can't clean output buffer cache for display %" PRIu64, display);
+ }
+ }
};
Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
// no locking as we require this function to be called only once
- mHalEventCallback = std::make_unique<HalEventCallback>(callback, mResources.get());
+ mHalEventCallback = std::make_unique<HalEventCallback>(mHal, callback, mResources.get());
mHal->registerEventCallback(mHalEventCallback.get());
return Void();
}
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
index 21f6035..e52bf71 100644
--- a/graphics/composer/2.1/utils/resources/ComposerResources.cpp
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -144,6 +144,10 @@
}
}
+size_t ComposerHandleCache::getCacheSize() const {
+ return mHandles.size();
+}
+
bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) {
// already initialized
if (mHandleType != HandleType::INVALID) {
@@ -220,6 +224,14 @@
return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
}
+size_t ComposerDisplayResource::getClientTargetCacheSize() const {
+ return mClientTargetCache.getCacheSize();
+}
+
+size_t ComposerDisplayResource::getOutputBufferCacheSize() const {
+ return mOutputBufferCache.getCacheSize();
+}
+
bool ComposerDisplayResource::isVirtual() const {
return mType == DisplayType::VIRTUAL;
}
@@ -293,6 +305,10 @@
mDisplayResources.clear();
}
+bool ComposerResources::hasDisplay(Display display) {
+ return mDisplayResources.count(display) > 0;
+}
+
Error ComposerResources::addPhysicalDisplay(Display display) {
auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
@@ -327,6 +343,26 @@
: Error::BAD_PARAMETER;
}
+Error ComposerResources::getDisplayClientTargetCacheSize(Display display, size_t* outCacheSize) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+ *outCacheSize = displayResource->getClientTargetCacheSize();
+ return Error::NONE;
+}
+
+Error ComposerResources::getDisplayOutputBufferCacheSize(Display display, size_t* outCacheSize) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+ *outCacheSize = displayResource->getOutputBufferCacheSize();
+ return Error::NONE;
+}
+
Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
auto layerResource = createLayerResource(bufferCacheSize);
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
index 3738278..de78a59 100644
--- a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -74,6 +74,7 @@
ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
bool initCache(HandleType type, uint32_t cacheSize);
+ size_t getCacheSize() const;
Error lookupCache(uint32_t slot, const native_handle_t** outHandle);
Error updateCache(uint32_t slot, const native_handle_t* handle,
const native_handle** outReplacedHandle);
@@ -120,7 +121,8 @@
uint32_t outputBufferCacheSize);
bool initClientTargetCache(uint32_t cacheSize);
-
+ size_t getClientTargetCacheSize() const;
+ size_t getOutputBufferCacheSize() const;
bool isVirtual() const;
Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
@@ -162,12 +164,15 @@
std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
void clear(RemoveDisplay removeDisplay);
+ bool hasDisplay(Display display);
Error addPhysicalDisplay(Display display);
Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize);
Error removeDisplay(Display display);
Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize);
+ Error getDisplayClientTargetCacheSize(Display display, size_t* outCacheSize);
+ Error getDisplayOutputBufferCacheSize(Display display, size_t* outCacheSize);
Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize);
Error removeLayer(Display display, Layer layer);
@@ -177,7 +182,8 @@
bool mustValidateDisplay(Display display);
// When a buffer in the cache is replaced by a new one, we must keep it
- // alive until it has been replaced in ComposerHal.
+ // alive until it has been replaced in ComposerHal because it is still using
+ // the old buffer.
class ReplacedHandle {
public:
explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index b92279d..4fee560 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -1083,11 +1083,13 @@
execute();
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlCommandTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index c78c358..3becace 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -69,9 +69,8 @@
[](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
return &settings;
});
- mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
- mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
- &readyFence);
+ mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers, mGraphicBuffer, true,
+ std::move(bufferFence), &readyFence);
int fd = readyFence.release();
if (fd != -1) {
ASSERT_EQ(0, sync_wait(fd, -1));
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index d80845f..16e9138 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -16,7 +16,11 @@
cc_test {
name: "VtsHalGraphicsComposerV2_2TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ // Needed for librenderengine
+ "skia_deps",
+ ],
srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
"VtsHalGraphicsComposerV2_2TargetTest.cpp",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index b0eb4ef..f522731 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -1381,6 +1381,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsCompositionTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsCompositionTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
@@ -1394,6 +1395,7 @@
testing::Values("0.2", "1.0")),
android::hardware::PrintInstanceTupleNameToString<>);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsTransformCompositionTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsTransformCompositionTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 95a0f69..4d7df1c 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -681,11 +681,13 @@
EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
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)),
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 94766af..a4c1b63 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -611,11 +611,13 @@
EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
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)),
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f0de4f7..e6ecf93 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -644,11 +644,13 @@
Test_setContentType(ContentType::GAME, "GAME");
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
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)),
diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp
index 99fdb8c..fc1f585 100644
--- a/input/classifier/1.0/vts/functional/Android.bp
+++ b/input/classifier/1.0/vts/functional/Android.bp
@@ -22,6 +22,7 @@
static_libs: [
"android.hardware.input.classifier@1.0",
"android.hardware.input.common@1.0",
+ "libui-types",
],
test_suites: [
"general-tests",
diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
index ee529c7..186e406 100644
--- a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
+++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
@@ -168,6 +168,7 @@
classifier->reset();
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputClassifierHidlTest_1_0);
INSTANTIATE_TEST_SUITE_P(
PerInstance, InputClassifierHidlTest_1_0,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IInputClassifier::descriptor)),
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 914a01a..0a95695 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -644,7 +644,7 @@
int n;
std::tie(n, outputShapes, timing, std::ignore) =
controller->compute(request10, testConfig.measureTiming, keys);
- executionStatus = nn::convertResultCodeToErrorStatus(n);
+ executionStatus = nn::convertToV1_3(nn::convertResultCodeToErrorStatus(n));
break;
}
diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
index a7569e6..1a40721 100644
--- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
+++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
@@ -15,10 +15,16 @@
*/
#include <android/hardware/neuralnetworks/1.3/types.h>
+#include "ControlFlow.h"
#include "TestHarness.h"
namespace android::hardware::neuralnetworks::V1_3 {
+static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::DEFAULT) ==
+ nn::operation_while::kTimeoutNsDefault);
+static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::MAXIMUM) ==
+ nn::operation_while::kTimeoutNsMaximum);
+
// Make sure that the HIDL enums are compatible with the values defined in
// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
using namespace test_helper;
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 1ae8b3f..3b441fb 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -116,7 +116,7 @@
// execute and verify
const auto [n, outputShapes, timing, fallback] = burst->compute(request10, measure, keys);
- const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+ const ErrorStatus status = nn::convertToV1_3(nn::convertResultCodeToErrorStatus(n));
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
EXPECT_EQ(outputShapes.size(), 0);
EXPECT_TRUE(badTiming(timing));
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
new file mode 100644
index 0000000..1688b12
--- /dev/null
+++ b/power/stats/aidl/Android.bp
@@ -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.
+
+aidl_interface {
+ name: "android.hardware.power.stats",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/power/stats/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/ChannelInfo.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/ChannelInfo.aidl
new file mode 100644
index 0000000..209bec4
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/ChannelInfo.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.power.stats;
+@VintfStability
+parcelable ChannelInfo {
+ int channelId;
+ @utf8InCpp String channelName;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerId.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerId.aidl
new file mode 100644
index 0000000..7ca3b15
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerId.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.power.stats;
+@Backing(type="int") @VintfStability
+enum EnergyConsumerId {
+ DISPLAY = 0,
+ GPS = 1,
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerResult.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerResult.aidl
new file mode 100644
index 0000000..6289a08
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerResult.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.power.stats;
+@VintfStability
+parcelable EnergyConsumerResult {
+ android.hardware.power.stats.EnergyConsumerId energyConsumerId;
+ long timestampMs;
+ long energyUWs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyMeasurement.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyMeasurement.aidl
new file mode 100644
index 0000000..341909e
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyMeasurement.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.power.stats;
+@VintfStability
+parcelable EnergyMeasurement {
+ int channelId;
+ long timestampMs;
+ long energyUWs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/IPowerStats.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/IPowerStats.aidl
new file mode 100644
index 0000000..07013b0
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/IPowerStats.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.power.stats;
+@VintfStability
+interface IPowerStats {
+ android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo();
+ android.hardware.power.stats.StateResidencyResult[] getStateResidency(in int[] powerEntityIds);
+ android.hardware.power.stats.EnergyConsumerId[] getEnergyConsumerInfo();
+ android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(in android.hardware.power.stats.EnergyConsumerId[] energyConsumerIds);
+ android.hardware.power.stats.ChannelInfo[] getEnergyMeterInfo();
+ android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(in int[] channelIds);
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/PowerEntityInfo.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/PowerEntityInfo.aidl
new file mode 100644
index 0000000..3b16362
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/PowerEntityInfo.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.power.stats;
+@VintfStability
+parcelable PowerEntityInfo {
+ int powerEntityId;
+ @utf8InCpp String powerEntityName;
+ android.hardware.power.stats.StateInfo[] states;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateInfo.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateInfo.aidl
new file mode 100644
index 0000000..0db9ab1
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateInfo.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.power.stats;
+@VintfStability
+parcelable StateInfo {
+ int stateId;
+ @utf8InCpp String stateName;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidency.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidency.aidl
new file mode 100644
index 0000000..206c974
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidency.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.power.stats;
+@VintfStability
+parcelable StateResidency {
+ int stateId;
+ long totalTimeInStateMs;
+ long totalStateEntryCount;
+ long lastEntryTimestampMs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidencyResult.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidencyResult.aidl
new file mode 100644
index 0000000..dc41fef
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/StateResidencyResult.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.power.stats;
+@VintfStability
+parcelable StateResidencyResult {
+ int powerEntityId;
+ android.hardware.power.stats.StateResidency[] stateResidencyData;
+}
diff --git a/power/stats/aidl/android/hardware/power/stats/ChannelInfo.aidl b/power/stats/aidl/android/hardware/power/stats/ChannelInfo.aidl
new file mode 100644
index 0000000..a2ca6a6
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/ChannelInfo.aidl
@@ -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.power.stats;
+
+@VintfStability
+parcelable ChannelInfo {
+ /**
+ * Unique ID of this ChannelInfo
+ */
+ int channelId;
+ /**
+ * Unique name of the ChannelInfo. Vendor/device specific. Opaque to framework
+ */
+ @utf8InCpp String channelName;
+}
+
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerId.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerId.aidl
new file mode 100644
index 0000000..4a6a677
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerId.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.power.stats;
+
+@VintfStability
+@Backing(type="int")
+enum EnergyConsumerId {
+ DISPLAY = 0,
+ GPS = 1,
+}
\ No newline at end of file
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerResult.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerResult.aidl
new file mode 100644
index 0000000..d2b902a
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerResult.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.power.stats;
+
+import android.hardware.power.stats.EnergyConsumerId;
+
+@VintfStability
+parcelable EnergyConsumerResult {
+ /**
+ * ID of the EnergyConsumer associated with this result
+ */
+ EnergyConsumerId energyConsumerId;
+ /**
+ * Time since boot in milliseconds
+ */
+ long timestampMs;
+ /**
+ * Accumulated energy since boot in microwatt-seconds (uWs)
+ */
+ long energyUWs;
+}
+
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyMeasurement.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyMeasurement.aidl
new file mode 100644
index 0000000..f873849
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyMeasurement.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.power.stats;
+
+@VintfStability
+parcelable EnergyMeasurement {
+ /**
+ * ID of the Channel associated with this measurement
+ */
+ int channelId;
+ /**
+ * Time since boot in milliseconds
+ */
+ long timestampMs;
+ /**
+ * Accumulated energy since boot in microwatt-seconds (uWs)
+ */
+ long energyUWs;
+}
+
diff --git a/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl b/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl
new file mode 100644
index 0000000..85a2ce0
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl
@@ -0,0 +1,112 @@
+/*
+ * 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.power.stats;
+
+import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.EnergyConsumerId;
+import android.hardware.power.stats.EnergyConsumerResult;
+import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateResidencyResult;
+
+@VintfStability
+interface IPowerStats {
+ /**
+ * Return information related to all supported PowerEntity(s) for which state residency data
+ * is available.
+ *
+ * A PowerEntity is defined as a platform subsystem, peripheral, or power domain that impacts
+ * the total device power consumption.
+ *
+ * @return List of information on each PowerEntity
+ */
+ PowerEntityInfo[] getPowerEntityInfo();
+
+ /**
+ * Reports the accumulated state residency for each requested PowerEntity.
+ *
+ * Each PowerEntity may reside in one of multiple states. It may also
+ * transition from one state to another. StateResidency is defined as
+ * an accumulation of time that a PowerEntity resided in each
+ * of its possible states, the number of times that each state was
+ * entered, and a timestamp corresponding to the last time that state
+ * was entered.
+ *
+ * Data is accumulated starting at device boot.
+ *
+ * @param powerEntityIds List of IDs of PowerEntities for which data is requested.
+ * Passing an empty list will return state residency for all available PowerEntitys.
+ * ID of each PowerEntity is contained in PowerEntityInfo.
+ *
+ * @return StateResidency since boot for each requested PowerEntity
+ *
+ * Returns the following service-specific exceptions in order of highest priority:
+ * - STATUS_BAD_VALUE if an invalid powerEntityId is provided
+ * - STATUS_FAILED_TRANSACTION if any StateResidencyResult fails to be returned
+ */
+ StateResidencyResult[] getStateResidency(in int[] powerEntityIds);
+
+ /**
+ * Return the list IDs for all supported EnergyConsumers for which energy consumption data is
+ * available.
+ *
+ * An EnergyConsumer is a device subsystem or peripheral that consumes energy. Energy
+ * consumption data may be used by framework for the purpose of power attribution.
+ *
+ * @return List of EnergyConsumersIds that are available.
+ */
+ EnergyConsumerId[] getEnergyConsumerInfo();
+
+ /**
+ * Reports the energy consumed since boot by each requested EnergyConsumer.
+ *
+ * @param energyConsumerIds List of IDs of EnergyConsumers for which data is requested.
+ * Passing an empty list will return state residency for all available EnergyConsumers.
+ *
+ * @return Energy consumed since boot for each requested EnergyConsumer
+ *
+ * Returns the following service-specific exceptions in order of highest priority:
+ * - STATUS_BAD_VALUE if an invalid energyConsumerId is provided
+ * - STATUS_FAILED_TRANSACTION if any EnergyConsumerResult fails to be returned
+ */
+ EnergyConsumerResult[] getEnergyConsumed(in EnergyConsumerId[] energyConsumerIds);
+
+ /**
+ * Return information related to all channels monitored by Energy Meters.
+ *
+ * An Energy Meter is a device that monitors energy and may support monitoring multiple
+ * channels simultaneously. A channel may correspond a bus, sense resistor, or power rail.
+ *
+ * @return Information about channels monitored by Energy Meters.
+ */
+ ChannelInfo[] getEnergyMeterInfo();
+
+ /**
+ * Reports accumulated energy since boot for each specified channel.
+ *
+ * @param channelIds IDs of channels for which data is requested.
+ * Passing an empty list will return energy measurements for all available channels.
+ * ID of each channel is contained in ChannelInfo.
+ *
+ * @return Energy measured since boot for each requested channel
+ *
+ * Returns the following service-specific exceptions in order of highest priority:
+ * - STATUS_BAD_VALUE if an invalid channelId is provided
+ * - STATUS_FAILED_TRANSACTION if any EnergyMeasurement fails to be returned
+ */
+ EnergyMeasurement[] readEnergyMeters(in int[] channelIds);
+}
\ No newline at end of file
diff --git a/power/stats/aidl/android/hardware/power/stats/PowerEntityInfo.aidl b/power/stats/aidl/android/hardware/power/stats/PowerEntityInfo.aidl
new file mode 100644
index 0000000..002b343
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/PowerEntityInfo.aidl
@@ -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.
+ */
+
+package android.hardware.power.stats;
+
+import android.hardware.power.stats.StateInfo;
+
+@VintfStability
+parcelable PowerEntityInfo {
+ /**
+ * Unique ID of this PowerEntityInfo
+ */
+ int powerEntityId;
+ /**
+ * Unique name of the PowerEntity. Vendor/device specific. Opaque to framework
+ */
+ @utf8InCpp String powerEntityName;
+ /**
+ * List of states that the PowerEntity may reside in
+ */
+ StateInfo[] states;
+}
\ No newline at end of file
diff --git a/power/stats/aidl/android/hardware/power/stats/StateInfo.aidl b/power/stats/aidl/android/hardware/power/stats/StateInfo.aidl
new file mode 100644
index 0000000..5703f1e
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/StateInfo.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.power.stats;
+
+@VintfStability
+parcelable StateInfo {
+ /**
+ * Unique (for a given PowerEntityInfo) ID of this StateInfo
+ */
+ int stateId;
+ /**
+ * Unique (for a given PowerEntityInfo) name of the state. Vendor/device specific.
+ * Opaque to framework
+ */
+ @utf8InCpp String stateName;
+}
+
diff --git a/power/stats/aidl/android/hardware/power/stats/StateResidency.aidl b/power/stats/aidl/android/hardware/power/stats/StateResidency.aidl
new file mode 100644
index 0000000..a85ca33
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/StateResidency.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.power.stats;
+
+/**
+ * Contains residency data for a single state
+ */
+@VintfStability
+parcelable StateResidency {
+ /**
+ * ID of the state associated with this residency
+ */
+ int stateId;
+ /**
+ * Total time in milliseconds that the corresponding PowerEntity resided
+ * in this state since boot
+ */
+ long totalTimeInStateMs;
+ /**
+ * Total number of times that the state was entered since boot
+ */
+ long totalStateEntryCount;
+ /**
+ * Last time this state was entered. Time in milliseconds since boot
+ */
+ long lastEntryTimestampMs;
+}
\ No newline at end of file
diff --git a/power/stats/aidl/android/hardware/power/stats/StateResidencyResult.aidl b/power/stats/aidl/android/hardware/power/stats/StateResidencyResult.aidl
new file mode 100644
index 0000000..3356405
--- /dev/null
+++ b/power/stats/aidl/android/hardware/power/stats/StateResidencyResult.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.power.stats;
+
+import android.hardware.power.stats.StateResidency;
+
+@VintfStability
+parcelable StateResidencyResult {
+ /**
+ * ID of the PowerEntity associated with this result
+ */
+ int powerEntityId;
+ /**
+ * Residency for each state in the PowerEntity's state space
+ */
+ StateResidency[] stateResidencyData;
+}
+
diff --git a/power/stats/aidl/default/Android.bp b/power/stats/aidl/default/Android.bp
new file mode 100644
index 0000000..40b9447
--- /dev/null
+++ b/power/stats/aidl/default/Android.bp
@@ -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.
+
+cc_binary {
+ name: "android.hardware.power.stats-service.example",
+ relative_install_path: "hw",
+ init_rc: ["power.stats-default.rc"],
+ vintf_fragments: ["power.stats-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.power.stats-ndk_platform",
+ ],
+ srcs: [
+ "main.cpp",
+ "PowerStats.cpp",
+ ],
+}
diff --git a/power/stats/aidl/default/PowerStats.cpp b/power/stats/aidl/default/PowerStats.cpp
new file mode 100644
index 0000000..367ee95
--- /dev/null
+++ b/power/stats/aidl/default/PowerStats.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "PowerStats.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+ndk::ScopedAStatus PowerStats::getPowerEntityInfo(std::vector<PowerEntityInfo>* _aidl_return) {
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getStateResidency(const std::vector<int32_t>& in_powerEntityIds,
+ std::vector<StateResidencyResult>* _aidl_return) {
+ (void)in_powerEntityIds;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getEnergyConsumerInfo(std::vector<EnergyConsumerId>* _aidl_return) {
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getEnergyConsumed(
+ const std::vector<EnergyConsumerId>& in_energyConsumerIds,
+ std::vector<EnergyConsumerResult>* _aidl_return) {
+ (void)in_energyConsumerIds;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getEnergyMeterInfo(std::vector<ChannelInfo>* _aidl_return) {
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::readEnergyMeters(const std::vector<int32_t>& in_channelIds,
+ std::vector<EnergyMeasurement>* _aidl_return) {
+ (void)in_channelIds;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/power/stats/aidl/default/PowerStats.h b/power/stats/aidl/default/PowerStats.h
new file mode 100644
index 0000000..76ab2cb
--- /dev/null
+++ b/power/stats/aidl/default/PowerStats.h
@@ -0,0 +1,46 @@
+/*
+ * 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/power/stats/BnPowerStats.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+class PowerStats : public BnPowerStats {
+ public:
+ PowerStats() = default;
+ // Methods from aidl::android::hardware::power::stats::IPowerStats
+ ndk::ScopedAStatus getPowerEntityInfo(std::vector<PowerEntityInfo>* _aidl_return) override;
+ ndk::ScopedAStatus getStateResidency(const std::vector<int32_t>& in_powerEntityIds,
+ std::vector<StateResidencyResult>* _aidl_return) override;
+ ndk::ScopedAStatus getEnergyConsumerInfo(std::vector<EnergyConsumerId>* _aidl_return) override;
+ ndk::ScopedAStatus getEnergyConsumed(const std::vector<EnergyConsumerId>& in_energyConsumerIds,
+ std::vector<EnergyConsumerResult>* _aidl_return) override;
+ ndk::ScopedAStatus getEnergyMeterInfo(std::vector<ChannelInfo>* _aidl_return) override;
+ ndk::ScopedAStatus readEnergyMeters(const std::vector<int32_t>& in_channelIds,
+ std::vector<EnergyMeasurement>* _aidl_return) override;
+};
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/power/stats/aidl/default/main.cpp b/power/stats/aidl/default/main.cpp
new file mode 100644
index 0000000..0469b4c
--- /dev/null
+++ b/power/stats/aidl/default/main.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.
+ */
+
+#include "PowerStats.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::power::stats::PowerStats;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<PowerStats> p = ndk::SharedRefBase::make<PowerStats>();
+
+ const std::string instance = std::string() + PowerStats::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(p->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/power/stats/aidl/default/power.stats-default.rc b/power/stats/aidl/default/power.stats-default.rc
new file mode 100644
index 0000000..6ff6754
--- /dev/null
+++ b/power/stats/aidl/default/power.stats-default.rc
@@ -0,0 +1,4 @@
+service vendor.power.stats-default /vendor/bin/hw/android.hardware.power.stats-service.example
+ class hal
+ user system
+ group system
diff --git a/power/stats/aidl/default/power.stats-default.xml b/power/stats/aidl/default/power.stats-default.xml
new file mode 100644
index 0000000..3b1a216
--- /dev/null
+++ b/power/stats/aidl/default/power.stats-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.power.stats</name>
+ <fqname>IPowerStats/default</fqname>
+ </hal>
+</manifest>
diff --git a/power/stats/aidl/vts/Android.bp b/power/stats/aidl/vts/Android.bp
new file mode 100644
index 0000000..930709f
--- /dev/null
+++ b/power/stats/aidl/vts/Android.bp
@@ -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.
+
+cc_test {
+ name: "VtsHalPowerStatsTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalPowerStatsTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.power.stats-ndk_platform",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
new file mode 100644
index 0000000..1d30821
--- /dev/null
+++ b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 <aidl/android/hardware/power/stats/IPowerStats.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::power::stats::ChannelInfo;
+using aidl::android::hardware::power::stats::EnergyMeasurement;
+using aidl::android::hardware::power::stats::IPowerStats;
+using aidl::android::hardware::power::stats::PowerEntityInfo;
+using aidl::android::hardware::power::stats::StateResidencyResult;
+
+using ndk::SpAIBinder;
+
+class PowerStatsAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ powerstats = IPowerStats::fromBinder(
+ SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+ ASSERT_NE(nullptr, powerstats.get());
+ }
+
+ std::shared_ptr<IPowerStats> powerstats;
+};
+
+TEST_P(PowerStatsAidl, TestReadEnergyMeter) {
+ std::vector<EnergyMeasurement> data;
+ ASSERT_TRUE(powerstats->readEnergyMeters({}, &data).isOk());
+}
+
+// Each PowerEntity must have a valid name
+TEST_P(PowerStatsAidl, ValidatePowerEntityNames) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ for (auto info : infos) {
+ EXPECT_NE(info.powerEntityName, "");
+ }
+}
+
+// Each power entity must have a unique name
+TEST_P(PowerStatsAidl, ValidatePowerEntityUniqueNames) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ std::set<std::string> names;
+ for (auto info : infos) {
+ EXPECT_TRUE(names.insert(info.powerEntityName).second);
+ }
+}
+
+// Each PowerEntity must have a unique ID
+TEST_P(PowerStatsAidl, ValidatePowerEntityIds) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ std::set<int32_t> ids;
+ for (auto info : infos) {
+ EXPECT_TRUE(ids.insert(info.powerEntityId).second);
+ }
+}
+
+// Each state must have a valid name
+TEST_P(PowerStatsAidl, ValidateStateNames) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ for (auto info : infos) {
+ for (auto state : info.states) {
+ EXPECT_NE(state.stateName, "");
+ }
+ }
+}
+
+// Each state must have a name that is unique to the given PowerEntity
+TEST_P(PowerStatsAidl, ValidateStateUniqueNames) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ for (auto info : infos) {
+ std::set<std::string> stateNames;
+ for (auto state : info.states) {
+ EXPECT_TRUE(stateNames.insert(state.stateName).second);
+ }
+ }
+}
+
+// Each state must have an ID that is unique to the given PowerEntity
+TEST_P(PowerStatsAidl, ValidateStateUniqueIds) {
+ std::vector<PowerEntityInfo> infos;
+ ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+ for (auto info : infos) {
+ std::set<int32_t> stateIds;
+ for (auto state : info.states) {
+ EXPECT_TRUE(stateIds.insert(state.stateId).second);
+ }
+ }
+}
+
+TEST_P(PowerStatsAidl, TestGetStateResidency) {
+ std::vector<StateResidencyResult> results;
+ ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk());
+}
+
+TEST_P(PowerStatsAidl, TestGetEnergyMeterInfo) {
+ std::vector<ChannelInfo> info;
+ ASSERT_TRUE(powerstats->getEnergyMeterInfo(&info).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerStatsAidl);
+INSTANTIATE_TEST_SUITE_P(
+ PowerStats, PowerStatsAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IPowerStats::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
index 6c7870d..5359a87 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
+++ b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
@@ -61,10 +61,11 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(sapCb->sapResponseToken, token);
- ASSERT_TRUE(
- CheckAnyOfErrors(sapCb->sapResultCode,
- {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF,
- SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF,
+ SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED,
+ SapResultCode::SUCCESS}));
LOG(DEBUG) << "apduReq finished";
}
@@ -79,10 +80,10 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(sapCb->sapResponseToken, token);
- ASSERT_TRUE(
- CheckAnyOfErrors(sapCb->sapResultCode,
- {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
- SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED}));
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF,
+ SapResultCode::CARD_REMOVED, SapResultCode::SUCCESS}));
LOG(DEBUG) << "transferAtrReq finished";
}
@@ -98,10 +99,11 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(sapCb->sapResponseToken, token);
- ASSERT_TRUE(CheckAnyOfErrors(
- sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
- SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
- SapResultCode::CARD_ALREADY_POWERED_ON}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+ SapResultCode::CARD_ALREADY_POWERED_ON, SapResultCode::SUCCESS}));
LOG(DEBUG) << "powerReq finished";
}
@@ -117,9 +119,10 @@
EXPECT_EQ(sapCb->sapResponseToken, token);
ASSERT_TRUE(
- CheckAnyOfErrors(sapCb->sapResultCode,
- {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
- SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED}));
+ CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+ SapResultCode::SUCCESS}));
LOG(DEBUG) << "resetSimReq finished";
}
@@ -134,8 +137,9 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(sapCb->sapResponseToken, token);
- ASSERT_TRUE(CheckAnyOfErrors(
- sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE}));
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+ SapResultCode::SUCCESS}));
LOG(DEBUG) << "transferCardReaderStatusReq finished";
}
@@ -151,6 +155,7 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(sapCb->sapResponseToken, token);
- EXPECT_EQ(SapResultCode::NOT_SUPPORTED, sapCb->sapResultCode);
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::NOT_SUPPORTED, SapResultCode::SUCCESS}));
LOG(DEBUG) << "setTransferProtocolReq finished";
}
diff --git a/radio/1.4/types.hal b/radio/1.4/types.hal
index 393716b..a830816 100644
--- a/radio/1.4/types.hal
+++ b/radio/1.4/types.hal
@@ -1847,9 +1847,9 @@
/**
* SS reference signal received quality, multipled by -1.
*
- * Reference: 3GPP TS 38.215.
+ * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10.
*
- * Range [3, 20], INT_MAX means invalid/unreported.
+ * Range [-20 dB, 43 dB], INT_MAX means invalid/unreported.
*/
int32_t ssRsrq;
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index b061bd5..c1f3f03 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -107,9 +107,9 @@
SSRSRP = 6,
/**
* 5G SS reference signal received quality.
- * Range: -20 dB to -3 dB.
+ * Range: -43 dB to 20 dB.
* Used RAN: NGRAN
- * Reference: 3GPP TS 38.215.
+ * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10
*/
SSRSRQ = 7,
/**
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index 5f5f5c1..ca40a17 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -181,4 +181,28 @@
*
*/
oneway sendCdmaSmsExpectMore_1_6(int32_t serial, CdmaSmsMessage sms);
+
+ /**
+ * Enable or disable E-UTRA-NR dual connectivity. If disabled then UE will not connect
+ * to secondary carrier.
+ *
+ * @param serial Serial number of request.
+ * @param nrDualConnectivityState expected NR dual connectivity state.
+ * 1. Enable NR dual connectivity {NrDualConnectivityState:ENABLE}
+ * 2. Disable NR dual connectivity {NrDualConnectivityState:DISABLE}
+ * 3. Disable NR dual connectivity and force secondary cell to be released
+ * {NrDualConnectivityState:DISABLE_IMMEDIATE}
+
+ * Response callback is IRadioResponse.enableNRDualConnectivityResponse()
+ */
+ oneway enableNrDualConnectivity(int32_t serial,
+ NrDualConnectivityState nrDualConnectivityState);
+
+ /**
+ * Is E-UTRA-NR Dual Connectivity enabled
+ *
+ * @param serial Serial number of request.
+ * Response callback is IRadioResponse.isNRDualConnectivityEnabledResponse()
+ */
+ oneway isNrDualConnectivityEnabled(int32_t serial);
};
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index fed7e79..4ff7e47 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -200,4 +200,26 @@
* RadioError:BLOCKED_DUE_TO_CALL
*/
oneway sendCdmaSmsExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway enableNrDualConnectivityResponse(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * @param isEnabled Indicates whether NR dual connectivity is enabled or not, True if enabled
+ * else false.
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway isNrDualConnectivityEnabledResponse(RadioResponseInfo info, bool isEnabled);
};
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index c77a86d..07b4977 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -255,3 +255,24 @@
/** Specifies the fallback mode on an IWLAN handover failure. */
HandoverFailureMode handoverFailureMode;
};
+
+/**
+ * NR Dual connectivity state
+ */
+enum NrDualConnectivityState: int32_t {
+ /**
+ * Enable NR dual connectivity. Enabled state does not mean dual connectivity
+ * is active. It means device is allowed to connect to both primary and secondary.
+ */
+ ENABLE = 1,
+ /**
+ * Disable NR dual connectivity. Disabled state does not mean secondary cell is released.
+ * Modem will release it only if current bearer is released to avoid radio link failure.
+ */
+ DISABLE = 2,
+ /**
+ * Disable NR dual connectivity and force secondary cell to be released if dual connectivity
+ * was active. This may result in radio link failure.
+ */
+ DISABLE_IMMEDIATE= 3,
+};
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 8f3b991..01236c6 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -63,7 +63,6 @@
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);
-
if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
@@ -259,3 +258,40 @@
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
}
+
+/*
+ * Test IRadio.enableNrDualConnectivity() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, enableNrDualConnectivity) {
+ serial = GetRandomSerialNumber();
+
+ Return<void> res =
+ radio_v1_6->enableNrDualConnectivity(serial, NrDualConnectivityState::DISABLE);
+ 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::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.isNrDualConnectivityEnabled() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, isNrDualConnectivityEnabled) {
+ serial = GetRandomSerialNumber();
+
+ Return<void> res = radio_v1_6->isNrDualConnectivityEnabled(serial);
+ 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::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::NONE}));
+}
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 d90aa80..784bcd9 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
@@ -78,6 +78,7 @@
// Modem
bool isModemEnabled;
bool enableModemResponseToggle;
+ bool isNRDualConnectivityEnabled;
::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
networkTypeBitmapResponse;
@@ -765,6 +766,11 @@
Return<void> sendCdmaSmsExpectMoreResponse_1_6(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
const SendSmsResult& sms);
+
+ Return<void> enableNrDualConnectivityResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+ Return<void> isNrDualConnectivityEnabledResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info, bool isEnabled);
};
/* Callback class for radio indication */
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index 574990d..ffa384e 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -1055,6 +1055,12 @@
parent_v1_6.notify(info.serial);
return Void();
}
+Return<void> RadioResponse_v1_6::enableNrDualConnectivityResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_6.notify(info.serial);
+ return Void();
+}
Return<void> RadioResponse_v1_6::getDataCallListResponse_1_6(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
@@ -1099,3 +1105,11 @@
parent_v1_6.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_6::isNrDualConnectivityEnabledResponse(
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info, bool isEnabled) {
+ rspInfo = info;
+ isNRDualConnectivityEnabled = isEnabled;
+ parent_v1_6.notify(info.serial);
+ return Void();
+}
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
index 809a3b5..28357a1 100644
--- a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -123,6 +123,7 @@
rebootescrow->storeKey(KEY_1);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RebootEscrowAidlTest);
INSTANTIATE_TEST_SUITE_P(
RebootEscrow, RebootEscrowAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index a0d436f..e212423 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -296,6 +296,7 @@
0 /* expectedFlushCount */, Result::BAD_VALUE);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsHidlTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
android::hardware::sensors::V2_0::ISensors::descriptor)),
diff --git a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
index 230bb6c..3a866b1 100644
--- a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
+++ b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
@@ -16,6 +16,7 @@
#include "VtsHalSensorsV2_XTargetTest.h"
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsHidlTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
android::hardware::sensors::V2_1::ISensors::descriptor)),
diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
index 2d147e4..50646d4 100644
--- a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
@@ -84,6 +84,7 @@
(AudioCapabilities::ECHO_CANCELLATION | AudioCapabilities::NOISE_SUPPRESSION));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundTriggerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, SoundTriggerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 67eff1b..9055a43 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -163,6 +163,7 @@
mRecordFilterIds.clear();
mFilters.clear();
mLastUsedFilterId = -1;
+ mTunerService->removeDemux(mDemuxId);
return Result::SUCCESS;
}
@@ -294,6 +295,11 @@
mFilters[filterId]->updateFilterOutput(data);
}
+void Demux::updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts) {
+ updateFilterOutput(filterId, data);
+ mFilters[filterId]->updatePts(pts);
+}
+
uint16_t Demux::getFilterTpid(uint32_t filterId) {
return mFilters[filterId]->getTpid();
}
@@ -313,6 +319,12 @@
std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
mFrontendInputThreadRunning = true;
+ if (!mDvrPlayback) {
+ ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
+ mFrontendInputThreadRunning = false;
+ return;
+ }
+
while (mFrontendInputThreadRunning) {
uint32_t efState = 0;
status_t status = mDvrPlayback->getDvrEventFlag()->wait(
@@ -322,6 +334,12 @@
ALOGD("[Demux] wait for data ready on the playback FMQ");
continue;
}
+ if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
+ if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
+ ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
+ break;
+ }
+ }
// Our current implementation filter the data and write it into the filter FMQ immediately
// after the DATA_READY from the VTS/framework
if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 7f282b2..6e93ea3 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -87,6 +87,7 @@
bool detachRecordFilter(int filterId);
Result startFilterHandler(uint32_t filterId);
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
+ void updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts);
uint16_t getFilterTpid(uint32_t filterId);
void setIsRecording(bool isRecording);
void startFrontendInputLoop();
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index 68e175c..c3edac9 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -129,7 +129,7 @@
mDvrThreadRunning = false;
- std::lock_guard<std::mutex> lock(mDvrThreadLock);
+ lock_guard<mutex> lock(mDvrThreadLock);
mIsRecordStarted = false;
mDemux->setIsRecording(false);
@@ -155,14 +155,13 @@
ALOGV("%s", __FUNCTION__);
// Create a synchronized FMQ that supports blocking read/write
- std::unique_ptr<DvrMQ> tmpDvrMQ =
- std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
+ unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
if (!tmpDvrMQ->isValid()) {
ALOGW("[Dvr] Failed to create FMQ of DVR");
return false;
}
- mDvrMQ = std::move(tmpDvrMQ);
+ mDvrMQ = move(tmpDvrMQ);
if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
return false;
@@ -183,7 +182,7 @@
void Dvr::playbackThreadLoop() {
ALOGD("[Dvr] playback threadLoop start.");
- std::lock_guard<std::mutex> lock(mDvrThreadLock);
+ lock_guard<mutex> lock(mDvrThreadLock);
mDvrThreadRunning = true;
while (mDvrThreadRunning) {
@@ -195,6 +194,14 @@
ALOGD("[Dvr] wait for data ready on the playback FMQ");
continue;
}
+
+ if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
+ if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+ ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
+ break;
+ }
+ maySendPlaybackStatusCallback();
+ }
// Our current implementation filter the data and write it into the filter FMQ immediately
// after the DATA_READY from the VTS/framework
if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
@@ -211,7 +218,7 @@
}
void Dvr::maySendPlaybackStatusCallback() {
- std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
+ lock_guard<mutex> lock(mPlaybackStatusLock);
int availableToRead = mDvrMQ->availableToRead();
int availableToWrite = mDvrMQ->availableToWrite();
@@ -263,8 +270,128 @@
return true;
}
+bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
+ // Read ES from the DVR FMQ
+ // Note that currently we only provides ES with metaData in a specific format to be parsed.
+ // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
+ int size = mDvrMQ->availableToRead();
+ vector<uint8_t> dataOutputBuffer;
+ dataOutputBuffer.resize(size);
+ if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
+ return false;
+ }
+
+ int metaDataSize = size;
+ int totalFrames = 0;
+ int videoEsDataSize = 0;
+ int audioEsDataSize = 0;
+ int audioPid = 0;
+ int videoPid = 0;
+
+ vector<MediaEsMetaData> esMeta;
+ int videoReadPointer = 0;
+ int audioReadPointer = 0;
+ int frameCount = 0;
+ // Get meta data from the es
+ for (int i = 0; i < metaDataSize; i++) {
+ switch (dataOutputBuffer[i]) {
+ case 'm':
+ metaDataSize = 0;
+ getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
+ videoReadPointer = metaDataSize;
+ continue;
+ case 'l':
+ getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
+ esMeta.resize(totalFrames);
+ continue;
+ case 'V':
+ getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
+ audioReadPointer = metaDataSize + videoEsDataSize;
+ continue;
+ case 'A':
+ getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
+ continue;
+ case 'p':
+ if (dataOutputBuffer[++i] == 'a') {
+ getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
+ } else if (dataOutputBuffer[i] == 'v') {
+ getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
+ }
+ continue;
+ case 'v':
+ case 'a':
+ if (dataOutputBuffer[i + 1] != ',') {
+ ALOGE("[Dvr] Invalid format meta data.");
+ return false;
+ }
+ esMeta[frameCount] = {
+ .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
+ };
+ i += 5; // Move to Len
+ getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
+ if (esMeta[frameCount].isAudio) {
+ esMeta[frameCount].startIndex = audioReadPointer;
+ audioReadPointer += esMeta[frameCount].len;
+ } else {
+ esMeta[frameCount].startIndex = videoReadPointer;
+ videoReadPointer += esMeta[frameCount].len;
+ }
+ i += 4; // move to PTS
+ getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
+ frameCount++;
+ continue;
+ default:
+ continue;
+ }
+ }
+
+ if (frameCount != totalFrames) {
+ ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
+ totalFrames);
+ return false;
+ }
+
+ if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
+ ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
+ metaDataSize, videoEsDataSize, audioEsDataSize, size);
+ return false;
+ }
+
+ // Read es raw data from the FMQ per meta data built previously
+ vector<uint8_t> frameData;
+ map<uint32_t, sp<IFilter>>::iterator it;
+ int pid = 0;
+ for (int i = 0; i < totalFrames; i++) {
+ frameData.resize(esMeta[i].len);
+ pid = esMeta[i].isAudio ? audioPid : videoPid;
+ memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
+ // Send to the media filter
+ if (isVirtualFrontend && isRecording) {
+ // TODO validate record
+ mDemux->sendFrontendInputToRecord(frameData);
+ } else {
+ for (it = mFilters.begin(); it != mFilters.end(); it++) {
+ if (pid == mDemux->getFilterTpid(it->first)) {
+ mDemux->updateMediaFilterOutput(it->first, frameData,
+ static_cast<uint64_t>(esMeta[i].pts));
+ startFilterDispatcher(isVirtualFrontend, isRecording);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
+ index += 2; // Move the pointer across the ":" to the value
+ while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
+ value = ((dataOutputBuffer[index++] - 48) + value * 10);
+ }
+}
+
void Dvr::startTpidFilter(vector<uint8_t> data) {
- std::map<uint32_t, sp<IFilter>>::iterator it;
+ map<uint32_t, sp<IFilter>>::iterator it;
for (it = mFilters.begin(); it != mFilters.end(); it++) {
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
if (DEBUG_DVR) {
@@ -285,7 +412,7 @@
}
}
- std::map<uint32_t, sp<IFilter>>::iterator it;
+ map<uint32_t, sp<IFilter>>::iterator it;
// Handle the output data per filter type
for (it = mFilters.begin(); it != mFilters.end(); it++) {
if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
@@ -296,8 +423,8 @@
return true;
}
-bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
- std::lock_guard<std::mutex> lock(mWriteLock);
+bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
+ lock_guard<mutex> lock(mWriteLock);
if (mRecordStatus == RecordStatus::OVERFLOW) {
ALOGW("[Dvr] stops writing and wait for the client side flushing.");
return true;
@@ -313,7 +440,7 @@
}
void Dvr::maySendRecordStatusCallback() {
- std::lock_guard<std::mutex> lock(mRecordStatusLock);
+ lock_guard<mutex> lock(mRecordStatusLock);
int availableToRead = mDvrMQ->availableToRead();
int availableToWrite = mDvrMQ->availableToWrite();
@@ -352,4 +479,4 @@
} // namespace tuner
} // namespace tv
} // namespace hardware
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index a63a256..3069586 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -44,6 +44,13 @@
using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+struct MediaEsMetaData {
+ bool isAudio;
+ int startIndex;
+ int len;
+ int pts;
+};
+
class Demux;
class Filter;
class Frontend;
@@ -84,8 +91,10 @@
bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter);
bool removePlaybackFilter(uint32_t filterId);
bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+ bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
EventFlag* getDvrEventFlag();
+ DvrSettings getSettings() { return mDvrSettings; }
private:
// Demux service
@@ -98,6 +107,7 @@
void deleteEventFlag();
bool readDataFromMQ();
+ void getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value);
void maySendPlaybackStatusCallback();
void maySendRecordStatusCallback();
PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index 30b19c0..ce748e5 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -317,6 +317,11 @@
mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
}
+void Filter::updatePts(uint64_t pts) {
+ std::lock_guard<std::mutex> lock(mFilterOutputLock);
+ mPts = pts;
+}
+
void Filter::updateRecordOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
@@ -460,6 +465,11 @@
if (mFilterOutput.empty()) {
return Result::SUCCESS;
}
+
+ if (mPts) {
+ return createMediaFilterEventWithIon(mFilterOutput);
+ }
+
for (int i = 0; i < mFilterOutput.size(); i += 188) {
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
@@ -493,46 +503,7 @@
continue;
}
- int av_fd = createAvIonFd(mPesOutput.size());
- if (av_fd == -1) {
- return Result::UNKNOWN_ERROR;
- }
- // copy the filtered data to the buffer
- uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size());
- if (avBuffer == NULL) {
- return Result::UNKNOWN_ERROR;
- }
- memcpy(avBuffer, mPesOutput.data(), mPesOutput.size() * sizeof(uint8_t));
-
- native_handle_t* nativeHandle = createNativeHandle(av_fd);
- if (nativeHandle == NULL) {
- return Result::UNKNOWN_ERROR;
- }
- hidl_handle handle;
- handle.setTo(nativeHandle, /*shouldOwn=*/true);
-
- // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
- uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
- mDataId2Avfd[dataId] = dup(av_fd);
-
- // Create mediaEvent and send callback
- DemuxFilterMediaEvent mediaEvent;
- mediaEvent = {
- .avMemory = std::move(handle),
- .dataLength = static_cast<uint32_t>(mPesOutput.size()),
- .avDataId = dataId,
- };
- int size = mFilterEvent.events.size();
- mFilterEvent.events.resize(size + 1);
- mFilterEvent.events[size].media(mediaEvent);
-
- // Clear and log
- mPesOutput.clear();
- mAvBufferCopyCount = 0;
- ::close(av_fd);
- if (DEBUG_FILTER) {
- ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength);
- }
+ createMediaFilterEventWithIon(mPesOutput);
}
mFilterOutput.clear();
@@ -540,6 +511,54 @@
return Result::SUCCESS;
}
+Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
+ int av_fd = createAvIonFd(output.size());
+ if (av_fd == -1) {
+ return Result::UNKNOWN_ERROR;
+ }
+ // copy the filtered data to the buffer
+ uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
+ if (avBuffer == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
+
+ native_handle_t* nativeHandle = createNativeHandle(av_fd);
+ if (nativeHandle == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+ // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+ uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+ mDataId2Avfd[dataId] = dup(av_fd);
+
+ // Create mediaEvent and send callback
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ .avMemory = std::move(handle),
+ .dataLength = static_cast<uint32_t>(output.size()),
+ .avDataId = dataId,
+ };
+ if (mPts) {
+ mediaEvent.pts = mPts;
+ mPts = 0;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].media(mediaEvent);
+
+ // Clear and log
+ output.clear();
+ mAvBufferCopyCount = 0;
+ ::close(av_fd);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
+ }
+ return Result::SUCCESS;
+}
+
Result Filter::startRecordFilterHandler() {
std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
if (mRecordFilterOutput.empty()) {
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index 9386dca..9b18a66 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -84,6 +84,7 @@
uint16_t getTpid();
void updateFilterOutput(vector<uint8_t> data);
void updateRecordOutput(vector<uint8_t> data);
+ void updatePts(uint64_t pts);
Result startFilterHandler();
Result startRecordFilterHandler();
void attachFilterToRecord(const sp<Dvr> dvr);
@@ -116,6 +117,7 @@
bool mIsDataSourceDemux = true;
vector<uint8_t> mFilterOutput;
vector<uint8_t> mRecordFilterOutput;
+ uint64_t mPts = 0;
unique_ptr<FilterMQ> mFilterMQ;
bool mIsUsingFMQ = false;
EventFlag* mFilterEventFlag;
@@ -172,6 +174,7 @@
int createAvIonFd(int size);
uint8_t* getIonBuffer(int fd, int size);
native_handle_t* createNativeHandle(int fd);
+ Result createMediaFilterEventWithIon(vector<uint8_t> output);
/**
* Lock to protect writes to the FMQs
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 8bf0ec5..6561c92 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -42,6 +42,7 @@
// Reset callback
mCallback = nullptr;
mIsLocked = false;
+ mTunerService->removeFrontend(mId);
return Result::SUCCESS;
}
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 48ce384..9a6ecf7 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -37,7 +37,6 @@
// Static Frontends array to maintain local frontends information
// Array index matches their FrontendId in the default impl
mFrontendSize = 8;
- mFrontends.resize(mFrontendSize);
mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
@@ -48,7 +47,6 @@
mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
FrontendInfo::FrontendCapabilities caps;
- mFrontendCaps.resize(mFrontendSize);
caps = FrontendInfo::FrontendCapabilities();
caps.dvbtCaps(FrontendDvbtCapabilities());
mFrontendCaps[0] = caps;
@@ -236,6 +234,21 @@
}
}
+void Tuner::removeDemux(uint32_t demuxId) {
+ map<uint32_t, uint32_t>::iterator it;
+ for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
+ if (it->second == demuxId) {
+ it = mFrontendToDemux.erase(it);
+ break;
+ }
+ }
+ mDemuxes.erase(demuxId);
+}
+
+void Tuner::removeFrontend(uint32_t frontendId) {
+ mFrontendToDemux.erase(frontendId);
+}
+
void Tuner::frontendStopTune(uint32_t frontendId) {
map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
uint32_t demuxId;
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 5de568f..1c09d6c 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -65,14 +65,16 @@
void frontendStartTune(uint32_t frontendId);
void frontendStopTune(uint32_t frontendId);
+ void removeDemux(uint32_t demuxId);
+ void removeFrontend(uint32_t frontendId);
private:
virtual ~Tuner();
// Static mFrontends array to maintain local frontends information
- vector<sp<Frontend>> mFrontends;
- vector<FrontendInfo::FrontendCapabilities> mFrontendCaps;
- std::map<uint32_t, uint32_t> mFrontendToDemux;
- std::map<uint32_t, sp<Demux>> mDemuxes;
+ map<uint32_t, sp<Frontend>> mFrontends;
+ map<uint32_t, FrontendInfo::FrontendCapabilities> mFrontendCaps;
+ map<uint32_t, uint32_t> mFrontendToDemux;
+ map<uint32_t, sp<Demux>> mDemuxes;
// To maintain how many Frontends we have
int mFrontendSize;
// The last used demux id. Initial value is -1.
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp
index 0ecdf73..5f5d108 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp
@@ -85,7 +85,7 @@
case FilterEventType::MEDIA:
return dumpAvData(filterEvent.events[i].media());
case FilterEventType::RECORD:
- break;
+ return readRecordData(filterEvent.events[i].tsRecord());
case FilterEventType::MMTPRECORD:
break;
case FilterEventType::DOWNLOAD:
@@ -128,6 +128,11 @@
return true;
}
+bool FilterCallback::readRecordData(DemuxFilterTsRecordEvent event) {
+ ALOGD("[vts] got DemuxFilterTsRecordEvent with pid=%d.", event.pid.tPid());
+ return true;
+}
+
AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
Result status;
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h
index a76a6b9..8ac9c55 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.h
+++ b/tv/tuner/1.0/vts/functional/FilterTests.h
@@ -50,6 +50,7 @@
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
@@ -115,6 +116,7 @@
void updateGoldenOutputMap(string goldenOutputFile);
bool readFilterEventData();
bool dumpAvData(DemuxFilterMediaEvent event);
+ bool readRecordData(DemuxFilterTsRecordEvent event);
private:
struct FilterThreadArgs {
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
index 45951d2..b35d112 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -370,13 +370,11 @@
mIsSoftwareFe = config.isSoftwareFe;
bool result = true;
if (mIsSoftwareFe && testWithDemux) {
- DvrConfig dvrConfig;
- getSoftwareFrontendPlaybackConfig(dvrConfig);
- result &= mDvrTests.openDvrInDemux(dvrConfig.type, dvrConfig.bufferSize) == success();
- result &= mDvrTests.configDvrPlayback(dvrConfig.settings) == success();
+ result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
+ result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
- mDvrTests.startPlaybackInputThread(dvrConfig.playbackInputFile,
- dvrConfig.settings.playback());
+ mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
+ mDvrConfig.settings.playback());
if (!result) {
ALOGW("[vts] Software frontend dvr configure failed.");
return failure();
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h
index c536325..4974ff3 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.h
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.h
@@ -104,6 +104,7 @@
void setService(sp<ITuner> tuner) {
mService = tuner;
mDvrTests.setService(tuner);
+ getDefaultSoftwareFrontendPlaybackConfig(mDvrConfig);
}
AssertionResult getFrontendIds();
@@ -125,12 +126,13 @@
void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+ void setSoftwareFrontendDvrConfig(DvrConfig conf) { mDvrConfig = conf; }
protected:
static AssertionResult failure() { return ::testing::AssertionFailure(); }
static AssertionResult success() { return ::testing::AssertionSuccess(); }
- void getSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+ void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
PlaybackSettings playbackSettings{
.statusMask = 0xf,
.lowThreshold = 0x1000,
@@ -151,4 +153,5 @@
DvrTests mDvrTests;
bool mIsSoftwareFe = false;
+ DvrConfig mDvrConfig;
};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 2be68b8..078f5df 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -486,6 +486,62 @@
broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]);
}
+TEST_P(TunerBroadcastHidlTest, BroadcastEsDataFlowMediaFiltersTest) {
+ description("Test Meida Filters functionality in Broadcast use case with ES input.");
+ uint32_t feId;
+ uint32_t demuxId;
+ sp<IDemux> demux;
+ uint32_t filterId;
+
+ mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+ if (feId == INVALID_ID) {
+ // TODO broadcast test on Cuttlefish needs licensed ts input,
+ // these tests are runnable on vendor device with real frontend module
+ // or with manual ts installing and use DVBT frontend.
+ return;
+ }
+ 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(filterArray[TS_AUDIO1].type,
+ filterArray[TS_AUDIO1].bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_AUDIO1].settings, filterId));
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
+ filterArray[TS_VIDEO1].bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, filterId));
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ // tune test
+ PlaybackSettings playbackSettings{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::ES,
+ .packetSize = 188,
+ };
+ DvrConfig dvrConfig{
+ .type = DvrType::PLAYBACK,
+ .playbackInputFile = "/data/local/tmp/test.es",
+ .bufferSize = FMQ_SIZE_4M,
+ };
+ dvrConfig.settings.playback(playbackSettings);
+ mFrontendTests.setSoftwareFrontendDvrConfig(dvrConfig);
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendArray[DVBT], true /*testWithDemux*/));
+ ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
description("Feed ts data from playback and configure Ts section filter to get output");
playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]);
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 6c68e35..27c6593 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -77,6 +77,7 @@
TS_VIDEO0,
TS_VIDEO1,
TS_AUDIO0,
+ TS_AUDIO1,
TS_PES0,
TS_PCR0,
TS_SECTION0,
@@ -121,7 +122,6 @@
typedef enum {
DVR_RECORD0,
DVR_PLAYBACK0,
- DVR_SOFTWARE_FE,
DVR_MAX,
} Dvr;
@@ -274,6 +274,11 @@
filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
filterArray[TS_AUDIO0].settings.ts().tpid = 256;
filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
+ filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+ filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_AUDIO1].settings.ts().tpid = 257;
+ filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
// TS PES filter setting
filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
@@ -362,17 +367,6 @@
dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
- PlaybackSettings softwareFePlaybackSettings{
- .statusMask = 0xf,
- .lowThreshold = 0x1000,
- .highThreshold = 0x07fff,
- .dataFormat = DataFormat::TS,
- .packetSize = 188,
- };
- dvrArray[DVR_SOFTWARE_FE].type = DvrType::PLAYBACK;
- dvrArray[DVR_SOFTWARE_FE].playbackInputFile = "/data/local/tmp/segment000000.ts";
- dvrArray[DVR_SOFTWARE_FE].bufferSize = FMQ_SIZE_4M;
- dvrArray[DVR_SOFTWARE_FE].settings.playback(softwareFePlaybackSettings);
};
/** Configuration array for the descrambler test */
diff --git a/tv/tuner/1.1/Android.bp b/tv/tuner/1.1/Android.bp
new file mode 100644
index 0000000..daa3683
--- /dev/null
+++ b/tv/tuner/1.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.tv.tuner@1.1",
+ root: "android.hardware",
+ srcs: [
+ "IFilter.hal",
+ "IFrontend.hal",
+ "IFilterCallback.hal",
+ "IFrontendCallback.hal",
+ "ITuner.hal",
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ "android.hardware.tv.tuner@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
new file mode 100644
index 0000000..df736aa
--- /dev/null
+++ b/tv/tuner/1.1/IFilter.hal
@@ -0,0 +1,101 @@
+/*
+ * 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.tv.tuner@1.1;
+
+import @1.0::IFilter;
+import @1.0::Result;
+
+/**
+ * The Filter is used to filter wanted data according to the filter's
+ * configuration.
+ *
+ * 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).
+ */
+interface IFilter extends @1.0::IFilter {
+ /**
+ * Get the 64-bit filter Id. This id is 32-bit in Tuner HAL 1.0.
+ *
+ * It is used by the client to ask the hardware resource id for the filter.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ * @return filterId the hardware resource Id for the filter.
+ */
+ getId64Bit() generates (Result result, uint64_t filterId);
+
+ /**
+ * Configure additional Context ID on the IP filter.
+ *
+ * @param ipCid Context Id of the IP filter.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ configureIpCid(uint32_t ipCid) generates (Result result);
+
+ /**
+ * Get the shared AV memory handle. Use IFilter.releaseAvHandle to release the handle.
+ *
+ * When media filters are opened, call this API to initialize the share memory handle if it's
+ * needed.
+ *
+ * If DemuxFilterMediaEvent.avMemory contains file descriptor, share memory should be ignored.
+ *
+ * @return avMemory A handle associated to the shared memory for audio or video.
+ * avMemory.data[0] is normally an fd for ION memory. When the avMemory->numFd is 0, the
+ * share memory is not initialized and does not contain valid fd.
+ * avMemory.data[avMemory.numFds] is an index used as a parameter of
+ * C2DataIdInfo to build C2 buffer in Codec. No C2 buffer would be created if the index
+ * does not exist.
+ * @return avMemSize the size of the shared av memory. It should be ignored when the share
+ * memory is not initialized.
+ */
+ getAvSharedHandle() generates (Result result, handle avMemory, uint64_t avMemSize);
+
+ /**
+ * Configure A/V filter’s stream type. This API only applies to A/V filters.
+ *
+ * @param avStreamType the stream type for A/V.
+ * @return 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.
+ */
+ configureAvStreamType(AvStreamType avStreamType) generates (Result result);
+
+ /**
+ * Configure the filter to monitor specific Scrambling Status.
+ *
+ * Scrambling Status should be sent through the filer callback 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.
+ *
+ * @param statuses Scrambling Statuses to monitor. Set corresponding bit 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.
+ */
+ configureScramblingEvent(bitfield<ScramblingStatus> statuses) generates (Result result);
+};
diff --git a/tv/tuner/1.1/IFilterCallback.hal b/tv/tuner/1.1/IFilterCallback.hal
new file mode 100644
index 0000000..9960a23
--- /dev/null
+++ b/tv/tuner/1.1/IFilterCallback.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.tv.tuner@1.1;
+
+import @1.0::IFilterCallback;
+import @1.0::DemuxFilterEvent;
+import DemuxFilterEventExt;
+
+interface IFilterCallback extends @1.0::IFilterCallback {
+ /**
+ * Notify the client that a new filter event happened.
+ *
+ * @param filterEvent a v1_0 filter event.
+ * @param filterEventExt a v1_1 extended filter event.
+ */
+ oneway onFilterEvent_1_1(DemuxFilterEvent filterEvent, DemuxFilterEventExt filterEventExt);
+};
diff --git a/tv/tuner/1.1/IFrontend.hal b/tv/tuner/1.1/IFrontend.hal
new file mode 100644
index 0000000..63f0655
--- /dev/null
+++ b/tv/tuner/1.1/IFrontend.hal
@@ -0,0 +1,112 @@
+/*
+ * 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.tv.tuner@1.1;
+
+import @1.0::FrontendScanType;
+import @1.0::FrontendSettings;
+import @1.0::IFrontend;
+import @1.0::Result;
+
+/**
+ * A Tuner Frontend is used to tune to a frequency and lock signal.
+ *
+ * IFrontend provides a bit stream to the Tuner Demux interface.
+ */
+interface IFrontend extends @1.0::IFrontend {
+ /**
+ * Tunes the frontend to using the settings given.
+ *
+ * This locks the frontend to a frequency by providing signal
+ * delivery information. If previous tuning isn't completed, this call MUST
+ * stop previous tuning, and start a new tuning.
+ * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback.
+ *
+ * @param settings Signal delivery information the frontend uses to
+ * search and lock the signal.
+ * @param settingsExt1_1 v1_1 Extended information that would be used in the 1.1 Frontend to
+ * search and lock the signal in a better way.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if tuning can't be applied at current stage,
+ * UNKNOWN_ERROR if tuning failed for other reasons.
+ */
+ tune_1_1(FrontendSettings settings, FrontendSettingsExt1_1 settingsExt1_1)
+ generates (Result result);
+
+ /**
+ * Scan the frontend to use the settings given.
+ *
+ * This uses the frontend to start a scan from signal delivery information.
+ * If previous scan isn't completed, this call MUST stop previous scan,
+ * and start a new scan.
+ * Scan is an async call, with FrontendScanMessage sent via callback.
+ *
+ * @param settings Signal delivery information which the frontend uses to
+ * scan the signal.
+ * @param type the type which the frontend uses to scan the signal.
+ * @param settingsExt1_1 v1_1 Extended information that would be used in the 1.1 Frontend to
+ * search and lock the signal in a better way.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if tuning can't be applied at current stage,
+ * UNKNOWN_ERROR if tuning failed for other reasons.
+ */
+ scan_1_1(FrontendSettings settings, FrontendScanType type,
+ FrontendSettingsExt1_1 settingsExt1_1) generates (Result result);
+
+ /**
+ * Link Conditional Access Modules (CAM) to Frontend support Common Interface (CI) bypass mode.
+ *
+ * The client may use this to link CI-CAM to a frontend. CI bypass mode requires that the
+ * CICAM also receives the TS concurrently from the frontend when the Demux is receiving the TS
+ * directly from the frontend.
+ *
+ * @param ciCamId specify CI-CAM Id to link.
+ * @return ltsId Local Transport Stream Id.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ linkCiCam(uint32_t ciCamId) generates (Result result, uint32_t ltsId);
+
+ /**
+ * Unlink Conditional Access Modules (CAM) to Frontend.
+ *
+ * @param ciCamId specify CI-CAM Id to unlink.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ unlinkCiCam(uint32_t ciCamId) generates (Result result);
+
+ /**
+ * Get the v1_1 extended statuses of the frontend.
+ *
+ * This retrieve the extended statuses of the frontend for given extended status types.
+ *
+ * @param statusTypes an array of the extended status types which the caller request.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if tuning can't be applied at current stage,
+ * UNKNOWN_ERROR if tuning failed for other reasons.
+ * @return statuses an array of extended statuses the caller requests for.
+ */
+ getStatusExt1_1(vec<FrontendStatusTypeExt1_1> statusTypes)
+ generates (Result result, vec<FrontendStatusExt1_1> statuses);
+};
diff --git a/tv/tuner/1.1/IFrontendCallback.hal b/tv/tuner/1.1/IFrontendCallback.hal
new file mode 100644
index 0000000..e148b1e
--- /dev/null
+++ b/tv/tuner/1.1/IFrontendCallback.hal
@@ -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.tv.tuner@1.1;
+
+import @1.0::IFrontendCallback;
+import FrontendScanMessageExt1_1;
+import FrontendScanMessageTypeExt1_1;
+
+interface IFrontendCallback extends @1.0::IFrontendCallback {
+ /**
+ * The callback function that must be called by HAL implementation to notify
+ * the client of the v1_1 extended scan messages.
+ *
+ * @param type the type of v1_1 extended scan message.
+ * @param message the v1_1 extended scan message sent by HAL to the client.
+ */
+ onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type, FrontendScanMessageExt1_1 messageExt);
+};
diff --git a/tv/tuner/1.1/ITuner.hal b/tv/tuner/1.1/ITuner.hal
new file mode 100644
index 0000000..d59c425
--- /dev/null
+++ b/tv/tuner/1.1/ITuner.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.tv.tuner@1.1;
+
+import @1.0::FrontendId;
+import @1.0::ITuner;
+import @1.0::Result;
+
+/**
+ * Top level interface to manage Frontend, Demux and Decrambler hardware
+ * resources which are needed for Android TV.
+ */
+interface ITuner extends @1.0::ITuner {
+ /**
+ * Get Dtmb Frontend Capabilities. If no dtmb exists, Result::UNAVAILABLE would be returned.
+ */
+ getFrontendDtmbCapabilities(FrontendId frontendId)
+ generates (Result result, FrontendDtmbCapabilities caps);
+};
diff --git a/tv/tuner/1.1/TEST_MAPPING b/tv/tuner/1.1/TEST_MAPPING
new file mode 100644
index 0000000..7c91b8f
--- /dev/null
+++ b/tv/tuner/1.1/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalTvTunerV1_1TargetTest"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Android.bp b/tv/tuner/1.1/default/Android.bp
new file mode 100644
index 0000000..4401f7c
--- /dev/null
+++ b/tv/tuner/1.1/default/Android.bp
@@ -0,0 +1,52 @@
+cc_defaults {
+ name: "tuner_service_defaults@1.1",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "Demux.cpp",
+ "Descrambler.cpp",
+ "Dvr.cpp",
+ "Filter.cpp",
+ "Frontend.cpp",
+ "Lnb.cpp",
+ "TimeFilter.cpp",
+ "Tuner.cpp",
+ "service.cpp",
+ ],
+
+ compile_multilib: "first",
+
+ shared_libs: [
+ "android.hardware.tv.tuner@1.0",
+ "android.hardware.tv.tuner@1.1",
+ "android.hidl.memory@1.0",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidlmemory",
+ "libion",
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+ header_libs: [
+ "media_plugin_headers",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.tv.tuner@1.1-service",
+ vintf_fragments: ["android.hardware.tv.tuner@1.1-service.xml"],
+ defaults: ["tuner_service_defaults@1.1"],
+ init_rc: ["android.hardware.tv.tuner@1.1-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.tv.tuner@1.1-service-lazy",
+ vintf_fragments: ["android.hardware.tv.tuner@1.1-service-lazy.xml"],
+ overrides: ["android.hardware.tv.tuner@1.1-service"],
+ defaults: ["tuner_service_defaults@1.1"],
+ init_rc: ["android.hardware.tv.tuner@1.1-service-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/tv/tuner/1.1/default/Demux.cpp b/tv/tuner/1.1/default/Demux.cpp
new file mode 100644
index 0000000..66c95dc
--- /dev/null
+++ b/tv/tuner/1.1/default/Demux.cpp
@@ -0,0 +1,414 @@
+/*
+ * 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.tv.tuner@1.1-Demux"
+
+#include "Demux.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
+ mDemuxId = demuxId;
+ mTunerService = tuner;
+}
+
+Demux::~Demux() {}
+
+Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mTunerService == nullptr) {
+ return Result::NOT_INITIALIZED;
+ }
+
+ mFrontend = mTunerService->getFrontendById(frontendId);
+
+ if (mFrontend == nullptr) {
+ return Result::INVALID_STATE;
+ }
+
+ mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
+
+ return Result::SUCCESS;
+}
+
+Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t filterId;
+ filterId = ++mLastUsedFilterId;
+
+ if (cb == nullptr) {
+ ALOGW("[Demux] callback can't be null");
+ _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
+ return Void();
+ }
+
+ sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
+
+ if (!filter->createFilterMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, filter);
+ return Void();
+ }
+
+ mFilters[filterId] = filter;
+ if (filter->isPcrFilter()) {
+ mPcrFilterIds.insert(filterId);
+ }
+ bool result = true;
+ if (!filter->isRecordFilter()) {
+ // Only save non-record filters for now. Record filters are saved when the
+ // IDvr.attacheFilter is called.
+ mPlaybackFilterIds.insert(filterId);
+ if (mDvrPlayback != nullptr) {
+ result = mDvrPlayback->addPlaybackFilter(filterId, filter);
+ }
+ }
+
+ _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter);
+ return Void();
+}
+
+Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ mTimeFilter = new TimeFilter(this);
+
+ _hidl_cb(Result::SUCCESS, mTimeFilter);
+ return Void();
+}
+
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& filter, getAvSyncHwId_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint32_t avSyncHwId = -1;
+ uint64_t id;
+ Result status;
+
+ sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+ if (filter_v1_1 != NULL) {
+ filter_v1_1->getId64Bit([&](Result result, uint64_t filterId) {
+ id = filterId;
+ status = result;
+ });
+ } else {
+ filter->getId([&](Result result, uint32_t filterId) {
+ id = filterId;
+ status = result;
+ });
+ }
+
+ if (status != Result::SUCCESS) {
+ ALOGE("[Demux] Can't get filter Id.");
+ _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+ return Void();
+ }
+
+ if (!mFilters[id]->isMediaFilter()) {
+ ALOGE("[Demux] Given filter is not a media filter.");
+ _hidl_cb(Result::INVALID_ARGUMENT, avSyncHwId);
+ return Void();
+ }
+
+ if (!mPcrFilterIds.empty()) {
+ // Return the lowest pcr filter id in the default implementation as the av sync id
+ _hidl_cb(Result::SUCCESS, *mPcrFilterIds.begin());
+ return Void();
+ }
+
+ ALOGE("[Demux] No PCR filter opened.");
+ _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+ return Void();
+}
+
+Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t avSyncTime = -1;
+ if (mPcrFilterIds.empty()) {
+ _hidl_cb(Result::INVALID_STATE, avSyncTime);
+ return Void();
+ }
+ if (avSyncHwId != *mPcrFilterIds.begin()) {
+ _hidl_cb(Result::INVALID_ARGUMENT, avSyncTime);
+ return Void();
+ }
+
+ _hidl_cb(Result::SUCCESS, avSyncTime);
+ return Void();
+}
+
+Return<Result> Demux::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ set<uint64_t>::iterator it;
+ for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+ mDvrPlayback->removePlaybackFilter(*it);
+ }
+ mPlaybackFilterIds.clear();
+ mRecordFilterIds.clear();
+ mFilters.clear();
+ mLastUsedFilterId = -1;
+ mTunerService->removeDemux(mDemuxId);
+
+ return Result::SUCCESS;
+}
+
+Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+ openDvr_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (cb == nullptr) {
+ ALOGW("[Demux] DVR callback can't be null");
+ _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
+ return Void();
+ }
+
+ set<uint64_t>::iterator it;
+ switch (type) {
+ case DvrType::PLAYBACK:
+ mDvrPlayback = new Dvr(type, bufferSize, cb, this);
+ if (!mDvrPlayback->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+ return Void();
+ }
+
+ for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+ if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
+ ALOGE("[Demux] Can't get filter info for DVR playback");
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+ return Void();
+ }
+ }
+
+ _hidl_cb(Result::SUCCESS, mDvrPlayback);
+ return Void();
+ case DvrType::RECORD:
+ mDvrRecord = new Dvr(type, bufferSize, cb, this);
+ if (!mDvrRecord->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord);
+ return Void();
+ }
+
+ _hidl_cb(Result::SUCCESS, mDvrRecord);
+ return Void();
+ default:
+ _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+ return Void();
+ }
+}
+
+Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCiCamId = ciCamId;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Demux::disconnectCiCam() {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Result Demux::removeFilter(uint64_t filterId) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mDvrPlayback != nullptr) {
+ mDvrPlayback->removePlaybackFilter(filterId);
+ }
+ mPlaybackFilterIds.erase(filterId);
+ mRecordFilterIds.erase(filterId);
+ mFilters.erase(filterId);
+
+ return Result::SUCCESS;
+}
+
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
+ set<uint64_t>::iterator it;
+ uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+ if (DEBUG_DEMUX) {
+ ALOGW("[Demux] start ts filter pid: %d", pid);
+ }
+ for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+ if (pid == mFilters[*it]->getTpid()) {
+ mFilters[*it]->updateFilterOutput(data);
+ }
+ }
+}
+
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+ set<uint64_t>::iterator it;
+ if (DEBUG_DEMUX) {
+ ALOGW("[Demux] update record filter output");
+ }
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ mFilters[*it]->updateRecordOutput(data);
+ }
+}
+
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data, uint16_t pid, uint64_t pts) {
+ sendFrontendInputToRecord(data);
+ set<uint64_t>::iterator it;
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (pid == mFilters[*it]->getTpid()) {
+ mFilters[*it]->updatePts(pts);
+ }
+ }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
+ set<uint64_t>::iterator it;
+
+ // Handle the output data per filter type
+ for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+ if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Demux::startRecordFilterDispatcher() {
+ set<uint64_t>::iterator it;
+
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Result Demux::startFilterHandler(uint64_t filterId) {
+ return mFilters[filterId]->startFilterHandler();
+}
+
+void Demux::updateFilterOutput(uint64_t filterId, vector<uint8_t> data) {
+ mFilters[filterId]->updateFilterOutput(data);
+}
+
+void Demux::updateMediaFilterOutput(uint64_t filterId, vector<uint8_t> data, uint64_t pts) {
+ updateFilterOutput(filterId, data);
+ mFilters[filterId]->updatePts(pts);
+}
+
+uint16_t Demux::getFilterTpid(uint64_t filterId) {
+ return mFilters[filterId]->getTpid();
+}
+
+void Demux::startFrontendInputLoop() {
+ pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+ pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
+}
+
+void* Demux::__threadLoopFrontend(void* user) {
+ Demux* const self = static_cast<Demux*>(user);
+ self->frontendInputThreadLoop();
+ return 0;
+}
+
+void Demux::frontendInputThreadLoop() {
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+ mFrontendInputThreadRunning = true;
+
+ if (!mDvrPlayback) {
+ ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
+ mFrontendInputThreadRunning = false;
+ return;
+ }
+
+ while (mFrontendInputThreadRunning) {
+ uint32_t efState = 0;
+ status_t status = mDvrPlayback->getDvrEventFlag()->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+ true /* retry on spurious wake */);
+ if (status != OK) {
+ ALOGD("[Demux] wait for data ready on the playback FMQ");
+ continue;
+ }
+ if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
+ if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
+ ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
+ break;
+ }
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ immediately
+ // after the DATA_READY from the VTS/framework
+ // This is for the non-ES data source, real playback use case handling.
+ if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
+ !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
+ ALOGE("[Demux] playback data failed to be filtered. Ending thread");
+ break;
+ }
+ }
+
+ mFrontendInputThreadRunning = false;
+ ALOGW("[Demux] Frontend Input thread end.");
+}
+
+void Demux::stopFrontendInput() {
+ ALOGD("[Demux] stop frontend on demux");
+ mKeepFetchingDataFromFrontend = false;
+ mFrontendInputThreadRunning = false;
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+ mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(uint64_t filterId) {
+ if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
+ !mFilters[filterId]->isRecordFilter()) {
+ return false;
+ }
+
+ mRecordFilterIds.insert(filterId);
+ mFilters[filterId]->attachFilterToRecord(mDvrRecord);
+
+ return true;
+}
+
+bool Demux::detachRecordFilter(uint64_t filterId) {
+ if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.erase(filterId);
+ mFilters[filterId]->detachFilterFromRecord();
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Demux.h b/tv/tuner/1.1/default/Demux.h
new file mode 100644
index 0000000..5212eae
--- /dev/null
+++ b/tv/tuner/1.1/default/Demux.h
@@ -0,0 +1,198 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
+
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Dvr.h"
+#include "Filter.h"
+#include "Frontend.h"
+#include "TimeFilter.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Dvr;
+class Filter;
+class Frontend;
+class TimeFilter;
+class Tuner;
+
+class Demux : public IDemux {
+ public:
+ Demux(uint32_t demuxId, sp<Tuner> tuner);
+
+ ~Demux();
+
+ virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
+
+ virtual Return<void> openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) override;
+
+ virtual Return<void> openTimeFilter(openTimeFilter_cb _hidl_cb) override;
+
+ virtual Return<void> getAvSyncHwId(const sp<IFilter>& filter,
+ getAvSyncHwId_cb _hidl_cb) override;
+
+ virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
+
+ virtual Return<Result> close() override;
+
+ virtual Return<void> openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+ openDvr_cb _hidl_cb) override;
+
+ virtual Return<Result> connectCiCam(uint32_t ciCamId) override;
+
+ virtual Return<Result> disconnectCiCam() override;
+
+ // Functions interacts with Tuner Service
+ void stopFrontendInput();
+ Result removeFilter(uint64_t filterId);
+ bool attachRecordFilter(uint64_t filterId);
+ bool detachRecordFilter(uint64_t filterId);
+ Result startFilterHandler(uint64_t filterId);
+ void updateFilterOutput(uint64_t filterId, vector<uint8_t> data);
+ void updateMediaFilterOutput(uint64_t filterId, vector<uint8_t> data, uint64_t pts);
+ uint16_t getFilterTpid(uint64_t filterId);
+ void setIsRecording(bool isRecording);
+ void startFrontendInputLoop();
+
+ /**
+ * A dispatcher to read and dispatch input data to all the started filters.
+ * Each filter handler handles the data filtering/output writing/filterEvent updating.
+ * Note that recording filters are not included.
+ */
+ bool startBroadcastFilterDispatcher();
+ void startBroadcastTsFilter(vector<uint8_t> data);
+
+ void sendFrontendInputToRecord(vector<uint8_t> data);
+ void sendFrontendInputToRecord(vector<uint8_t> data, uint16_t pid, uint64_t pts);
+ bool startRecordFilterDispatcher();
+
+ private:
+ // Tuner service
+ sp<Tuner> mTunerService;
+
+ // Frontend source
+ sp<Frontend> mFrontend;
+
+ // A struct that passes the arguments to a newly created filter thread
+ struct ThreadArgs {
+ Demux* user;
+ uint64_t filterId;
+ };
+
+ static void* __threadLoopFrontend(void* user);
+ void frontendInputThreadLoop();
+
+ /**
+ * To create a FilterMQ with the next available Filter ID.
+ * Creating Event Flag at the same time.
+ * Add the successfully created/saved FilterMQ into the local list.
+ *
+ * Return false is any of the above processes fails.
+ */
+ void deleteEventFlag();
+ bool readDataFromMQ();
+
+ uint32_t mDemuxId = -1;
+ uint32_t mCiCamId;
+ set<uint64_t> mPcrFilterIds;
+ /**
+ * Record the last used filter id. Initial value is -1.
+ * Filter Id starts with 0.
+ */
+ uint64_t mLastUsedFilterId = -1;
+ /**
+ * Record all the used playback filter Ids.
+ * Any removed filter id should be removed from this set.
+ */
+ set<uint64_t> mPlaybackFilterIds;
+ /**
+ * Record all the attached record filter Ids.
+ * Any removed filter id should be removed from this set.
+ */
+ set<uint64_t> mRecordFilterIds;
+ /**
+ * A list of created Filter sp.
+ * The array number is the filter ID.
+ */
+ std::map<uint64_t, sp<Filter>> mFilters;
+
+ /**
+ * Local reference to the opened Timer Filter instance.
+ */
+ sp<TimeFilter> mTimeFilter;
+
+ /**
+ * Local reference to the opened DVR object.
+ */
+ sp<Dvr> mDvrPlayback;
+ sp<Dvr> mDvrRecord;
+
+ // Thread handlers
+ pthread_t mFrontendInputThread;
+ /**
+ * If a specific filter's writing loop is still running
+ */
+ bool mFrontendInputThreadRunning;
+ bool mKeepFetchingDataFromFrontend;
+ /**
+ * If the dvr recording is running.
+ */
+ bool mIsRecording = false;
+ /**
+ * Lock to protect writes to the FMQs
+ */
+ std::mutex mWriteLock;
+ /**
+ * Lock to protect writes to the input status
+ */
+ std::mutex mFrontendInputThreadLock;
+
+ // temp handle single PES filter
+ // TODO handle mulptiple Pes filters
+ int mPesSizeLeft = 0;
+ vector<uint8_t> mPesOutput;
+
+ const bool DEBUG_DEMUX = false;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
diff --git a/tv/tuner/1.1/default/Descrambler.cpp b/tv/tuner/1.1/default/Descrambler.cpp
new file mode 100644
index 0000000..1fbc780
--- /dev/null
+++ b/tv/tuner/1.1/default/Descrambler.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.tv.tuner@1.1-Descrambler"
+
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+#include "Descrambler.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Descrambler::Descrambler() {}
+
+Descrambler::~Descrambler() {}
+
+Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) {
+ ALOGV("%s", __FUNCTION__);
+ if (mDemuxSet) {
+ ALOGW("[ WARN ] Descrambler has already been set with a demux id %" PRIu32,
+ mSourceDemuxId);
+ return Result::INVALID_STATE;
+ }
+ mDemuxSet = true;
+ mSourceDemuxId = static_cast<uint32_t>(demuxId);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::setKeyToken(const hidl_vec<uint8_t>& /* keyToken */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::addPid(const DemuxPid& /* pid */,
+ const sp<IFilter>& /* optionalSourceFilter */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::removePid(const DemuxPid& /* pid */,
+ const sp<IFilter>& /* optionalSourceFilter */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::close() {
+ ALOGV("%s", __FUNCTION__);
+ mDemuxSet = false;
+
+ return Result::SUCCESS;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Descrambler.h b/tv/tuner/1.1/default/Descrambler.h
new file mode 100644
index 0000000..ffc284d
--- /dev/null
+++ b/tv/tuner/1.1/default/Descrambler.h
@@ -0,0 +1,62 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_DESCRAMBLER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DESCRAMBLER_H_
+
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <inttypes.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Descrambler : public IDescrambler {
+ public:
+ Descrambler();
+
+ virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
+
+ virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
+
+ virtual Return<Result> addPid(const DemuxPid& pid,
+ const sp<IFilter>& optionalSourceFilter) override;
+
+ virtual Return<Result> removePid(const DemuxPid& pid,
+ const sp<IFilter>& optionalSourceFilter) override;
+
+ virtual Return<Result> close() override;
+
+ private:
+ virtual ~Descrambler();
+ uint32_t mSourceDemuxId;
+ bool mDemuxSet = false;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_DESCRAMBLER_H_
diff --git a/tv/tuner/1.1/default/Dvr.cpp b/tv/tuner/1.1/default/Dvr.cpp
new file mode 100644
index 0000000..3a4ef1b
--- /dev/null
+++ b/tv/tuner/1.1/default/Dvr.cpp
@@ -0,0 +1,500 @@
+/*
+ * 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.tv.tuner@1.1-Dvr"
+
+#include "Dvr.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Dvr::Dvr() {}
+
+Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
+ mType = type;
+ mBufferSize = bufferSize;
+ mCallback = cb;
+ mDemux = demux;
+}
+
+Dvr::~Dvr() {}
+
+Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
+ return Void();
+}
+
+Return<Result> Dvr::configure(const DvrSettings& settings) {
+ ALOGV("%s", __FUNCTION__);
+
+ mDvrSettings = settings;
+ mDvrConfigured = true;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::attachFilter(const sp<V1_0::IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t filterId;
+ Result status;
+
+ sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+ if (filter_v1_1 != NULL) {
+ filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
+ filterId = id;
+ status = result;
+ });
+ } else {
+ filter->getId([&](Result result, uint32_t id) {
+ filterId = id;
+ status = result;
+ });
+ }
+
+ if (status != Result::SUCCESS) {
+ return status;
+ }
+
+ // TODO check if the attached filter is a record filter
+ if (!mDemux->attachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::detachFilter(const sp<V1_0::IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t filterId;
+ Result status;
+
+ sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+ if (filter_v1_1 != NULL) {
+ filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
+ filterId = id;
+ status = result;
+ });
+ } else {
+ filter->getId([&](Result result, uint32_t id) {
+ filterId = id;
+ status = result;
+ });
+ }
+
+ if (status != Result::SUCCESS) {
+ return status;
+ }
+
+ if (!mDemux->detachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::start() {
+ ALOGV("%s", __FUNCTION__);
+
+ if (!mCallback) {
+ return Result::NOT_INITIALIZED;
+ }
+
+ if (!mDvrConfigured) {
+ return Result::INVALID_STATE;
+ }
+
+ if (mType == DvrType::PLAYBACK) {
+ pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
+ pthread_setname_np(mDvrThread, "playback_waiting_loop");
+ } else if (mType == DvrType::RECORD) {
+ mRecordStatus = RecordStatus::DATA_READY;
+ mDemux->setIsRecording(mType == DvrType::RECORD);
+ }
+
+ // TODO start another thread to send filter status callback to the framework
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::stop() {
+ ALOGV("%s", __FUNCTION__);
+
+ mDvrThreadRunning = false;
+
+ lock_guard<mutex> lock(mDvrThreadLock);
+
+ mIsRecordStarted = false;
+ mDemux->setIsRecording(false);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::flush() {
+ ALOGV("%s", __FUNCTION__);
+
+ mRecordStatus = RecordStatus::DATA_READY;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+bool Dvr::createDvrMQ() {
+ ALOGV("%s", __FUNCTION__);
+
+ // Create a synchronized FMQ that supports blocking read/write
+ unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
+ if (!tmpDvrMQ->isValid()) {
+ ALOGW("[Dvr] Failed to create FMQ of DVR");
+ return false;
+ }
+
+ mDvrMQ = move(tmpDvrMQ);
+
+ if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
+ return false;
+ }
+
+ return true;
+}
+
+EventFlag* Dvr::getDvrEventFlag() {
+ return mDvrEventFlag;
+}
+
+void* Dvr::__threadLoopPlayback(void* user) {
+ Dvr* const self = static_cast<Dvr*>(user);
+ self->playbackThreadLoop();
+ return 0;
+}
+
+void Dvr::playbackThreadLoop() {
+ ALOGD("[Dvr] playback threadLoop start.");
+ lock_guard<mutex> lock(mDvrThreadLock);
+ mDvrThreadRunning = true;
+
+ while (mDvrThreadRunning) {
+ uint32_t efState = 0;
+ status_t status =
+ mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
+ &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
+ if (status != OK) {
+ ALOGD("[Dvr] wait for data ready on the playback FMQ");
+ continue;
+ }
+
+ if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
+ if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+ ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
+ break;
+ }
+ maySendPlaybackStatusCallback();
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ immediately
+ // after the DATA_READY from the VTS/framework
+ // This is for the non-ES data source, real playback use case handling.
+ if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
+ !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+ ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
+ break;
+ }
+
+ maySendPlaybackStatusCallback();
+ }
+
+ mDvrThreadRunning = false;
+ ALOGD("[Dvr] playback thread ended.");
+}
+
+void Dvr::maySendPlaybackStatusCallback() {
+ lock_guard<mutex> lock(mPlaybackStatusLock);
+ int availableToRead = mDvrMQ->availableToRead();
+ int availableToWrite = mDvrMQ->availableToWrite();
+
+ PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
+ mDvrSettings.playback().highThreshold,
+ mDvrSettings.playback().lowThreshold);
+ if (mPlaybackStatus != newStatus) {
+ mCallback->onPlaybackStatus(newStatus);
+ mPlaybackStatus = newStatus;
+ }
+}
+
+PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return PlaybackStatus::SPACE_FULL;
+ } else if (availableToRead > highThreshold) {
+ return PlaybackStatus::SPACE_ALMOST_FULL;
+ } else if (availableToRead < lowThreshold) {
+ return PlaybackStatus::SPACE_ALMOST_EMPTY;
+ } else if (availableToRead == 0) {
+ return PlaybackStatus::SPACE_EMPTY;
+ }
+ return mPlaybackStatus;
+}
+
+bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
+ // Read playback data from the input FMQ
+ int size = mDvrMQ->availableToRead();
+ int playbackPacketSize = mDvrSettings.playback().packetSize;
+ vector<uint8_t> dataOutputBuffer;
+ dataOutputBuffer.resize(playbackPacketSize);
+ // Dispatch the packet to the PID matching filter output buffer
+ for (int i = 0; i < size / playbackPacketSize; i++) {
+ if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
+ return false;
+ }
+ if (isVirtualFrontend) {
+ if (isRecording) {
+ mDemux->sendFrontendInputToRecord(dataOutputBuffer);
+ } else {
+ mDemux->startBroadcastTsFilter(dataOutputBuffer);
+ }
+ } else {
+ startTpidFilter(dataOutputBuffer);
+ }
+ }
+
+ return true;
+}
+
+bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
+ // Read ES from the DVR FMQ
+ // Note that currently we only provides ES with metaData in a specific format to be parsed.
+ // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
+ int size = mDvrMQ->availableToRead();
+ vector<uint8_t> dataOutputBuffer;
+ dataOutputBuffer.resize(size);
+ if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
+ return false;
+ }
+
+ int metaDataSize = size;
+ int totalFrames = 0;
+ int videoEsDataSize = 0;
+ int audioEsDataSize = 0;
+ int audioPid = 0;
+ int videoPid = 0;
+
+ vector<MediaEsMetaData> esMeta;
+ int videoReadPointer = 0;
+ int audioReadPointer = 0;
+ int frameCount = 0;
+ // Get meta data from the es
+ for (int i = 0; i < metaDataSize; i++) {
+ switch (dataOutputBuffer[i]) {
+ case 'm':
+ metaDataSize = 0;
+ getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
+ videoReadPointer = metaDataSize;
+ continue;
+ case 'l':
+ getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
+ esMeta.resize(totalFrames);
+ continue;
+ case 'V':
+ getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
+ audioReadPointer = metaDataSize + videoEsDataSize;
+ continue;
+ case 'A':
+ getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
+ continue;
+ case 'p':
+ if (dataOutputBuffer[++i] == 'a') {
+ getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
+ } else if (dataOutputBuffer[i] == 'v') {
+ getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
+ }
+ continue;
+ case 'v':
+ case 'a':
+ if (dataOutputBuffer[i + 1] != ',') {
+ ALOGE("[Dvr] Invalid format meta data.");
+ return false;
+ }
+ esMeta[frameCount] = {
+ .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
+ };
+ i += 5; // Move to Len
+ getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
+ if (esMeta[frameCount].isAudio) {
+ esMeta[frameCount].startIndex = audioReadPointer;
+ audioReadPointer += esMeta[frameCount].len;
+ } else {
+ esMeta[frameCount].startIndex = videoReadPointer;
+ videoReadPointer += esMeta[frameCount].len;
+ }
+ i += 4; // move to PTS
+ getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
+ frameCount++;
+ continue;
+ default:
+ continue;
+ }
+ }
+
+ if (frameCount != totalFrames) {
+ ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
+ totalFrames);
+ return false;
+ }
+
+ if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
+ ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
+ metaDataSize, videoEsDataSize, audioEsDataSize, size);
+ return false;
+ }
+
+ // Read es raw data from the FMQ per meta data built previously
+ vector<uint8_t> frameData;
+ map<uint64_t, sp<IFilter>>::iterator it;
+ int pid = 0;
+ for (int i = 0; i < totalFrames; i++) {
+ frameData.resize(esMeta[i].len);
+ pid = esMeta[i].isAudio ? audioPid : videoPid;
+ memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
+ // Send to the media filters or record filters
+ if (!isRecording) {
+ for (it = mFilters.begin(); it != mFilters.end(); it++) {
+ if (pid == mDemux->getFilterTpid(it->first)) {
+ mDemux->updateMediaFilterOutput(it->first, frameData,
+ static_cast<uint64_t>(esMeta[i].pts));
+ }
+ }
+ } else {
+ mDemux->sendFrontendInputToRecord(frameData, pid, static_cast<uint64_t>(esMeta[i].pts));
+ }
+ startFilterDispatcher(isVirtualFrontend, isRecording);
+ frameData.clear();
+ }
+
+ return true;
+}
+
+void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
+ index += 2; // Move the pointer across the ":" to the value
+ while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
+ value = ((dataOutputBuffer[index++] - 48) + value * 10);
+ }
+}
+
+void Dvr::startTpidFilter(vector<uint8_t> data) {
+ map<uint64_t, sp<IFilter>>::iterator it;
+ for (it = mFilters.begin(); it != mFilters.end(); it++) {
+ uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+ if (DEBUG_DVR) {
+ ALOGW("[Dvr] start ts filter pid: %d", pid);
+ }
+ if (pid == mDemux->getFilterTpid(it->first)) {
+ mDemux->updateFilterOutput(it->first, data);
+ }
+ }
+}
+
+bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
+ if (isVirtualFrontend) {
+ if (isRecording) {
+ return mDemux->startRecordFilterDispatcher();
+ } else {
+ return mDemux->startBroadcastFilterDispatcher();
+ }
+ }
+
+ map<uint64_t, sp<IFilter>>::iterator it;
+ // Handle the output data per filter type
+ for (it = mFilters.begin(); it != mFilters.end(); it++) {
+ if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
+ lock_guard<mutex> lock(mWriteLock);
+ if (mRecordStatus == RecordStatus::OVERFLOW) {
+ ALOGW("[Dvr] stops writing and wait for the client side flushing.");
+ return true;
+ }
+ if (mDvrMQ->write(data.data(), data.size())) {
+ mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ maySendRecordStatusCallback();
+ return true;
+ }
+
+ maySendRecordStatusCallback();
+ return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+ lock_guard<mutex> lock(mRecordStatusLock);
+ int availableToRead = mDvrMQ->availableToRead();
+ int availableToWrite = mDvrMQ->availableToWrite();
+
+ RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+ mDvrSettings.record().highThreshold,
+ mDvrSettings.record().lowThreshold);
+ if (mRecordStatus != newStatus) {
+ mCallback->onRecordStatus(newStatus);
+ mRecordStatus = newStatus;
+ }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mRecordStatus;
+}
+
+bool Dvr::addPlaybackFilter(uint64_t filterId, sp<IFilter> filter) {
+ mFilters[filterId] = filter;
+ return true;
+}
+
+bool Dvr::removePlaybackFilter(uint64_t filterId) {
+ mFilters.erase(filterId);
+ return true;
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Dvr.h b/tv/tuner/1.1/default/Dvr.h
new file mode 100644
index 0000000..7b7efef
--- /dev/null
+++ b/tv/tuner/1.1/default/Dvr.h
@@ -0,0 +1,167 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
+
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+struct MediaEsMetaData {
+ bool isAudio;
+ int startIndex;
+ int len;
+ int pts;
+};
+
+class Demux;
+class Filter;
+class Frontend;
+class Tuner;
+
+class Dvr : public IDvr {
+ public:
+ Dvr();
+
+ Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux);
+
+ ~Dvr();
+
+ virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+ virtual Return<Result> configure(const DvrSettings& settings) override;
+
+ virtual Return<Result> attachFilter(const sp<IFilter>& filter) override;
+
+ virtual Return<Result> detachFilter(const sp<IFilter>& filter) override;
+
+ virtual Return<Result> start() override;
+
+ virtual Return<Result> stop() override;
+
+ virtual Return<Result> flush() override;
+
+ virtual Return<Result> close() override;
+
+ /**
+ * To create a DvrMQ and its Event Flag.
+ *
+ * Return false is any of the above processes fails.
+ */
+ bool createDvrMQ();
+ void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+ bool writeRecordFMQ(const std::vector<uint8_t>& data);
+ bool addPlaybackFilter(uint64_t filterId, sp<IFilter> filter);
+ bool removePlaybackFilter(uint64_t filterId);
+ bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+ bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
+ bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
+ EventFlag* getDvrEventFlag();
+ DvrSettings getSettings() { return mDvrSettings; }
+
+ private:
+ // Demux service
+ sp<Demux> mDemux;
+
+ DvrType mType;
+ uint32_t mBufferSize;
+ sp<IDvrCallback> mCallback;
+ std::map<uint64_t, sp<IFilter>> mFilters;
+
+ void deleteEventFlag();
+ bool readDataFromMQ();
+ void getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value);
+ void maySendPlaybackStatusCallback();
+ void maySendRecordStatusCallback();
+ PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
+ RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
+ /**
+ * A dispatcher to read and dispatch input data to all the started filters.
+ * Each filter handler handles the data filtering/output writing/filterEvent updating.
+ */
+ void startTpidFilter(vector<uint8_t> data);
+ static void* __threadLoopPlayback(void* user);
+ static void* __threadLoopRecord(void* user);
+ void playbackThreadLoop();
+ void recordThreadLoop();
+
+ unique_ptr<DvrMQ> mDvrMQ;
+ EventFlag* mDvrEventFlag;
+ /**
+ * Demux callbacks used on filter events or IO buffer status
+ */
+ bool mDvrConfigured = false;
+ DvrSettings mDvrSettings;
+
+ // Thread handlers
+ pthread_t mDvrThread;
+
+ // FMQ status local records
+ PlaybackStatus mPlaybackStatus;
+ RecordStatus mRecordStatus;
+ /**
+ * If a specific filter's writing loop is still running
+ */
+ bool mDvrThreadRunning;
+ bool mKeepFetchingDataFromFrontend;
+ /**
+ * Lock to protect writes to the FMQs
+ */
+ std::mutex mWriteLock;
+ /**
+ * Lock to protect writes to the input status
+ */
+ std::mutex mPlaybackStatusLock;
+ std::mutex mRecordStatusLock;
+ std::mutex mDvrThreadLock;
+
+ const bool DEBUG_DVR = false;
+
+ // Booleans to check if recording is running.
+ // Recording is ready when both of the following are set to true.
+ bool mIsRecordStarted = false;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
new file mode 100644
index 0000000..4c37729
--- /dev/null
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -0,0 +1,892 @@
+/*
+ * 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.tv.tuner@1.1-Filter"
+
+#include "Filter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Filter::Filter() {}
+
+Filter::Filter(DemuxFilterType type, uint64_t filterId, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, sp<Demux> demux) {
+ mType = type;
+ mFilterId = filterId;
+ mBufferSize = bufferSize;
+ mDemux = demux;
+
+ switch (mType.mainType) {
+ case DemuxFilterMainType::TS:
+ if (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+ mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+ mIsMediaFilter = true;
+ }
+ if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) {
+ mIsPcrFilter = true;
+ }
+ if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) {
+ mIsRecordFilter = true;
+ }
+ break;
+ case DemuxFilterMainType::MMTP:
+ if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+ mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+ mIsMediaFilter = true;
+ }
+ if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) {
+ mIsRecordFilter = true;
+ }
+ break;
+ case DemuxFilterMainType::IP:
+ break;
+ case DemuxFilterMainType::TLV:
+ break;
+ case DemuxFilterMainType::ALP:
+ break;
+ default:
+ break;
+ }
+
+ sp<V1_1::IFilterCallback> filterCallback_v1_1 = V1_1::IFilterCallback::castFrom(cb);
+ if (filterCallback_v1_1 != NULL) {
+ mCallback_1_1 = filterCallback_v1_1;
+ } else {
+ mCallback = cb;
+ }
+}
+
+Filter::~Filter() {}
+
+Return<void> Filter::getId64Bit(getId64Bit_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ _hidl_cb(Result::SUCCESS, mFilterId);
+ return Void();
+}
+
+Return<void> Filter::getId(getId_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ _hidl_cb(Result::SUCCESS, static_cast<uint32_t>(mFilterId));
+ return Void();
+}
+
+Return<Result> Filter::setDataSource(const sp<V1_0::IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ mDataSource = filter;
+ mIsDataSourceDemux = false;
+
+ return Result::SUCCESS;
+}
+
+Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ mIsUsingFMQ = mIsRecordFilter ? false : true;
+
+ _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
+ return Void();
+}
+
+Return<Result> Filter::configure(const DemuxFilterSettings& settings) {
+ ALOGV("%s", __FUNCTION__);
+
+ mFilterSettings = settings;
+ switch (mType.mainType) {
+ case DemuxFilterMainType::TS:
+ mTpid = settings.ts().tpid;
+ break;
+ case DemuxFilterMainType::MMTP:
+ break;
+ case DemuxFilterMainType::IP:
+ break;
+ case DemuxFilterMainType::TLV:
+ break;
+ case DemuxFilterMainType::ALP:
+ break;
+ default:
+ break;
+ }
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Filter::start() {
+ ALOGV("%s", __FUNCTION__);
+
+ return startFilterLoop();
+}
+
+Return<Result> Filter::stop() {
+ ALOGV("%s", __FUNCTION__);
+
+ mFilterThreadRunning = false;
+
+ std::lock_guard<std::mutex> lock(mFilterThreadLock);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Filter::flush() {
+ ALOGV("%s", __FUNCTION__);
+
+ // temp implementation to flush the FMQ
+ int size = mFilterMQ->availableToRead();
+ char* buffer = new char[size];
+ mFilterMQ->read((unsigned char*)&buffer[0], size);
+ delete[] buffer;
+ mFilterStatus = DemuxFilterStatus::DATA_READY;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) {
+ ALOGV("%s", __FUNCTION__);
+
+ if ((avMemory.getNativeHandle()->numFds > 0) &&
+ (mSharedAvMemHandle.getNativeHandle()->numFds > 0) &&
+ (sameFile(avMemory.getNativeHandle()->data[0],
+ mSharedAvMemHandle.getNativeHandle()->data[0]))) {
+ freeSharedAvHandle();
+ return Result::SUCCESS;
+ }
+
+ if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
+ return Result::INVALID_ARGUMENT;
+ }
+
+ ::close(mDataId2Avfd[avDataId]);
+ return Result::SUCCESS;
+}
+
+Return<Result> Filter::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ return mDemux->removeFilter(mFilterId);
+}
+
+Return<Result> Filter::configureIpCid(uint32_t ipCid) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mType.mainType != DemuxFilterMainType::IP) {
+ return Result::INVALID_STATE;
+ }
+
+ mCid = ipCid;
+ return Result::SUCCESS;
+}
+
+Return<void> Filter::getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (!mIsMediaFilter) {
+ _hidl_cb(Result::INVALID_STATE, NULL, BUFFER_SIZE_16M);
+ return Void();
+ }
+
+ if (mSharedAvMemHandle.getNativeHandle() != nullptr) {
+ _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
+ return Void();
+ }
+
+ int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+ if (av_fd == -1) {
+ _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
+ }
+
+ native_handle_t* nativeHandle = createNativeHandle(av_fd);
+ if (nativeHandle == NULL) {
+ _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
+ }
+ mSharedAvMemHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+ ::close(av_fd);
+
+ _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
+ return Void();
+}
+
+Return<Result> Filter::configureAvStreamType(const V1_1::AvStreamType& avStreamType) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (!mIsMediaFilter) {
+ return Result::UNAVAILABLE;
+ }
+
+ switch (avStreamType.getDiscriminator()) {
+ case V1_1::AvStreamType::hidl_discriminator::audio:
+ mAudioStreamType = static_cast<uint32_t>(avStreamType.audio());
+ break;
+ case V1_1::AvStreamType::hidl_discriminator::video:
+ mVideoStreamType = static_cast<uint32_t>(avStreamType.video());
+ break;
+ default:
+ break;
+ }
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Filter::configureScramblingEvent(uint32_t statuses) {
+ 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;
+
+ mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, filterEventExt);
+ mFilterEventExt.events.resize(0);
+ } else {
+ return Result::INVALID_STATE;
+ }
+ return Result::SUCCESS;
+}
+
+bool Filter::createFilterMQ() {
+ ALOGV("%s", __FUNCTION__);
+
+ // Create a synchronized FMQ that supports blocking read/write
+ std::unique_ptr<FilterMQ> tmpFilterMQ =
+ std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
+ if (!tmpFilterMQ->isValid()) {
+ ALOGW("[Filter] Failed to create FMQ of filter with id: %" PRIu64, mFilterId);
+ return false;
+ }
+
+ mFilterMQ = std::move(tmpFilterMQ);
+
+ if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) {
+ return false;
+ }
+
+ return true;
+}
+
+Result Filter::startFilterLoop() {
+ pthread_create(&mFilterThread, NULL, __threadLoopFilter, this);
+ pthread_setname_np(mFilterThread, "filter_waiting_loop");
+
+ return Result::SUCCESS;
+}
+
+void* Filter::__threadLoopFilter(void* user) {
+ Filter* const self = static_cast<Filter*>(user);
+ self->filterThreadLoop();
+ return 0;
+}
+
+void Filter::filterThreadLoop() {
+ ALOGD("[Filter] filter %" PRIu64 " threadLoop start.", mFilterId);
+ std::lock_guard<std::mutex> lock(mFilterThreadLock);
+ mFilterThreadRunning = true;
+
+ // For the first time of filter output, implementation needs to send the filter
+ // Event Callback without waiting for the DATA_CONSUMED to init the process.
+ while (mFilterThreadRunning) {
+ if (mFilterEvent.events.size() == 0 && mFilterEventExt.events.size() == 0) {
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] wait for filter data output.");
+ }
+ usleep(1000 * 1000);
+ continue;
+ }
+ // After successfully write, send a callback and wait for the read to be done
+ if (mCallback_1_1 != nullptr) {
+ mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
+ mFilterEventExt.events.resize(0);
+ } else if (mCallback != nullptr) {
+ mCallback->onFilterEvent(mFilterEvent);
+ } else {
+ ALOGD("[Filter] filter callback is not configured yet.");
+ mFilterThreadRunning = false;
+ return;
+ }
+ mFilterEvent.events.resize(0);
+
+ freeAvHandle();
+ mFilterStatus = DemuxFilterStatus::DATA_READY;
+ if (mCallback != nullptr) {
+ mCallback->onFilterStatus(mFilterStatus);
+ } else if (mCallback_1_1 != nullptr) {
+ mCallback_1_1->onFilterStatus(mFilterStatus);
+ }
+ break;
+ }
+
+ while (mFilterThreadRunning) {
+ uint32_t efState = 0;
+ // We do not wait for the last round of written data to be read to finish the thread
+ // because the VTS can verify the reading itself.
+ for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
+ while (mFilterThreadRunning && mIsUsingFMQ) {
+ status_t status = mFilterEventFlag->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
+ WAIT_TIMEOUT, true /* retry on spurious wake */);
+ if (status != OK) {
+ ALOGD("[Filter] wait for data consumed");
+ continue;
+ }
+ break;
+ }
+
+ maySendFilterStatusCallback();
+
+ while (mFilterThreadRunning) {
+ std::lock_guard<std::mutex> lock(mFilterEventLock);
+ if (mFilterEvent.events.size() == 0 && mFilterEventExt.events.size() == 0) {
+ continue;
+ }
+ // After successfully write, send a callback and wait for the read to be done
+ if (mCallback_1_1 != nullptr) {
+ mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
+ mFilterEventExt.events.resize(0);
+ } else if (mCallback != nullptr) {
+ mCallback->onFilterEvent(mFilterEvent);
+ }
+ mFilterEvent.events.resize(0);
+ break;
+ }
+ // We do not wait for the last read to be done
+ // VTS can verify the read result itself.
+ if (i == SECTION_WRITE_COUNT - 1) {
+ ALOGD("[Filter] filter %" PRIu64 " writing done. Ending thread", mFilterId);
+ break;
+ }
+ }
+ mFilterThreadRunning = false;
+ }
+
+ ALOGD("[Filter] filter thread ended.");
+}
+
+void Filter::freeAvHandle() {
+ if (!mIsMediaFilter) {
+ return;
+ }
+ for (int i = 0; i < mFilterEvent.events.size(); i++) {
+ ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
+ native_handle_delete(const_cast<native_handle_t*>(
+ mFilterEvent.events[i].media().avMemory.getNativeHandle()));
+ }
+}
+
+void Filter::freeSharedAvHandle() {
+ if (!mIsMediaFilter) {
+ return;
+ }
+ ::close(mSharedAvMemHandle.getNativeHandle()->data[0]);
+ native_handle_delete(const_cast<native_handle_t*>(mSharedAvMemHandle.getNativeHandle()));
+}
+
+void Filter::maySendFilterStatusCallback() {
+ if (!mIsUsingFMQ) {
+ return;
+ }
+ std::lock_guard<std::mutex> lock(mFilterStatusLock);
+ int availableToRead = mFilterMQ->availableToRead();
+ int availableToWrite = mFilterMQ->availableToWrite();
+ int fmqSize = mFilterMQ->getQuantumCount();
+
+ DemuxFilterStatus newStatus = checkFilterStatusChange(
+ availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
+ if (mFilterStatus != newStatus) {
+ if (mCallback != nullptr) {
+ mCallback->onFilterStatus(newStatus);
+ } else if (mCallback_1_1 != nullptr) {
+ mCallback_1_1->onFilterStatus(newStatus);
+ }
+ mFilterStatus = newStatus;
+ }
+}
+
+DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite,
+ uint32_t availableToRead, uint32_t highThreshold,
+ uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mFilterStatus;
+}
+
+uint16_t Filter::getTpid() {
+ return mTpid;
+}
+
+void Filter::updateFilterOutput(vector<uint8_t> data) {
+ std::lock_guard<std::mutex> lock(mFilterOutputLock);
+ mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
+}
+
+void Filter::updatePts(uint64_t pts) {
+ std::lock_guard<std::mutex> lock(mFilterOutputLock);
+ mPts = pts;
+}
+
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
+Result Filter::startFilterHandler() {
+ std::lock_guard<std::mutex> lock(mFilterOutputLock);
+ switch (mType.mainType) {
+ case DemuxFilterMainType::TS:
+ switch (mType.subType.tsFilterType()) {
+ case DemuxTsFilterType::UNDEFINED:
+ break;
+ case DemuxTsFilterType::SECTION:
+ startSectionFilterHandler();
+ break;
+ case DemuxTsFilterType::PES:
+ startPesFilterHandler();
+ break;
+ case DemuxTsFilterType::TS:
+ startTsFilterHandler();
+ break;
+ case DemuxTsFilterType::AUDIO:
+ case DemuxTsFilterType::VIDEO:
+ startMediaFilterHandler();
+ break;
+ case DemuxTsFilterType::PCR:
+ startPcrFilterHandler();
+ break;
+ case DemuxTsFilterType::TEMI:
+ startTemiFilterHandler();
+ break;
+ default:
+ break;
+ }
+ break;
+ case DemuxFilterMainType::MMTP:
+ /*mmtpSettings*/
+ break;
+ case DemuxFilterMainType::IP:
+ /*ipSettings*/
+ break;
+ case DemuxFilterMainType::TLV:
+ /*tlvSettings*/
+ break;
+ case DemuxFilterMainType::ALP:
+ /*alpSettings*/
+ break;
+ default:
+ break;
+ }
+ return Result::SUCCESS;
+}
+
+Result Filter::startSectionFilterHandler() {
+ if (mFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
+ if (!writeSectionsAndCreateEvent(mFilterOutput)) {
+ ALOGD("[Filter] filter %" PRIu64 " fails to write into FMQ. Ending thread", mFilterId);
+ return Result::UNKNOWN_ERROR;
+ }
+
+ mFilterOutput.clear();
+
+ return Result::SUCCESS;
+}
+
+Result Filter::startPesFilterHandler() {
+ std::lock_guard<std::mutex> lock(mFilterEventLock);
+ if (mFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
+
+ for (int i = 0; i < mFilterOutput.size(); i += 188) {
+ if (mPesSizeLeft == 0) {
+ uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+ mFilterOutput[i + 6];
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] prefix %d", prefix);
+ }
+ if (prefix == 0x000001) {
+ // TODO handle mulptiple Pes filters
+ mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+ mPesSizeLeft += 6;
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ }
+ } else {
+ continue;
+ }
+ }
+
+ int endPoint = min(184, mPesSizeLeft);
+ // append data and check size
+ vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+ vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+ mPesOutput.insert(mPesOutput.end(), first, last);
+ // size does not match then continue
+ mPesSizeLeft -= endPoint;
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ }
+ if (mPesSizeLeft > 0) {
+ continue;
+ }
+ // size match then create event
+ if (!writeDataToFilterMQ(mPesOutput)) {
+ ALOGD("[Filter] pes data write failed");
+ mFilterOutput.clear();
+ return Result::INVALID_STATE;
+ }
+ maySendFilterStatusCallback();
+ DemuxFilterPesEvent pesEvent;
+ pesEvent = {
+ // temp dump meta data
+ .streamId = mPesOutput[3],
+ .dataLength = static_cast<uint16_t>(mPesOutput.size()),
+ };
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ }
+
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].pes(pesEvent);
+ mPesOutput.clear();
+ }
+
+ mFilterOutput.clear();
+
+ return Result::SUCCESS;
+}
+
+Result Filter::startTsFilterHandler() {
+ // TODO handle starting TS filter
+ return Result::SUCCESS;
+}
+
+Result Filter::startMediaFilterHandler() {
+ std::lock_guard<std::mutex> lock(mFilterEventLock);
+ if (mFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
+
+ Result result;
+ if (mPts) {
+ result = createMediaFilterEventWithIon(mFilterOutput);
+ if (result == Result::SUCCESS) {
+ mFilterOutput.clear();
+ }
+ return result;
+ }
+
+ for (int i = 0; i < mFilterOutput.size(); i += 188) {
+ if (mPesSizeLeft == 0) {
+ uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+ mFilterOutput[i + 6];
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] prefix %d", prefix);
+ }
+ if (prefix == 0x000001) {
+ // TODO handle mulptiple Pes filters
+ mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+ mPesSizeLeft += 6;
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ }
+ } else {
+ continue;
+ }
+ }
+
+ int endPoint = min(184, mPesSizeLeft);
+ // append data and check size
+ vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+ vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+ mPesOutput.insert(mPesOutput.end(), first, last);
+ // size does not match then continue
+ mPesSizeLeft -= endPoint;
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ }
+ if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) {
+ continue;
+ }
+
+ result = createMediaFilterEventWithIon(mPesOutput);
+ if (result != Result::SUCCESS) {
+ return result;
+ }
+ }
+
+ mFilterOutput.clear();
+
+ return Result::SUCCESS;
+}
+
+Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
+ if (mUsingSharedAvMem) {
+ if (mSharedAvMemHandle.getNativeHandle() == nullptr) {
+ return Result::UNKNOWN_ERROR;
+ }
+ return createShareMemMediaEvents(output);
+ }
+
+ return createIndependentMediaEvents(output);
+}
+
+Result Filter::startRecordFilterHandler() {
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ if (mRecordFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
+
+ if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+ ALOGD("[Filter] dvr fails to write into record FMQ.");
+ return Result::UNKNOWN_ERROR;
+ }
+
+ V1_0::DemuxFilterTsRecordEvent recordEvent;
+ recordEvent = {
+ .byteNumber = mRecordFilterOutput.size(),
+ };
+ V1_1::DemuxFilterRecordEventExt recordEventExt;
+ recordEventExt = {
+ .pts = (mPts == 0) ? time(NULL) * 900000 : mPts,
+ .firstMbInSlice = 0, // random address
+ .mpuSequenceNumber = 1, // random sequence number
+ };
+
+ int size;
+ size = mFilterEventExt.events.size();
+ mFilterEventExt.events.resize(size + 1);
+ mFilterEventExt.events[size].tsRecord(recordEventExt);
+ size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].tsRecord(recordEvent);
+
+ mRecordFilterOutput.clear();
+ return Result::SUCCESS;
+}
+
+Result Filter::startPcrFilterHandler() {
+ // TODO handle starting PCR filter
+ return Result::SUCCESS;
+}
+
+Result Filter::startTemiFilterHandler() {
+ // TODO handle starting TEMI filter
+ return Result::SUCCESS;
+}
+
+bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
+ // TODO check how many sections has been read
+ ALOGD("[Filter] section handler");
+ std::lock_guard<std::mutex> lock(mFilterEventLock);
+ if (!writeDataToFilterMQ(data)) {
+ return false;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ DemuxFilterSectionEvent secEvent;
+ secEvent = {
+ // temp dump meta data
+ .tableId = 0,
+ .version = 1,
+ .sectionNum = 1,
+ .dataLength = static_cast<uint16_t>(data.size()),
+ };
+ mFilterEvent.events[size].section(secEvent);
+ return true;
+}
+
+bool Filter::writeDataToFilterMQ(const std::vector<uint8_t>& data) {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ if (mFilterMQ->write(data.data(), data.size())) {
+ return true;
+ }
+ return false;
+}
+
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+ mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+ mDvr = nullptr;
+}
+
+int Filter::createAvIonFd(int size) {
+ // Create an ion fd and allocate an av fd mapped to a buffer to it.
+ int ion_fd = ion_open();
+ if (ion_fd == -1) {
+ ALOGE("[Filter] Failed to open ion fd %d", errno);
+ return -1;
+ }
+ int av_fd = -1;
+ ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd);
+ if (av_fd == -1) {
+ ALOGE("[Filter] Failed to create av fd %d", errno);
+ return -1;
+ }
+ return av_fd;
+}
+
+uint8_t* Filter::getIonBuffer(int fd, int size) {
+ uint8_t* avBuf = static_cast<uint8_t*>(
+ mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/));
+ if (avBuf == MAP_FAILED) {
+ ALOGE("[Filter] fail to allocate buffer %d", errno);
+ return NULL;
+ }
+ return avBuf;
+}
+
+native_handle_t* Filter::createNativeHandle(int fd) {
+ native_handle_t* nativeHandle;
+ if (fd < 0) {
+ nativeHandle = native_handle_create(/*numFd*/ 0, 0);
+ } else {
+ // Create a native handle to pass the av fd via the callback event.
+ nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+ }
+ if (nativeHandle == NULL) {
+ ALOGE("[Filter] Failed to create native_handle %d", errno);
+ return NULL;
+ }
+ if (nativeHandle->numFds > 0) {
+ nativeHandle->data[0] = dup(fd);
+ }
+ return nativeHandle;
+}
+
+Result Filter::createIndependentMediaEvents(vector<uint8_t> output) {
+ int av_fd = createAvIonFd(output.size());
+ if (av_fd == -1) {
+ return Result::UNKNOWN_ERROR;
+ }
+ // copy the filtered data to the buffer
+ uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
+ if (avBuffer == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
+
+ native_handle_t* nativeHandle = createNativeHandle(av_fd);
+ if (nativeHandle == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+ // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+ uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+ mDataId2Avfd[dataId] = dup(av_fd);
+
+ // Create mediaEvent and send callback
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ .avMemory = std::move(handle),
+ .dataLength = static_cast<uint32_t>(output.size()),
+ .avDataId = dataId,
+ };
+ if (mPts) {
+ mediaEvent.pts = mPts;
+ mPts = 0;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].media(mediaEvent);
+
+ // Clear and log
+ output.clear();
+ mAvBufferCopyCount = 0;
+ ::close(av_fd);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
+ }
+ return Result::SUCCESS;
+}
+
+Result Filter::createShareMemMediaEvents(vector<uint8_t> output) {
+ // copy the filtered data to the shared buffer
+ uint8_t* sharedAvBuffer = getIonBuffer(mSharedAvMemHandle.getNativeHandle()->data[0],
+ output.size() + mSharedAvMemOffset);
+ if (sharedAvBuffer == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ memcpy(sharedAvBuffer + mSharedAvMemOffset, output.data(), output.size() * sizeof(uint8_t));
+
+ // Create a memory handle with numFds == 0
+ native_handle_t* nativeHandle = createNativeHandle(-1);
+ if (nativeHandle == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+ // Create mediaEvent and send callback
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ .offset = static_cast<uint32_t>(mSharedAvMemOffset),
+ .dataLength = static_cast<uint32_t>(output.size()),
+ .avMemory = handle,
+ };
+ mSharedAvMemOffset += output.size();
+ if (mPts) {
+ mediaEvent.pts = mPts;
+ mPts = 0;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].media(mediaEvent);
+
+ // Clear and log
+ output.clear();
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] shared av data length %d", mediaEvent.dataLength);
+ }
+ return Result::SUCCESS;
+}
+
+bool Filter::sameFile(int fd1, int fd2) {
+ struct stat stat1, stat2;
+ if (fstat(fd1, &stat1) < 0 || fstat(fd2, &stat2) < 0) {
+ return false;
+ }
+ return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
new file mode 100644
index 0000000..522db35
--- /dev/null
+++ b/tv/tuner/1.1/default/Filter.h
@@ -0,0 +1,247 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
+
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <fmq/MessageQueue.h>
+#include <inttypes.h>
+#include <ion/ion.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <set>
+#include "Demux.h"
+#include "Dvr.h"
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+const uint32_t BUFFER_SIZE_16M = 0x1000000;
+
+class Demux;
+class Dvr;
+
+class Filter : public V1_1::IFilter {
+ public:
+ Filter();
+
+ Filter(DemuxFilterType type, uint64_t filterId, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, sp<Demux> demux);
+
+ ~Filter();
+
+ virtual Return<void> getId64Bit(getId64Bit_cb _hidl_cb) override;
+
+ virtual Return<void> getId(getId_cb _hidl_cb) override;
+
+ virtual Return<Result> setDataSource(const sp<V1_0::IFilter>& filter) override;
+
+ virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+ virtual Return<Result> configure(const DemuxFilterSettings& settings) override;
+
+ virtual Return<Result> start() override;
+
+ virtual Return<Result> stop() override;
+
+ virtual Return<Result> flush() override;
+
+ virtual Return<Result> releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) override;
+
+ virtual Return<Result> close() override;
+
+ virtual Return<Result> configureIpCid(uint32_t ipCid) override;
+
+ virtual Return<void> getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) override;
+
+ virtual Return<Result> configureAvStreamType(const V1_1::AvStreamType& avStreamType) override;
+
+ virtual Return<Result> configureScramblingEvent(uint32_t statuses) override;
+
+ /**
+ * To create a FilterMQ and its Event Flag.
+ *
+ * Return false is any of the above processes fails.
+ */
+ bool createFilterMQ();
+ uint16_t getTpid();
+ void updateFilterOutput(vector<uint8_t> data);
+ void updateRecordOutput(vector<uint8_t> data);
+ void updatePts(uint64_t pts);
+ Result startFilterHandler();
+ Result startRecordFilterHandler();
+ void attachFilterToRecord(const sp<Dvr> dvr);
+ void detachFilterFromRecord();
+ void freeAvHandle();
+ void freeSharedAvHandle();
+ bool isMediaFilter() { return mIsMediaFilter; };
+ bool isPcrFilter() { return mIsPcrFilter; };
+ bool isRecordFilter() { return mIsRecordFilter; };
+
+ private:
+ // Tuner service
+ sp<Demux> mDemux;
+ // Dvr reference once the filter is attached to any
+ sp<Dvr> mDvr = nullptr;
+ /**
+ * Filter callbacks used on filter events or FMQ status
+ */
+ sp<IFilterCallback> mCallback = nullptr;
+
+ /**
+ * V1_1 Filter callbacks used on filter events or FMQ status
+ */
+ sp<V1_1::IFilterCallback> mCallback_1_1 = nullptr;
+
+ uint64_t mFilterId;
+ uint32_t mCid = static_cast<uint32_t>(V1_1::Constant::INVALID_IP_FILTER_CONTEXT_ID);
+ uint32_t mBufferSize;
+ DemuxFilterType mType;
+ bool mIsMediaFilter = false;
+ bool mIsPcrFilter = false;
+ bool mIsRecordFilter = false;
+ DemuxFilterSettings mFilterSettings;
+
+ uint16_t mTpid;
+ sp<V1_0::IFilter> mDataSource;
+ bool mIsDataSourceDemux = true;
+ vector<uint8_t> mFilterOutput;
+ vector<uint8_t> mRecordFilterOutput;
+ uint64_t mPts = 0;
+ unique_ptr<FilterMQ> mFilterMQ;
+ bool mIsUsingFMQ = false;
+ EventFlag* mFilterEventFlag;
+ DemuxFilterEvent mFilterEvent;
+ V1_1::DemuxFilterEventExt mFilterEventExt;
+
+ // Thread handlers
+ pthread_t mFilterThread;
+
+ // FMQ status local records
+ DemuxFilterStatus mFilterStatus;
+ /**
+ * If a specific filter's writing loop is still running
+ */
+ bool mFilterThreadRunning;
+ bool mKeepFetchingDataFromFrontend;
+
+ /**
+ * How many times a filter should write
+ * TODO make this dynamic/random/can take as a parameter
+ */
+ const uint16_t SECTION_WRITE_COUNT = 10;
+
+ bool DEBUG_FILTER = false;
+
+ /**
+ * Filter handlers to handle the data filtering.
+ * They are also responsible to write the filtered output into the filter FMQ
+ * and update the filterEvent bound with the same filterId.
+ */
+ Result startSectionFilterHandler();
+ Result startPesFilterHandler();
+ Result startTsFilterHandler();
+ Result startMediaFilterHandler();
+ Result startPcrFilterHandler();
+ Result startTemiFilterHandler();
+ Result startFilterLoop();
+
+ void deleteEventFlag();
+ bool writeDataToFilterMQ(const std::vector<uint8_t>& data);
+ bool readDataFromMQ();
+ bool writeSectionsAndCreateEvent(vector<uint8_t> data);
+ void maySendFilterStatusCallback();
+ DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
+ /**
+ * A dispatcher to read and dispatch input data to all the started filters.
+ * Each filter handler handles the data filtering/output writing/filterEvent updating.
+ */
+ void startTsFilter(vector<uint8_t> data);
+ bool startFilterDispatcher();
+ static void* __threadLoopFilter(void* user);
+ void filterThreadLoop();
+
+ int createAvIonFd(int size);
+ uint8_t* getIonBuffer(int fd, int size);
+ native_handle_t* createNativeHandle(int fd);
+ Result createMediaFilterEventWithIon(vector<uint8_t> output);
+ Result createIndependentMediaEvents(vector<uint8_t> output);
+ Result createShareMemMediaEvents(vector<uint8_t> output);
+ bool sameFile(int fd1, int fd2);
+
+ /**
+ * Lock to protect writes to the FMQs
+ */
+ std::mutex mWriteLock;
+ /**
+ * Lock to protect writes to the filter event
+ */
+ // TODO make each filter separate event lock
+ std::mutex mFilterEventLock;
+ /**
+ * Lock to protect writes to the input status
+ */
+ std::mutex mFilterStatusLock;
+ std::mutex mFilterThreadLock;
+ std::mutex mFilterOutputLock;
+ std::mutex mRecordFilterOutputLock;
+
+ // temp handle single PES filter
+ // TODO handle mulptiple Pes filters
+ int mPesSizeLeft = 0;
+ vector<uint8_t> mPesOutput;
+
+ // A map from data id to ion handle
+ std::map<uint64_t, int> mDataId2Avfd;
+ uint64_t mLastUsedDataId = 1;
+ int mAvBufferCopyCount = 0;
+
+ // Shared A/V memory handle
+ hidl_handle mSharedAvMemHandle;
+ bool mUsingSharedAvMem = true;
+ uint32_t mSharedAvMemOffset = 0;
+
+ uint32_t mAudioStreamType;
+ uint32_t mVideoStreamType;
+
+ // Scrambling status to be monitored
+ uint32_t mStatuses = 0;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
diff --git a/tv/tuner/1.1/default/Frontend.cpp b/tv/tuner/1.1/default/Frontend.cpp
new file mode 100644
index 0000000..6956f30
--- /dev/null
+++ b/tv/tuner/1.1/default/Frontend.cpp
@@ -0,0 +1,429 @@
+/*
+ * 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.tv.tuner@1.1-Frontend"
+
+#include "Frontend.h"
+#include <android/hardware/tv/tuner/1.1/IFrontendCallback.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Frontend::Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner) {
+ mType = type;
+ mId = id;
+ mTunerService = tuner;
+ // Init callback to nullptr
+ mCallback = nullptr;
+}
+
+Frontend::~Frontend() {}
+
+Return<Result> Frontend::close() {
+ ALOGV("%s", __FUNCTION__);
+ // Reset callback
+ mCallback = nullptr;
+ mIsLocked = false;
+ mTunerService->removeFrontend(mId);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setCallback(const sp<IFrontendCallback>& callback) {
+ ALOGV("%s", __FUNCTION__);
+ if (callback == nullptr) {
+ ALOGW("[ WARN ] Set Frontend callback with nullptr");
+ return Result::INVALID_ARGUMENT;
+ }
+
+ mCallback = callback;
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
+ ALOGV("%s", __FUNCTION__);
+ if (mCallback == nullptr) {
+ ALOGW("[ WARN ] Frontend callback is not set when tune");
+ return Result::INVALID_STATE;
+ }
+
+ mTunerService->frontendStartTune(mId);
+ mCallback->onEvent(FrontendEventType::LOCKED);
+ mIsLocked = true;
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune_1_1(const FrontendSettings& settings,
+ const V1_1::FrontendSettingsExt1_1& /*settingsExt1_1*/) {
+ ALOGV("%s", __FUNCTION__);
+ return tune(settings);
+}
+
+Return<Result> Frontend::stopTune() {
+ ALOGV("%s", __FUNCTION__);
+
+ mTunerService->frontendStopTune(mId);
+ mIsLocked = false;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::scan(const FrontendSettings& settings, FrontendScanType type) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mType == FrontendType::ATSC) {
+ FrontendScanMessage msg;
+ msg.isLocked(true);
+ mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+ mIsLocked = true;
+ return Result::SUCCESS;
+ }
+ if (mType != FrontendType::DVBT) {
+ return Result::UNAVAILABLE;
+ }
+
+ FrontendScanMessage msg;
+
+ if (mIsLocked) {
+ msg.isEnd(true);
+ mCallback->onScanMessage(FrontendScanMessageType::END, msg);
+ return Result::SUCCESS;
+ }
+
+ uint32_t frequency = settings.dvbt().frequency;
+ if (type == FrontendScanType::SCAN_BLIND) {
+ frequency += 100;
+ }
+ msg.frequencies({frequency});
+ mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
+ msg.isLocked(true);
+ mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+ mIsLocked = true;
+
+ sp<V1_1::IFrontendCallback> frontendCallback_v1_1 =
+ V1_1::IFrontendCallback::castFrom(mCallback);
+ if (frontendCallback_v1_1 != NULL) {
+ V1_1::FrontendScanMessageExt1_1 msg;
+ msg.modulation().dvbc(FrontendDvbcModulation::MOD_16QAM);
+ frontendCallback_v1_1->onScanMessageExt1_1(V1_1::FrontendScanMessageTypeExt1_1::MODULATION,
+ msg);
+ msg.isHighPriority(true);
+ frontendCallback_v1_1->onScanMessageExt1_1(
+ V1_1::FrontendScanMessageTypeExt1_1::HIGH_PRIORITY, msg);
+ } else {
+ ALOGD("[Filter] Couldn't cast to V1_1 IFrontendCallback");
+ }
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::scan_1_1(const FrontendSettings& settings, FrontendScanType type,
+ const V1_1::FrontendSettingsExt1_1& /*settingsExt1_1*/) {
+ ALOGV("%s", __FUNCTION__);
+ return scan(settings, type);
+}
+
+Return<Result> Frontend::stopScan() {
+ ALOGV("%s", __FUNCTION__);
+
+ mIsLocked = false;
+ return Result::SUCCESS;
+}
+
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+ getStatus_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ vector<FrontendStatus> statuses;
+ for (int i = 0; i < statusTypes.size(); i++) {
+ FrontendStatusType type = statusTypes[i];
+ FrontendStatus status;
+ // assign randomly selected values for testing.
+ switch (type) {
+ case FrontendStatusType::DEMOD_LOCK: {
+ status.isDemodLocked(true);
+ break;
+ }
+ case FrontendStatusType::SNR: {
+ status.snr(221);
+ break;
+ }
+ case FrontendStatusType::BER: {
+ status.ber(1);
+ break;
+ }
+ case FrontendStatusType::PER: {
+ status.per(2);
+ break;
+ }
+ case FrontendStatusType::PRE_BER: {
+ status.preBer(3);
+ break;
+ }
+ case FrontendStatusType::SIGNAL_QUALITY: {
+ status.signalQuality(4);
+ break;
+ }
+ case FrontendStatusType::SIGNAL_STRENGTH: {
+ status.signalStrength(5);
+ break;
+ }
+ case FrontendStatusType::SYMBOL_RATE: {
+ status.symbolRate(6);
+ break;
+ }
+ case FrontendStatusType::FEC: {
+ status.innerFec(FrontendInnerFec::FEC_2_9); // value = 1 << 7
+ break;
+ }
+ case FrontendStatusType::MODULATION: {
+ FrontendModulationStatus modulationStatus;
+ modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM); // value = 1 << 3
+ status.modulation(modulationStatus);
+ break;
+ }
+ case FrontendStatusType::SPECTRAL: {
+ status.inversion(FrontendDvbcSpectralInversion::NORMAL);
+ break;
+ }
+ case FrontendStatusType::LNB_VOLTAGE: {
+ status.lnbVoltage(LnbVoltage::VOLTAGE_5V);
+ break;
+ }
+ case FrontendStatusType::PLP_ID: {
+ status.plpId(101); // type uint8_t
+ break;
+ }
+ case FrontendStatusType::EWBS: {
+ status.isEWBS(false);
+ break;
+ }
+ case FrontendStatusType::AGC: {
+ status.agc(7);
+ break;
+ }
+ case FrontendStatusType::LNA: {
+ status.isLnaOn(false);
+ break;
+ }
+ case FrontendStatusType::LAYER_ERROR: {
+ vector<bool> v = {false, true, true};
+ status.isLayerError(v);
+ break;
+ }
+ case FrontendStatusType::MER: {
+ status.mer(8);
+ break;
+ }
+ case FrontendStatusType::FREQ_OFFSET: {
+ status.freqOffset(9);
+ break;
+ }
+ case FrontendStatusType::HIERARCHY: {
+ status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE);
+ break;
+ }
+ case FrontendStatusType::RF_LOCK: {
+ status.isRfLocked(false);
+ break;
+ }
+ case FrontendStatusType::ATSC3_PLP_INFO: {
+ vector<FrontendStatusAtsc3PlpInfo> v;
+ FrontendStatusAtsc3PlpInfo info1{
+ .plpId = 3,
+ .isLocked = false,
+ .uec = 313,
+ };
+ FrontendStatusAtsc3PlpInfo info2{
+ .plpId = 5,
+ .isLocked = true,
+ .uec = 515,
+ };
+ v.push_back(info1);
+ v.push_back(info2);
+ status.plpInfo(v);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ statuses.push_back(status);
+ }
+ _hidl_cb(Result::SUCCESS, statuses);
+
+ return Void();
+}
+
+Return<void> Frontend::getStatusExt1_1(const hidl_vec<V1_1::FrontendStatusTypeExt1_1>& statusTypes,
+ V1_1::IFrontend::getStatusExt1_1_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ vector<V1_1::FrontendStatusExt1_1> statuses;
+ for (int i = 0; i < statusTypes.size(); i++) {
+ V1_1::FrontendStatusTypeExt1_1 type = statusTypes[i];
+ V1_1::FrontendStatusExt1_1 status;
+ // assign randomly selected values for testing.
+ switch (type) {
+ case V1_1::FrontendStatusTypeExt1_1::MODULATIONS: {
+ vector<V1_1::FrontendModulation> modulations;
+ V1_1::FrontendModulation modulation;
+ modulation.isdbt(FrontendIsdbtModulation::MOD_16QAM); // value = 1 << 3
+ modulations.push_back(modulation);
+ status.modulations(modulations);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::BERS: {
+ vector<uint32_t> bers = {1};
+ status.bers(bers);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::CODERATES: {
+ // value = 1 << 39
+ vector<V1_1::FrontendInnerFec> codeRates = {V1_1::FrontendInnerFec::FEC_6_15};
+ status.codeRates(codeRates);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::BANDWIDTH: {
+ V1_1::FrontendBandwidth bandwidth;
+ bandwidth.dvbt(FrontendDvbtBandwidth::BANDWIDTH_8MHZ);
+ status.bandwidth(bandwidth);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::GUARD_INTERVAL: {
+ V1_1::FrontendGuardInterval interval;
+ interval.dvbt(FrontendDvbtGuardInterval::INTERVAL_1_32); // value = 1 << 1
+ status.interval(interval);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::TRANSMISSION_MODE: {
+ V1_1::FrontendTransmissionMode transMode;
+ transMode.dvbt(V1_1::FrontendDvbtTransmissionMode::AUTO); // value = 1 << 0
+ status.transmissionMode(transMode);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::UEC: {
+ status.uec(4);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::T2_SYSTEM_ID: {
+ status.systemId(5);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::INTERLEAVINGS: {
+ V1_1::FrontendInterleaveMode interleave;
+ interleave.atsc3(FrontendAtsc3TimeInterleaveMode::AUTO);
+ vector<V1_1::FrontendInterleaveMode> interleaving = {interleave};
+ status.interleaving(interleaving);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::ISDBT_SEGMENTS: {
+ vector<uint8_t> segments = {2, 3};
+ status.isdbtSegment(segments);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::TS_DATA_RATES: {
+ vector<uint32_t> dataRates = {4, 5};
+ status.tsDataRate(dataRates);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::ROLL_OFF: {
+ V1_1::FrontendRollOff rollOff;
+ rollOff.dvbs(FrontendDvbsRolloff::ROLLOFF_0_35);
+ status.rollOff(rollOff);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::IS_MISO: {
+ status.isMiso(true);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::IS_LINEAR: {
+ status.isLinear(true);
+ break;
+ }
+ case V1_1::FrontendStatusTypeExt1_1::IS_SHORT_FRAMES: {
+ status.isShortFrames(true);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ statuses.push_back(status);
+ }
+ _hidl_cb(Result::SUCCESS, statuses);
+
+ return Void();
+}
+
+Return<Result> Frontend::setLna(bool /* bEnable */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
+ ALOGV("%s", __FUNCTION__);
+ if (!supportsSatellite()) {
+ return Result::INVALID_STATE;
+ }
+ return Result::SUCCESS;
+}
+
+Return<void> Frontend::linkCiCam(uint32_t ciCamId, linkCiCam_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCiCamId = ciCamId;
+ _hidl_cb(Result::SUCCESS, 0 /*ltsId*/);
+
+ return Void();
+}
+
+Return<Result> Frontend::unlinkCiCam(uint32_t /*ciCamId*/) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCiCamId = -1;
+
+ return Result::SUCCESS;
+}
+
+FrontendType Frontend::getFrontendType() {
+ return mType;
+}
+
+FrontendId Frontend::getFrontendId() {
+ return mId;
+}
+
+bool Frontend::supportsSatellite() {
+ return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
+ mType == FrontendType::ISDBS3;
+}
+
+bool Frontend::isLocked() {
+ return mIsLocked;
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Frontend.h b/tv/tuner/1.1/default/Frontend.h
new file mode 100644
index 0000000..a28fb64
--- /dev/null
+++ b/tv/tuner/1.1/default/Frontend.h
@@ -0,0 +1,101 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
+
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <fstream>
+#include <iostream>
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Tuner;
+
+class Frontend : public V1_1::IFrontend {
+ public:
+ Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner);
+
+ virtual Return<Result> close() override;
+
+ virtual Return<Result> setCallback(const sp<IFrontendCallback>& callback) override;
+
+ virtual Return<Result> tune(const FrontendSettings& settings) override;
+
+ virtual Return<Result> tune_1_1(const FrontendSettings& settings,
+ const V1_1::FrontendSettingsExt1_1& settingsExt1_1) override;
+
+ virtual Return<Result> stopTune() override;
+
+ virtual Return<Result> scan(const FrontendSettings& settings, FrontendScanType type) override;
+
+ virtual Return<Result> scan_1_1(const FrontendSettings& settings, FrontendScanType type,
+ const V1_1::FrontendSettingsExt1_1& settingsExt1_1) override;
+
+ virtual Return<Result> stopScan() override;
+
+ virtual Return<void> getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+ getStatus_cb _hidl_cb) override;
+
+ virtual Return<void> getStatusExt1_1(
+ const hidl_vec<V1_1::FrontendStatusTypeExt1_1>& statusTypes,
+ V1_1::IFrontend::getStatusExt1_1_cb _hidl_cb) override;
+
+ virtual Return<Result> setLna(bool bEnable) override;
+
+ virtual Return<Result> setLnb(uint32_t lnb) override;
+
+ virtual Return<void> linkCiCam(uint32_t ciCamId, linkCiCam_cb _hidl_cb) override;
+
+ virtual Return<Result> unlinkCiCam(uint32_t ciCamId) override;
+
+ FrontendType getFrontendType();
+
+ FrontendId getFrontendId();
+
+ string getSourceFile();
+
+ bool isLocked();
+
+ private:
+ virtual ~Frontend();
+ bool supportsSatellite();
+ sp<IFrontendCallback> mCallback;
+ sp<Tuner> mTunerService;
+ FrontendType mType = FrontendType::UNDEFINED;
+ FrontendId mId = 0;
+ bool mIsLocked = false;
+ uint32_t mCiCamId;
+
+ std::ifstream mFrontendData;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
diff --git a/tv/tuner/1.1/default/Lnb.cpp b/tv/tuner/1.1/default/Lnb.cpp
new file mode 100644
index 0000000..044727f
--- /dev/null
+++ b/tv/tuner/1.1/default/Lnb.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.tv.tuner@1.1-Lnb"
+
+#include "Lnb.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Lnb::Lnb() {}
+Lnb::Lnb(int id) {
+ mId = id;
+}
+
+Lnb::~Lnb() {}
+
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setVoltage(LnbVoltage /* voltage */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setTone(LnbTone /* tone */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(LnbPosition /* position */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+int Lnb::getId() {
+ return mId;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Lnb.h b/tv/tuner/1.1/default/Lnb.h
new file mode 100644
index 0000000..70a8e41
--- /dev/null
+++ b/tv/tuner/1.1/default/Lnb.h
@@ -0,0 +1,63 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
+
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Lnb : public ILnb {
+ public:
+ Lnb();
+ Lnb(int id);
+
+ virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
+
+ virtual Return<Result> setVoltage(LnbVoltage voltage) override;
+
+ virtual Return<Result> setTone(LnbTone tone) override;
+
+ virtual Return<Result> setSatellitePosition(LnbPosition position) override;
+
+ virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
+ virtual Return<Result> close() override;
+
+ int getId();
+
+ private:
+ int mId;
+ virtual ~Lnb();
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
diff --git a/tv/tuner/1.1/default/OWNERS b/tv/tuner/1.1/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.1/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.1/default/TimeFilter.cpp b/tv/tuner/1.1/default/TimeFilter.cpp
new file mode 100644
index 0000000..bb243a6
--- /dev/null
+++ b/tv/tuner/1.1/default/TimeFilter.cpp
@@ -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.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-TimeFilter"
+
+#include "TimeFilter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+TimeFilter::TimeFilter() {}
+
+TimeFilter::TimeFilter(sp<Demux> demux) {
+ mDemux = demux;
+}
+
+TimeFilter::~TimeFilter() {}
+
+Return<Result> TimeFilter::setTimeStamp(uint64_t timeStamp) {
+ ALOGV("%s", __FUNCTION__);
+ if (timeStamp == INVALID_TIME_STAMP) {
+ return Result::INVALID_ARGUMENT;
+ }
+ mTimeStamp = timeStamp;
+ mBeginTime = time(NULL);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> TimeFilter::clearTimeStamp() {
+ ALOGV("%s", __FUNCTION__);
+ mTimeStamp = INVALID_TIME_STAMP;
+
+ return Result::SUCCESS;
+}
+
+Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+ if (mTimeStamp == INVALID_TIME_STAMP) {
+ _hidl_cb(Result::INVALID_STATE, mTimeStamp);
+ }
+
+ uint64_t currentTimeStamp = mTimeStamp + difftime(time(NULL), mBeginTime) * 900000;
+ _hidl_cb(Result::SUCCESS, currentTimeStamp);
+ return Void();
+}
+
+Return<void> TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t time = 0;
+
+ _hidl_cb(Result::SUCCESS, time);
+ return Void();
+}
+
+Return<Result> TimeFilter::close() {
+ ALOGV("%s", __FUNCTION__);
+ mTimeStamp = INVALID_TIME_STAMP;
+
+ return Result::SUCCESS;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/TimeFilter.h b/tv/tuner/1.1/default/TimeFilter.h
new file mode 100644
index 0000000..d53ad2c
--- /dev/null
+++ b/tv/tuner/1.1/default/TimeFilter.h
@@ -0,0 +1,70 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include "Demux.h"
+#include "time.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+#define INVALID_TIME_STAMP -1
+
+class Demux;
+
+class TimeFilter : public ITimeFilter {
+ public:
+ TimeFilter();
+
+ TimeFilter(sp<Demux> demux);
+
+ ~TimeFilter();
+
+ virtual Return<Result> setTimeStamp(uint64_t timeStamp) override;
+
+ virtual Return<Result> clearTimeStamp() override;
+
+ virtual Return<void> getTimeStamp(getTimeStamp_cb _hidl_cb) override;
+
+ virtual Return<void> getSourceTime(getSourceTime_cb _hidl_cb) override;
+
+ virtual Return<Result> close() override;
+
+ private:
+ sp<Demux> mDemux;
+ uint64_t mTimeStamp = INVALID_TIME_STAMP;
+ time_t mBeginTime;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Tuner.cpp b/tv/tuner/1.1/default/Tuner.cpp
new file mode 100644
index 0000000..c3dcd1d
--- /dev/null
+++ b/tv/tuner/1.1/default/Tuner.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.tv.tuner@1.1-Tuner"
+
+#include "Tuner.h"
+#include <utils/Log.h>
+#include "Demux.h"
+#include "Descrambler.h"
+#include "Frontend.h"
+#include "Lnb.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Tuner::Tuner() {
+ // Static Frontends array to maintain local frontends information
+ // Array index matches their FrontendId in the default impl
+ mFrontendSize = 9;
+ mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
+ mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
+ mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
+ mFrontends[3] = new Frontend(FrontendType::DVBS, 3, this);
+ mFrontends[4] = new Frontend(FrontendType::DVBT, 4, this);
+ mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this);
+ mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this);
+ mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
+ mFrontends[8] =
+ new Frontend(static_cast<V1_0::FrontendType>(V1_1::FrontendType::DTMB), 8, this);
+
+ FrontendInfo::FrontendCapabilities caps;
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.dvbtCaps(FrontendDvbtCapabilities());
+ mFrontendCaps[0] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.atscCaps(FrontendAtscCapabilities());
+ mFrontendCaps[1] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.dvbcCaps(FrontendDvbcCapabilities());
+ mFrontendCaps[2] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.dvbsCaps(FrontendDvbsCapabilities());
+ mFrontendCaps[3] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.dvbtCaps(FrontendDvbtCapabilities());
+ mFrontendCaps[4] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ FrontendIsdbtCapabilities isdbtCaps{
+ .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2,
+ .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+ .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM,
+ // ISDBT shares coderate and guard interval with DVBT
+ .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7,
+ .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128,
+ };
+ caps.isdbtCaps(isdbtCaps);
+ mFrontendCaps[5] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.analogCaps(FrontendAnalogCapabilities());
+ mFrontendCaps[6] = caps;
+
+ caps = FrontendInfo::FrontendCapabilities();
+ caps.atscCaps(FrontendAtscCapabilities());
+ mFrontendCaps[7] = caps;
+
+ mLnbs.resize(2);
+ mLnbs[0] = new Lnb(0);
+ mLnbs[1] = new Lnb(1);
+}
+
+Tuner::~Tuner() {}
+
+Return<void> Tuner::getFrontendIds(getFrontendIds_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ vector<FrontendId> frontendIds;
+ frontendIds.resize(mFrontendSize);
+ for (int i = 0; i < mFrontendSize; i++) {
+ frontendIds[i] = mFrontends[i]->getFrontendId();
+ }
+
+ _hidl_cb(Result::SUCCESS, frontendIds);
+ return Void();
+}
+
+Return<void> Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (frontendId >= mFrontendSize || frontendId < 0) {
+ ALOGW("[ WARN ] Frontend with id %d isn't available", frontendId);
+ _hidl_cb(Result::UNAVAILABLE, nullptr);
+ return Void();
+ }
+
+ _hidl_cb(Result::SUCCESS, mFrontends[frontendId]);
+ return Void();
+}
+
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint32_t demuxId = mLastUsedId + 1;
+ mLastUsedId += 1;
+ sp<Demux> demux = new Demux(demuxId, this);
+ mDemuxes[demuxId] = demux;
+
+ _hidl_cb(Result::SUCCESS, demuxId, demux);
+ return Void();
+}
+
+Return<void> Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ DemuxCapabilities caps;
+
+ // IP filter can be an MMTP filter's data source.
+ caps.linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
+ _hidl_cb(Result::SUCCESS, caps);
+ return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<V1_0::IDescrambler> descrambler = new Descrambler();
+
+ _hidl_cb(Result::SUCCESS, descrambler);
+ return Void();
+}
+
+Return<void> Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ FrontendInfo info;
+ if (frontendId >= mFrontendSize) {
+ _hidl_cb(Result::INVALID_ARGUMENT, info);
+ return Void();
+ }
+
+ vector<FrontendStatusType> statusCaps = {
+ FrontendStatusType::DEMOD_LOCK,
+ FrontendStatusType::SNR,
+ FrontendStatusType::FEC,
+ FrontendStatusType::MODULATION,
+ FrontendStatusType::PLP_ID,
+ FrontendStatusType::LAYER_ERROR,
+ FrontendStatusType::ATSC3_PLP_INFO,
+ };
+ // assign randomly selected values for testing.
+ info = {
+ .type = mFrontends[frontendId]->getFrontendType(),
+ .minFrequency = 139,
+ .maxFrequency = 1139,
+ .minSymbolRate = 45,
+ .maxSymbolRate = 1145,
+ .acquireRange = 30,
+ .exclusiveGroupId = 57,
+ .statusCaps = statusCaps,
+ .frontendCaps = mFrontendCaps[frontendId],
+ };
+
+ _hidl_cb(Result::SUCCESS, info);
+ return Void();
+}
+
+Return<void> Tuner::getLnbIds(getLnbIds_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ vector<V1_0::LnbId> lnbIds;
+ lnbIds.resize(mLnbs.size());
+ for (int i = 0; i < lnbIds.size(); i++) {
+ lnbIds[i] = mLnbs[i]->getId();
+ }
+
+ _hidl_cb(Result::SUCCESS, lnbIds);
+ return Void();
+}
+
+Return<void> Tuner::openLnbById(V1_0::LnbId lnbId, openLnbById_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (lnbId >= mLnbs.size()) {
+ _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ _hidl_cb(Result::SUCCESS, mLnbs[lnbId]);
+ return Void();
+}
+
+sp<Frontend> Tuner::getFrontendById(uint32_t frontendId) {
+ ALOGV("%s", __FUNCTION__);
+
+ return mFrontends[frontendId];
+}
+
+Return<void> Tuner::openLnbByName(const hidl_string& /*lnbName*/, openLnbByName_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<V1_0::ILnb> lnb = new Lnb();
+
+ _hidl_cb(Result::SUCCESS, 1234, lnb);
+ return Void();
+}
+
+Return<void> Tuner::getFrontendDtmbCapabilities(uint32_t frontendId,
+ getFrontendDtmbCapabilities_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mFrontends[frontendId] != nullptr &&
+ (mFrontends[frontendId]->getFrontendType() ==
+ static_cast<V1_0::FrontendType>(V1_1::FrontendType::DTMB))) {
+ _hidl_cb(Result::SUCCESS, mDtmbCaps);
+ } else {
+ _hidl_cb(Result::UNAVAILABLE, mDtmbCaps);
+ }
+ return Void();
+}
+
+void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
+ mFrontendToDemux[frontendId] = demuxId;
+ if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
+ mDemuxes[demuxId]->startFrontendInputLoop();
+ }
+}
+
+void Tuner::removeDemux(uint32_t demuxId) {
+ map<uint32_t, uint32_t>::iterator it;
+ for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
+ if (it->second == demuxId) {
+ it = mFrontendToDemux.erase(it);
+ break;
+ }
+ }
+ mDemuxes.erase(demuxId);
+}
+
+void Tuner::removeFrontend(uint32_t frontendId) {
+ mFrontendToDemux.erase(frontendId);
+}
+
+void Tuner::frontendStopTune(uint32_t frontendId) {
+ map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+ uint32_t demuxId;
+ if (it != mFrontendToDemux.end()) {
+ demuxId = it->second;
+ mDemuxes[demuxId]->stopFrontendInput();
+ }
+}
+
+void Tuner::frontendStartTune(uint32_t frontendId) {
+ map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+ uint32_t demuxId;
+ if (it != mFrontendToDemux.end()) {
+ demuxId = it->second;
+ mDemuxes[demuxId]->startFrontendInputLoop();
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.1/default/Tuner.h b/tv/tuner/1.1/default/Tuner.h
new file mode 100644
index 0000000..fda3636
--- /dev/null
+++ b/tv/tuner/1.1/default/Tuner.h
@@ -0,0 +1,100 @@
+/*
+ * 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 ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
+
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <map>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Lnb.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_1::ITuner;
+
+class Frontend;
+class Demux;
+class Lnb;
+
+class Tuner : public ITuner {
+ public:
+ Tuner();
+
+ virtual Return<void> getFrontendIds(getFrontendIds_cb _hidl_cb) override;
+
+ virtual Return<void> openFrontendById(uint32_t frontendId,
+ openFrontendById_cb _hidl_cb) override;
+
+ virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+ virtual Return<void> getDemuxCaps(getDemuxCaps_cb _hidl_cb) override;
+
+ virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
+ virtual Return<void> getFrontendInfo(uint32_t frontendId, getFrontendInfo_cb _hidl_cb) override;
+
+ virtual Return<void> getLnbIds(getLnbIds_cb _hidl_cb) override;
+
+ virtual Return<void> openLnbById(uint32_t lnbId, openLnbById_cb _hidl_cb) override;
+
+ virtual Return<void> openLnbByName(const hidl_string& lnbName,
+ openLnbByName_cb _hidl_cb) override;
+
+ virtual Return<void> getFrontendDtmbCapabilities(
+ uint32_t frontendId, getFrontendDtmbCapabilities_cb _hidl_cb) override;
+
+ sp<Frontend> getFrontendById(uint32_t frontendId);
+
+ void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
+
+ void frontendStartTune(uint32_t frontendId);
+ void frontendStopTune(uint32_t frontendId);
+ void removeDemux(uint32_t demuxId);
+ void removeFrontend(uint32_t frontendId);
+
+ private:
+ virtual ~Tuner();
+ // Static mFrontends array to maintain local frontends information
+ map<uint32_t, sp<Frontend>> mFrontends;
+ map<uint32_t, FrontendInfo::FrontendCapabilities> mFrontendCaps;
+ V1_1::FrontendDtmbCapabilities mDtmbCaps;
+ map<uint32_t, uint32_t> mFrontendToDemux;
+ map<uint32_t, sp<Demux>> mDemuxes;
+ // To maintain how many Frontends we have
+ int mFrontendSize;
+ // The last used demux id. Initial value is -1.
+ // First used id will be 0.
+ uint32_t mLastUsedId = -1;
+ vector<sp<Lnb>> mLnbs;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
diff --git a/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc
new file mode 100644
index 0000000..abff430
--- /dev/null
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc
@@ -0,0 +1,10 @@
+service vendor.tuner-hal-1-1 /vendor/bin/hw/android.hardware.tv.tuner@1.1-service-lazy
+ interface android.hardware.tv.tuner@1.0::ITuner default
+ interface android.hardware.tv.tuner@1.1::ITuner default
+ oneshot
+ disabled
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
similarity index 64%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
index b5d25cd..86b0445 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
@@ -1,11 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.wifi</name>
+ <name>android.hardware.tv.tuner</name>
<transport>hwbinder</transport>
- <version>1.4</version>
+ <version>1.1</version>
<interface>
- <name>IWifi</name>
+ <name>ITuner</name>
<instance>default</instance>
</interface>
</hal>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc
new file mode 100644
index 0000000..3718a93
--- /dev/null
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.tuner-hal-1-1 /vendor/bin/hw/android.hardware.tv.tuner@1.1-service
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
similarity index 64%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
index b5d25cd..86b0445 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
@@ -1,11 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.wifi</name>
+ <name>android.hardware.tv.tuner</name>
<transport>hwbinder</transport>
- <version>1.4</version>
+ <version>1.1</version>
<interface>
- <name>IWifi</name>
+ <name>ITuner</name>
<instance>default</instance>
</interface>
</hal>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/service.cpp b/tv/tuner/1.1/default/service.cpp
new file mode 100644
index 0000000..2320308
--- /dev/null
+++ b/tv/tuner/1.1/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.tv.tuner@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.tv.tuner@1.1-service"
+#endif
+
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "Tuner.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::tv::tuner::V1_0::implementation::Tuner;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+
+ // Setup hwbinder service
+ android::sp<ITuner> service = new Tuner();
+ android::status_t status;
+ if (kLazyService) {
+ auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+ status = serviceRegistrar.registerService(service);
+ } else {
+ status = service->registerAsService();
+ }
+ LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering tuner service: %d", status);
+
+ joinRpcThreadpool();
+ return 0;
+}
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
new file mode 100644
index 0000000..defc99b
--- /dev/null
+++ b/tv/tuner/1.1/types.hal
@@ -0,0 +1,818 @@
+/*
+ * 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.tv.tuner@1.1;
+
+import @1.0::Constant;
+import @1.0::DemuxFilterMmtpRecordEvent;
+import @1.0::DemuxFilterTsRecordEvent;
+import @1.0::DemuxScIndex;
+import @1.0::FrontendIsdbs3Rolloff;
+import @1.0::FrontendAtsc3Bandwidth;
+import @1.0::FrontendAtsc3Modulation;
+import @1.0::FrontendAtsc3TimeInterleaveMode;
+import @1.0::FrontendIsdbsRolloff;
+import @1.0::FrontendAtscModulation;
+import @1.0::FrontendDvbcAnnex;
+import @1.0::FrontendDvbcModulation;
+import @1.0::FrontendDvbcSpectralInversion;
+import @1.0::FrontendDvbsModulation;
+import @1.0::FrontendDvbsRolloff;
+import @1.0::FrontendDvbtBandwidth;
+import @1.0::FrontendDvbtConstellation;
+import @1.0::FrontendDvbtTransmissionMode;
+import @1.0::FrontendDvbtGuardInterval;
+import @1.0::FrontendInnerFec;
+import @1.0::FrontendIsdbs3Modulation;
+import @1.0::FrontendIsdbsModulation;
+import @1.0::FrontendIsdbtBandwidth;
+import @1.0::FrontendIsdbtGuardInterval;
+import @1.0::FrontendIsdbtMode;
+import @1.0::FrontendIsdbtModulation;
+import @1.0::FrontendScanMessageType;
+import @1.0::FrontendStatusType;
+import @1.0::FrontendType;
+import android.hidl.safe_union@1.0;
+import android.hidl.safe_union@1.0::Monostate;
+
+@export
+enum Constant : @1.0::Constant {
+ /**
+ * An invalid mpuSequenceNumber in DemuxFilterRecordEventExt.
+ */
+ INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = 0xFFFFFFFF,
+ /**
+ * An invalid first macroblock address in DemuxFilterRecordEventExt.
+ */
+ INVALID_FIRST_MACROBLOCK_IN_SLICE = 0xFFFFFFFF,
+ /**
+ * An invalid frenquency that can be used as the default value of the frontend setting.
+ */
+ INVALID_FRONTEND_SETTING_FREQUENCY = 0xFFFFFFFF,
+ /**
+ * An invalid context id that can be used as the default value of the unconfigured id. It can
+ * be used to reset the configured ip context id.
+ */
+ INVALID_IP_FILTER_CONTEXT_ID = 0xFFFFFFFF,
+ /**
+ * An invalid local transport stream id used as the return value on a failed operation of
+ * IFrontend.linkCiCam.
+ */
+ INVALID_LTS_ID = 0xFFFFFFFF,
+};
+
+@export
+enum Constant64Bit : uint64_t {
+ /**
+ * An invalid 64-bit Filter ID.
+ */
+ INVALID_FILTER_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+ /**
+ * An invalid 64-bit AV sync hardware ID.
+ */
+ INVALID_AV_SYNC_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+ /**
+ * An invalid pts.
+ */
+ INVALID_PRESENTATION_TIME_STAMP = 0xFFFFFFFFFFFFFFFF,
+};
+
+/**
+ * Extended Demux Filter Record Event.
+ */
+struct DemuxFilterRecordEventExt {
+ /**
+ * The Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
+ * and has the same format as the PTS in ISO/IEC 13818-1.
+ */
+ uint64_t pts;
+
+ /**
+ * MPU sequence number of the filtered data. This is only used for MMTP.
+ */
+ uint32_t mpuSequenceNumber;
+
+ /**
+ * Specifies the address of the first macroblock in the slice defined in ITU-T Rec. H.264.
+ */
+ uint32_t firstMbInSlice;
+};
+
+/**
+ * Extended Demux Filter Event.
+ */
+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 DemuxFilterRecordEventExt information.
+ */
+ Monostate noinit;
+
+ DemuxFilterRecordEventExt tsRecord;
+
+ DemuxFilterRecordEventExt mmtpRecord;
+
+ ScramblingStatus scramblingStatus;
+ };
+
+ /**
+ * An array of events
+ */
+ vec<Event> events;
+};
+
+/**
+ * Scrambling Status Type.
+ */
+@export
+enum ScramblingStatus : uint32_t {
+ /**
+ * Content’s scrambling status is unknown
+ */
+ UNKNOWN = 1 << 0,
+ /**
+ * Content is not scrambled.
+ */
+ NOT_SCRAMBLED = 1 << 1,
+ /**
+ * Content is scrambled.
+ */
+ SCRAMBLED = 1 << 2,
+};
+
+typedef FrontendDvbcSpectralInversion FrontendSpectralInversion;
+
+/**
+ * Scan type for a DVBS Frontend.
+ */
+@export
+enum FrontendDvbsScanType : uint32_t {
+ UNDEFINED = 0,
+ DIRECT,
+ DISEQC,
+ UNICABLE,
+ JESS,
+};
+
+/**
+ * AFT flag for an Analog Frontend.
+ */
+@export
+enum FrontendAnalogAftFlag : uint32_t {
+ UNDEFINED,
+ AFT_TRUE,
+ AFT_FALSE,
+};
+
+/**
+ * Time Interleave Mode for DVBC Frontend.
+ */
+@export
+enum FrontendCableTimeInterleaveMode : uint32_t {
+ UNDEFINED = 0,
+ AUTO = 1 << 0,
+ INTERLEAVING_128_1_0 = 1 << 1,
+ INTERLEAVING_128_1_1 = 1 << 2,
+ INTERLEAVING_64_2 = 1 << 3,
+ INTERLEAVING_32_4 = 1 << 4,
+ INTERLEAVING_16_8 = 1 << 5,
+ INTERLEAVING_8_16 = 1 << 6,
+ INTERLEAVING_128_2 = 1 << 7,
+ INTERLEAVING_128_3 = 1 << 8,
+ INTERLEAVING_128_4 = 1 << 9,
+};
+
+/**
+ * Extended Transmission Mode for DVBT.
+ */
+@export
+enum FrontendDvbtTransmissionMode : @1.0::FrontendDvbtTransmissionMode {
+ MODE_8K_E = 1 << 7,
+ MODE_16K_E = 1 << 8,
+ MODE_32K_E = 1 << 9,
+};
+
+/**
+ * Extended Constellation for DVBT.
+ */
+@export
+enum FrontendDvbtConstellation : @1.0::FrontendDvbtConstellation {
+ CONSTELLATION_QPSK_R = 1 << 5,
+ CONSTELLATION_16QAM_R = 1 << 6,
+ CONSTELLATION_64QAM_R = 1 << 7,
+ CONSTELLATION_256QAM_R = 1 << 8,
+};
+
+/**
+ * Extended Signal Settings for a DVBS Frontend.
+ */
+struct FrontendDvbsSettingsExt1_1 {
+ FrontendDvbsScanType scanType;
+
+ bool isDiseqcRxMessage;
+};
+
+/**
+ * Extended Signal Settings for a DVBT Frontend.
+ */
+struct FrontendDvbtSettingsExt1_1 {
+ FrontendDvbtConstellation constellation;
+
+ FrontendDvbtTransmissionMode transmissionMode;
+};
+
+/**
+ * Extended Signal Settings for an Analog Frontend.
+ */
+struct FrontendAnalogSettingsExt1_1 {
+ FrontendAnalogAftFlag aftFlag;
+};
+
+/**
+ * Extended Signal Settings for DVBC Frontend.
+ */
+struct FrontendDvbcSettingsExt1_1 {
+ FrontendCableTimeInterleaveMode interleaveMode;
+
+ FrontendDvbcBandwidth bandwidth;
+};
+
+/**
+ * Extended Signal Settings for Frontend.
+ */
+struct FrontendSettingsExt1_1 {
+ uint32_t endFrequency;
+
+ FrontendSpectralInversion inversion;
+
+ safe_union SettingsExt {
+ Monostate noinit;
+
+ FrontendAnalogSettingsExt1_1 analog;
+
+ FrontendDvbcSettingsExt1_1 dvbc;
+
+ FrontendDvbsSettingsExt1_1 dvbs;
+
+ FrontendDvbtSettingsExt1_1 dvbt;
+
+ FrontendDtmbSettings dtmb;
+ } settingExt;
+};
+
+/**
+ * Extended Frontend Type.
+ */
+@export
+enum FrontendType : @1.0::FrontendType {
+ /**
+ * DTMB (Digital Terrestrial Multimedia Broadcast) standard.
+ */
+ DTMB,
+};
+
+/**
+ * Bandwidth Type for Cable Frontend.
+ */
+@export
+enum FrontendDvbcBandwidth : uint32_t {
+ UNDEFINED = 0,
+ BANDWIDTH_5MHZ = 1 << 0,
+ BANDWIDTH_6MHZ = 1 << 1,
+ BANDWIDTH_7MHZ = 1 << 2,
+ BANDWIDTH_8MHZ = 1 << 3,
+};
+
+/**
+ * Bandwidth Type for DTMB.
+ */
+@export
+enum FrontendDtmbBandwidth : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set Bandwidth automatically
+ */
+ AUTO = 1 << 0,
+ BANDWIDTH_8MHZ = 1 << 1,
+ BANDWIDTH_6MHZ = 1 << 2,
+};
+
+/**
+ * TimeInterleaveMode Type for DTMB.
+ */
+@export
+enum FrontendDtmbTimeInterleaveMode : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set time interleave mode automatically
+ */
+ AUTO = 1 << 0,
+ TIMER_INT_240 = 1 << 1,
+ TIMER_INT_720 = 1 << 2,
+};
+
+/**
+ * FrontendDtmbModulation Type for DTMB.
+ */
+@export
+enum FrontendDtmbModulation : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set Constellation automatically
+ */
+ AUTO = 1 << 0,
+ CONSTELLATION_4QAM = 1 << 1,
+ CONSTELLATION_4QAM_NR = 1 << 2,
+ CONSTELLATION_16QAM = 1 << 3,
+ CONSTELLATION_32QAM = 1 << 4,
+ CONSTELLATION_64QAM = 1 << 5,
+};
+
+/**
+ * CODERATE Type for DTMB.
+ */
+@export
+enum FrontendDtmbCodeRate : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set code rate automatically
+ */
+ AUTO = 1 << 0,
+ CODERATE_2_5 = 1 << 1,
+ CODERATE_3_5 = 1 << 2,
+ CODERATE_4_5 = 1 << 3,
+};
+
+/**
+ * Guard Interval Type for DTMB.
+ */
+@export
+enum FrontendDtmbGuardInterval : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set Guard Interval automatically
+ */
+ AUTO = 1 << 0,
+ PN_420_VARIOUS = 1 << 1,
+ PN_595_CONST = 1 << 2,
+ PN_945_VARIOUS = 1 << 3,
+ PN_420_CONST = 1 << 4,
+ PN_945_CONST = 1 << 5,
+ PN_RESERVED = 1 << 6,
+};
+
+/**
+ * Transmission Mode for DTMB.
+ */
+@export
+enum FrontendDtmbTransmissionMode : uint32_t {
+ UNDEFINED = 0,
+ /**
+ * hardware is able to detect and set Transmission Mode automatically
+ */
+ AUTO = 1 << 0,
+ C1 = 1 << 1,
+ C3780 = 1 << 2,
+};
+
+/**
+ * Signal Setting for DTMB Frontend.
+ */
+struct FrontendDtmbSettings {
+ uint32_t frequency;
+
+ FrontendDtmbTransmissionMode transmissionMode;
+
+ FrontendDtmbBandwidth bandwidth;
+
+ FrontendDtmbModulation modulation;
+
+ FrontendDtmbCodeRate codeRate;
+
+ FrontendDtmbGuardInterval guardInterval;
+
+ FrontendDtmbTimeInterleaveMode interleaveMode;
+};
+
+/**
+ * Capabilities for DTMB Frontend.
+ */
+struct FrontendDtmbCapabilities {
+ bitfield<FrontendDtmbTransmissionMode> transmissionModeCap;
+
+ bitfield<FrontendDtmbBandwidth> bandwidthCap;
+
+ bitfield<FrontendDtmbModulation> modulationCap;
+
+ bitfield<FrontendDtmbCodeRate> codeRateCap;
+
+ bitfield<FrontendDtmbGuardInterval> guardIntervalCap;
+
+ bitfield<FrontendDtmbTimeInterleaveMode> interleaveModeCap;
+};
+
+safe_union FrontendModulation {
+ @1.0::FrontendDvbcModulation dvbc;
+
+ @1.0::FrontendDvbsModulation dvbs;
+
+ FrontendDvbtConstellation dvbt;
+
+ @1.0::FrontendIsdbsModulation isdbs;
+
+ @1.0::FrontendIsdbs3Modulation isdbs3;
+
+ @1.0::FrontendIsdbtModulation isdbt;
+
+ @1.0::FrontendAtscModulation atsc;
+
+ @1.0::FrontendAtsc3Modulation atsc3;
+
+ FrontendDtmbModulation dtmb;
+};
+
+safe_union FrontendInterleaveMode {
+ @1.0::FrontendAtsc3TimeInterleaveMode atsc3;
+
+ FrontendCableTimeInterleaveMode dvbc;
+
+ FrontendDtmbTimeInterleaveMode dtmb;
+};
+
+@export
+enum FrontendInnerFec : @1.0::FrontendInnerFec {
+ FEC_2_15 = 1 << 36,
+ FEC_3_15 = 1 << 37,
+ FEC_5_15 = 1 << 38,
+ FEC_6_15 = 1 << 39,
+ FEC_9_15 = 1 << 40,
+ FEC_10_15 = 1 << 41,
+ FEC_12_15 = 1 << 42,
+ FEC_13_15 = 1 << 43,
+ FEC_18_30 = 1 << 44,
+ FEC_20_30 = 1 << 45,
+ FEC_90_180 = 1 << 46,
+ FEC_96_180 = 1 << 47,
+ FEC_104_180 = 1 << 48,
+ FEC_128_180 = 1 << 49,
+ FEC_132_180 = 1 << 50,
+ FEC_135_180 = 1 << 51,
+ FEC_140_180 = 1 << 52,
+};
+
+safe_union FrontendBandwidth {
+ @1.0::FrontendAtsc3Bandwidth atsc3;
+
+ FrontendDvbcBandwidth dvbc;
+
+ @1.0::FrontendDvbtBandwidth dvbt;
+
+ @1.0::FrontendIsdbtBandwidth isdbt;
+
+ FrontendDtmbBandwidth dtmb;
+};
+
+safe_union FrontendGuardInterval {
+ @1.0::FrontendDvbtGuardInterval dvbt;
+
+ @1.0::FrontendIsdbtGuardInterval isdbt;
+
+ FrontendDtmbGuardInterval dtmb;
+};
+
+safe_union FrontendTransmissionMode {
+ FrontendDvbtTransmissionMode dvbt;
+
+ @1.0::FrontendIsdbtMode isdbt;
+
+ FrontendDtmbTransmissionMode dtmb;
+};
+
+safe_union FrontendRollOff {
+ @1.0::FrontendDvbsRolloff dvbs;
+
+ @1.0::FrontendIsdbsRolloff isdbs;
+
+ @1.0::FrontendIsdbs3Rolloff isdbs3;
+};
+
+@export
+enum FrontendStatusTypeExt1_1 : uint32_t {
+ /**
+ * Modulation Types.
+ */
+ MODULATIONS = @1.0::FrontendStatusType:ATSC3_PLP_INFO + 1,
+ /**
+ * Bit Error Ratios.
+ */
+ BERS,
+ /**
+ * Code Rates.
+ */
+ CODERATES,
+ /**
+ * Extended Bandwidth.
+ */
+ BANDWIDTH,
+ /**
+ * Extended Guard Intervals.
+ */
+ GUARD_INTERVAL,
+ /**
+ * Extended Transmission Mode.
+ */
+ TRANSMISSION_MODE,
+ /**
+ * Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP)
+ * since the last tune operation.
+ */
+ UEC,
+ /**
+ * DVB-T2 System Id.
+ */
+ T2_SYSTEM_ID,
+ /**
+ * Frontend Interleaving Modes.
+ */
+ INTERLEAVINGS,
+ /**
+ * Segments in ISDB-T Specification of all the channels.
+ */
+ ISDBT_SEGMENTS,
+ /**
+ * Transport Stream Data Rate in BPS of the current channel.
+ */
+ TS_DATA_RATES,
+ /**
+ * Roll Off Type status of the frontend.
+ */
+ ROLL_OFF,
+ /**
+ * If the frontend currently supports MISO or not.
+ */
+ IS_MISO,
+ /**
+ * If the frontend code rate is linear or not.
+ */
+ IS_LINEAR,
+ /**
+ * If short frames is enabled or not.
+ */
+ IS_SHORT_FRAMES,
+};
+
+safe_union FrontendStatusExt1_1 {
+ /**
+ * Extended modulation status.
+ */
+ vec<FrontendModulation> modulations;
+
+ /**
+ * Extended bit error ratio status.
+ */
+ vec<uint32_t> bers;
+
+ /**
+ * Extended code rate status.
+ */
+ vec<FrontendInnerFec> codeRates;
+
+ /**
+ * Extended bandwidth status.
+ */
+ FrontendBandwidth bandwidth;
+
+ /**
+ * Extended guard interval status.
+ */
+ FrontendGuardInterval interval;
+
+ /**
+ * Extended transmission mode status.
+ */
+ FrontendTransmissionMode transmissionMode;
+
+ /**
+ * Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP)
+ * since the last tune operation.
+ */
+ uint32_t uec;
+
+ /**
+ * The current DVB-T2 system id status.
+ */
+ uint16_t systemId;
+
+ /**
+ * Frontend Interleaving Modes.
+ */
+ vec<FrontendInterleaveMode> interleaving;
+
+ /**
+ * Segments in ISDB-T Specification of all the channels.
+ */
+ vec<uint8_t> isdbtSegment;
+
+ /**
+ * Transport Stream Data Rate in BPS of the current channel.
+ */
+ vec<uint32_t> tsDataRate;
+ /**
+ * Roll Off Type status of the frontend.
+ */
+ FrontendRollOff rollOff;
+ /**
+ * If the frontend currently supports MISO or not.
+ */
+ bool isMiso;
+ /**
+ * If the frontend code rate is linear or not.
+ */
+ bool isLinear;
+ /**
+ * If short frames is enabled or not.
+ */
+ bool isShortFrames;
+};
+
+enum FrontendScanMessageTypeExt1_1 : uint32_t {
+ MODULATION = @1.0::FrontendScanMessageType:ATSC3_PLP_INFO + 1,
+ DVBC_ANNEX,
+ HIGH_PRIORITY,
+};
+
+safe_union FrontendScanMessageExt1_1 {
+ FrontendModulation modulation;
+
+ @1.0::FrontendDvbcAnnex annex;
+
+ bool isHighPriority;
+};
+
+@export
+enum VideoStreamType : uint32_t {
+ UNDEFINED,
+ /*
+ * ITU-T | ISO/IEC Reserved
+ */
+ RESERVED,
+ /*
+ * ISO/IEC 11172
+ */
+ MPEG1,
+ /*
+ * ITU-T Rec.H.262 and ISO/IEC 13818-2
+ */
+ MPEG2,
+ /*
+ * ISO/IEC 14496-2 (MPEG-4 H.263 based video)
+ */
+ MPEG4P2,
+ /*
+ * ITU-T Rec.H.264 and ISO/IEC 14496-10
+ */
+ AVC,
+ /*
+ * ITU-T Rec. H.265 and ISO/IEC 23008-2
+ */
+ HEVC,
+ /*
+ * Microsoft VC.1
+ */
+ VC1,
+ /*
+ * Google VP8
+ */
+ VP8,
+ /*
+ * Google VP9
+ */
+ VP9,
+ /*
+ * AOMedia Video 1
+ */
+ AV1,
+ /*
+ * Chinese Standard
+ */
+ AVS,
+ /*
+ * New Chinese Standard
+ */
+ AVS2,
+};
+
+@export
+enum AudioStreamType : uint32_t {
+ UNDEFINED,
+ /*
+ * Uncompressed Audio
+ */
+ PCM,
+ /*
+ * MPEG Audio Layer III versions
+ */
+ MP3,
+ /*
+ * ISO/IEC 11172 Audio
+ */
+ MPEG1,
+ /*
+ * ISO/IEC 13818-3
+ */
+ MPEG2,
+ /*
+ * ISO/IEC 23008-3 (MPEG-H Part 3)
+ */
+ MPEGH,
+ /*
+ * ISO/IEC 14496-3
+ */
+ AAC,
+ /*
+ * Dolby Digital
+ */
+ AC3,
+ /*
+ * Dolby Digital Plus
+ */
+ EAC3,
+ /*
+ * Dolby AC-4
+ */
+ AC4,
+ /*
+ * Basic DTS
+ */
+ DTS,
+ /*
+ * High Resolution DTS
+ */
+ DTS_HD,
+ /*
+ * Windows Media Audio
+ */
+ WMA,
+ /*
+ * Opus Interactive Audio Codec
+ */
+ OPUS,
+ /*
+ * VORBIS Interactive Audio Codec
+ */
+ VORBIS,
+ /*
+ * SJ/T 11368-2006
+ */
+ DRA,
+};
+
+/**
+ * Stream type for A/V filter.
+ */
+safe_union AvStreamType {
+ VideoStreamType video;
+
+ AudioStreamType audio;
+};
+
+/**
+ * Indexes can be tagged by start point of slice groups according to ISO/IEC 14496-10.
+ */
+@export
+enum DemuxScIndex : @1.0::DemuxScIndex {
+ /**
+ * All blocks are coded as I blocks.
+ */
+ I_SLICE = 1 << 4,
+ /**
+ * Blocks are coded as I or P blocks.
+ */
+ P_SLICE = 1 << 5,
+ /**
+ * Blocks are coded as I, P or B blocks.
+ */
+ B_SLICE = 1 << 6,
+ /**
+ * A so-called switching I slice that is coded.
+ */
+ SI_SLICE = 1 << 7,
+ /**
+ * A so-called switching P slice that is coded.
+ */
+ SP_SLICE = 1 << 8,
+};
diff --git a/tv/tuner/1.1/vts/OWNERS b/tv/tuner/1.1/vts/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.1/vts/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.1/vts/functional/Android.bp b/tv/tuner/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..1fc36f1
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/Android.bp
@@ -0,0 +1,49 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalTvTunerV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "DemuxTests.cpp",
+ "DvrTests.cpp",
+ "FilterTests.cpp",
+ "FrontendTests.cpp",
+ "VtsHalTvTunerV1_1TargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas@1.1",
+ "android.hardware.cas@1.2",
+ "android.hardware.tv.tuner@1.0",
+ "android.hardware.tv.tuner@1.1",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlallocatorutils",
+ "libhidlmemory",
+ "libcutils",
+ "libfmq",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+
+ require_root: true,
+}
diff --git a/tv/tuner/1.1/vts/functional/DemuxTests.cpp b/tv/tuner/1.1/vts/functional/DemuxTests.cpp
new file mode 100644
index 0000000..b1d8a0a
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DemuxTests.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "DemuxTests.h"
+
+AssertionResult DemuxTests::openDemux(sp<IDemux>& demux, uint32_t& demuxId) {
+ Result status;
+ mService->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) {
+ mDemux = demuxSp;
+ demux = demuxSp;
+ demuxId = id;
+ status = result;
+ });
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) {
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ auto status = mDemux->setFrontendDataSource(frontendId);
+ return AssertionResult(status.isOk());
+}
+
+AssertionResult DemuxTests::closeDemux() {
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ auto status = mDemux->close();
+ mDemux = nullptr;
+ return AssertionResult(status.isOk());
+}
\ No newline at end of file
diff --git a/tv/tuner/1.1/vts/functional/DemuxTests.h b/tv/tuner/1.1/vts/functional/DemuxTests.h
new file mode 100644
index 0000000..c28d6ca
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DemuxTests.h
@@ -0,0 +1,56 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::sp;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+class DemuxTests {
+ public:
+ void setService(sp<ITuner> tuner) { mService = tuner; }
+
+ AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId);
+ AssertionResult setDemuxFrontendDataSource(uint32_t frontendId);
+ AssertionResult closeDemux();
+
+ protected:
+ static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+ static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+ sp<ITuner> mService;
+ sp<IDemux> mDemux;
+};
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.cpp b/tv/tuner/1.1/vts/functional/DvrTests.cpp
new file mode 100644
index 0000000..1e478f5
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DvrTests.cpp
@@ -0,0 +1,349 @@
+/*
+ * 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 "DvrTests.h"
+
+void DvrCallback::startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+ MQDesc& playbackMQDescriptor) {
+ mInputDataFile = dataInputFile;
+ mPlaybackSettings = settings;
+ mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mPlaybackMQ);
+ pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, this);
+ pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+ mPlaybackThreadRunning = false;
+ mKeepWritingPlaybackFMQ = false;
+
+ android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* user) {
+ DvrCallback* const self = static_cast<DvrCallback*>(user);
+ self->playbackThreadLoop();
+ return 0;
+}
+
+void DvrCallback::playbackThreadLoop() {
+ android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+ mPlaybackThreadRunning = true;
+
+ // Create the EventFlag that is used to signal the HAL impl that data have been
+ // written into the Playback FMQ
+ EventFlag* playbackMQEventFlag;
+ EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
+ android::OK);
+
+ int fd = open(mInputDataFile.c_str(), O_RDONLY | O_LARGEFILE);
+ int readBytes;
+ uint32_t regionSize = 0;
+ uint8_t* buffer;
+ ALOGW("[vts] playback thread loop start %s", mInputDataFile.c_str());
+ if (fd < 0) {
+ mPlaybackThreadRunning = false;
+ ALOGW("[vts] Error %s", strerror(errno));
+ }
+
+ while (mPlaybackThreadRunning) {
+ while (mKeepWritingPlaybackFMQ) {
+ int totalWrite = mPlaybackMQ->availableToWrite();
+ if (totalWrite * 4 < mPlaybackMQ->getQuantumCount()) {
+ // Wait for the HAL implementation to read more data then write.
+ continue;
+ }
+ MessageQueue<uint8_t, kSynchronizedReadWrite>::MemTransaction memTx;
+ if (!mPlaybackMQ->beginWrite(totalWrite, &memTx)) {
+ ALOGW("[vts] Fail to write into Playback fmq.");
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ auto first = memTx.getFirstRegion();
+ buffer = first.getAddress();
+ regionSize = first.getLength();
+
+ if (regionSize > 0) {
+ readBytes = read(fd, buffer, regionSize);
+ if (readBytes <= 0) {
+ if (readBytes < 0) {
+ ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+ } else {
+ ALOGW("[vts] playback input EOF.");
+ }
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ }
+ if (regionSize == 0 || (readBytes == regionSize && regionSize < totalWrite)) {
+ auto second = memTx.getSecondRegion();
+ buffer = second.getAddress();
+ regionSize = second.getLength();
+ int ret = read(fd, buffer, regionSize);
+ if (ret <= 0) {
+ if (ret < 0) {
+ ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+ } else {
+ ALOGW("[vts] playback input EOF.");
+ }
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ readBytes += ret;
+ }
+ if (!mPlaybackMQ->commitWrite(readBytes)) {
+ ALOGW("[vts] Failed to commit write playback fmq.");
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ }
+ }
+
+ mPlaybackThreadRunning = false;
+ ALOGW("[vts] Playback thread end.");
+ close(fd);
+}
+
+void DvrCallback::testRecordOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mDataOutputBuffer.empty()) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+ stopRecordThread();
+ return;
+ }
+ }
+ stopRecordThread();
+ ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSettings,
+ MQDesc& recordMQDescriptor) {
+ mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mRecordMQ);
+ struct RecordThreadArgs* threadArgs =
+ (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+ threadArgs->user = this;
+ threadArgs->recordSettings = &recordSettings;
+ threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+ pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+ pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+ DvrCallback* const self =
+ static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+ self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSettings,
+ ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+ return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* keepReadingRecordFMQ) {
+ ALOGD("[vts] DvrCallback record threadLoop start.");
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+ mRecordThreadRunning = true;
+ mKeepReadingRecordFMQ = true;
+
+ // Create the EventFlag that is used to signal the HAL impl that data have been
+ // read from the Record FMQ
+ EventFlag* recordMQEventFlag;
+ EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+ android::OK);
+
+ while (mRecordThreadRunning) {
+ while (*keepReadingRecordFMQ) {
+ uint32_t efState = 0;
+ android::status_t status = recordMQEventFlag->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+ true /* retry on spurious wake */);
+ if (status != android::OK) {
+ ALOGD("[vts] wait for data ready on the record FMQ");
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ
+ // immediately after the DATA_READY from the VTS/framework
+ if (!readRecordFMQ()) {
+ ALOGD("[vts] record data failed to be filtered. Ending thread");
+ mRecordThreadRunning = false;
+ break;
+ }
+ }
+ }
+
+ mRecordThreadRunning = false;
+ ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ bool result = false;
+ int readSize = mRecordMQ->availableToRead();
+ mDataOutputBuffer.clear();
+ mDataOutputBuffer.resize(readSize);
+ result = mRecordMQ->read(mDataOutputBuffer.data(), readSize);
+ EXPECT_TRUE(result) << "can't read from Record MQ";
+ mMsgCondition.signal();
+ return result;
+}
+
+void DvrCallback::stopRecordThread() {
+ mKeepReadingRecordFMQ = false;
+ mRecordThreadRunning = false;
+}
+
+AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+ // Create dvr callback
+ if (type == DvrType::PLAYBACK) {
+ mDvrPlaybackCallback = new DvrCallback();
+ mDemux->openDvr(type, bufferSize, mDvrPlaybackCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvrPlayback = dvr;
+ status = result;
+ });
+ if (status == Result::SUCCESS) {
+ mDvrPlaybackCallback->setDvr(mDvrPlayback);
+ }
+ }
+
+ if (type == DvrType::RECORD) {
+ mDvrRecordCallback = new DvrCallback();
+ mDemux->openDvr(type, bufferSize, mDvrRecordCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvrRecord = dvr;
+ status = result;
+ });
+ if (status == Result::SUCCESS) {
+ mDvrRecordCallback->setDvr(mDvrRecord);
+ }
+ }
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
+ Result status = mDvrPlayback->configure(setting);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
+ Result status = mDvrRecord->configure(setting);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrPlaybackMQDescriptor() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+ mDvrPlayback->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mDvrPlaybackMQDescriptor = dvrMQDesc;
+ status = result;
+ });
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrRecordMQDescriptor() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+ mDvrRecord->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mDvrRecordMQDescriptor = dvrMQDesc;
+ status = result;
+ });
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::attachFilterToDvr(sp<IFilter> filter) {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+ status = mDvrRecord->attachFilter(filter);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::detachFilterToDvr(sp<IFilter> filter) {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+ status = mDvrRecord->detachFilter(filter);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrPlayback() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+ status = mDvrPlayback->start();
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrPlayback() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+ status = mDvrPlayback->stop();
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrPlayback() {
+ ASSERT_TRUE(mDemux);
+ ASSERT_TRUE(mDvrPlayback);
+ ASSERT_TRUE(mDvrPlayback->close() == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrRecord() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+ status = mDvrRecord->start();
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrRecord() {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+ status = mDvrRecord->stop();
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrRecord() {
+ ASSERT_TRUE(mDemux);
+ ASSERT_TRUE(mDvrRecord);
+ ASSERT_TRUE(mDvrRecord->close() == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.h b/tv/tuner/1.1/vts/functional/DvrTests.h
new file mode 100644
index 0000000..289ddf6
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DvrTests.h
@@ -0,0 +1,195 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <fcntl.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+#include "FilterTests.h"
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using namespace std;
+
+#define WAIT_TIMEOUT 3000000000
+
+class DvrCallback : public IDvrCallback {
+ public:
+ virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+ ALOGD("[vts] record status %hhu", status);
+ switch (status) {
+ case DemuxFilterStatus::DATA_READY:
+ break;
+ case DemuxFilterStatus::LOW_WATER:
+ break;
+ case DemuxFilterStatus::HIGH_WATER:
+ case DemuxFilterStatus::OVERFLOW:
+ ALOGD("[vts] record overflow. Flushing.");
+ EXPECT_TRUE(mDvr) << "Dvr callback is not set with an IDvr";
+ if (mDvr) {
+ Result result = mDvr->flush();
+ ALOGD("[vts] Flushing result %d.", result);
+ }
+ break;
+ }
+ return Void();
+ }
+
+ virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+ // android::Mutex::Autolock autoLock(mMsgLock);
+ ALOGD("[vts] playback status %d", status);
+ switch (status) {
+ case PlaybackStatus::SPACE_EMPTY:
+ case PlaybackStatus::SPACE_ALMOST_EMPTY:
+ ALOGD("[vts] keep playback inputing %d", status);
+ mKeepWritingPlaybackFMQ = true;
+ break;
+ case PlaybackStatus::SPACE_ALMOST_FULL:
+ case PlaybackStatus::SPACE_FULL:
+ ALOGD("[vts] stop playback inputing %d", status);
+ mKeepWritingPlaybackFMQ = false;
+ break;
+ }
+ return Void();
+ }
+
+ void stopPlaybackThread();
+ void testRecordOutput();
+ void stopRecordThread();
+
+ void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+ MQDesc& playbackMQDescriptor);
+ void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor);
+ static void* __threadLoopPlayback(void* user);
+ static void* __threadLoopRecord(void* threadArgs);
+ void playbackThreadLoop();
+ void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+ bool readRecordFMQ();
+
+ void setDvr(sp<IDvr> dvr) { mDvr = dvr; }
+
+ private:
+ struct RecordThreadArgs {
+ DvrCallback* user;
+ RecordSettings* recordSettings;
+ bool* keepReadingRecordFMQ;
+ };
+ // uint16_t mDataLength = 0;
+ std::vector<uint8_t> mDataOutputBuffer;
+
+ std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ;
+ std::unique_ptr<FilterMQ> mPlaybackMQ;
+ std::unique_ptr<FilterMQ> mRecordMQ;
+ std::map<uint32_t, EventFlag*> mFilterMQEventFlag;
+
+ android::Mutex mMsgLock;
+ android::Mutex mPlaybackThreadLock;
+ android::Mutex mRecordThreadLock;
+ android::Condition mMsgCondition;
+
+ bool mKeepWritingPlaybackFMQ = true;
+ bool mKeepReadingRecordFMQ = true;
+ bool mPlaybackThreadRunning;
+ bool mRecordThreadRunning;
+ pthread_t mPlaybackThread;
+ pthread_t mRecordThread;
+ string mInputDataFile;
+ PlaybackSettings mPlaybackSettings;
+
+ sp<IDvr> mDvr = nullptr;
+
+ // int mPidFilterOutputCount = 0;
+};
+
+class DvrTests {
+ public:
+ void setService(sp<ITuner> tuner) { mService = tuner; }
+ void setDemux(sp<IDemux> demux) { mDemux = demux; }
+
+ void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) {
+ mDvrPlaybackCallback->startPlaybackInputThread(dataInputFile, settings,
+ mDvrPlaybackMQDescriptor);
+ };
+
+ void startRecordOutputThread(RecordSettings settings) {
+ mDvrRecordCallback->startRecordOutputThread(settings, mDvrRecordMQDescriptor);
+ };
+
+ void stopPlaybackThread() { mDvrPlaybackCallback->stopPlaybackThread(); }
+ void testRecordOutput() { mDvrRecordCallback->testRecordOutput(); }
+ void stopRecordThread() { mDvrRecordCallback->stopRecordThread(); }
+
+ AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize);
+ AssertionResult configDvrPlayback(DvrSettings setting);
+ AssertionResult configDvrRecord(DvrSettings setting);
+ AssertionResult getDvrPlaybackMQDescriptor();
+ AssertionResult getDvrRecordMQDescriptor();
+ AssertionResult attachFilterToDvr(sp<IFilter> filter);
+ AssertionResult detachFilterToDvr(sp<IFilter> filter);
+ AssertionResult stopDvrPlayback();
+ AssertionResult startDvrPlayback();
+ AssertionResult stopDvrRecord();
+ AssertionResult startDvrRecord();
+ void closeDvrPlayback();
+ void closeDvrRecord();
+
+ protected:
+ static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+ static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+ sp<ITuner> mService;
+ sp<IDvr> mDvrPlayback;
+ sp<IDvr> mDvrRecord;
+ sp<IDemux> mDemux;
+ sp<DvrCallback> mDvrPlaybackCallback;
+ sp<DvrCallback> mDvrRecordCallback;
+ MQDesc mDvrPlaybackMQDescriptor;
+ MQDesc mDvrRecordMQDescriptor;
+};
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
new file mode 100644
index 0000000..f114a66
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -0,0 +1,273 @@
+/*
+ * 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 "FilterTests.h"
+
+void FilterCallback::testFilterDataOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mPidFilterOutputCount < 1) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
+ return;
+ }
+ }
+ mPidFilterOutputCount = 0;
+ ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::testFilterScramblingEvent() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mScramblingStatusEvent < 1) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "scrambling event does not output within timeout";
+ return;
+ }
+ }
+ mScramblingStatusEvent = 0;
+ ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::readFilterEventData() {
+ ALOGW("[vts] reading filter event");
+ // todo separate filter handlers
+ for (int i = 0; i < mFilterEvent.events.size(); i++) {
+ auto event = mFilterEvent.events[i];
+ switch (event.getDiscriminator()) {
+ case DemuxFilterEvent::Event::hidl_discriminator::media:
+ ALOGD("[vts] Media filter event, avMemHandle numFds=%d.",
+ event.media().avMemory.getNativeHandle()->numFds);
+ dumpAvData(event.media());
+ break;
+ default:
+ break;
+ }
+ }
+ for (int i = 0; i < mFilterEventExt.events.size(); i++) {
+ auto eventExt = mFilterEventExt.events[i];
+ switch (eventExt.getDiscriminator()) {
+ case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord:
+ ALOGD("[vts] Extended TS record filter event, pts=%" PRIu64 ", firstMbInSlice=%d",
+ eventExt.tsRecord().pts, eventExt.tsRecord().firstMbInSlice);
+ break;
+ case DemuxFilterEventExt::Event::hidl_discriminator::mmtpRecord:
+ ALOGD("[vts] Extended MMTP record filter event, pts=%" PRIu64
+ ", firstMbInSlice=%d, mpuSequenceNumber=%d",
+ eventExt.mmtpRecord().pts, eventExt.mmtpRecord().firstMbInSlice,
+ eventExt.mmtpRecord().mpuSequenceNumber);
+ break;
+ case DemuxFilterEventExt::Event::hidl_discriminator::scramblingStatus:
+ mScramblingStatusEvent++;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
+ uint32_t length = event.dataLength;
+ uint32_t offset = event.offset;
+ // read data from buffer pointed by a handle
+ hidl_handle handle = event.avMemory;
+ if (handle.getNativeHandle()->numFds == 0) {
+ if (mAvSharedHandle == NULL) {
+ return false;
+ }
+ handle = mAvSharedHandle;
+ }
+
+ 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));
+ if (buffer == MAP_FAILED) {
+ ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
+ return false;
+ }
+ uint8_t output[length + 1];
+ memcpy(output, buffer + offset, length);
+ // print buffer and check with golden output.
+ ::close(av_fd);
+ return true;
+}
+
+AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+ // Create demux callback
+ mFilterCallback = new FilterCallback();
+
+ // Add filter to the local demux
+ mDemux->openFilter(type, bufferSize, mFilterCallback,
+ [&](Result result, const sp<IFilter>& filter) {
+ mFilter = filter;
+ status = result;
+ });
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(uint64_t& filterId) {
+ Result status;
+ EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+ EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
+ EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
+
+ sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
+ android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
+ if (filter_v1_1 != NULL) {
+ filter_v1_1->getId64Bit([&](Result result, uint64_t filterId) {
+ mFilterId = filterId;
+ status = result;
+ });
+ } else {
+ ALOGW("[vts] Can't cast IFilter into v1_1.");
+ return failure();
+ }
+
+ if (status == Result::SUCCESS) {
+ mFilterCallback->setFilterId(mFilterId);
+ mFilterCallback->setFilterInterface(mFilter);
+ mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
+ mFilters[mFilterId] = mFilter;
+ mFilterCallbacks[mFilterId] = mFilterCallback;
+ filterId = mFilterId;
+ }
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getSharedAvMemoryHandle(uint64_t filterId) {
+ EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
+ Result status = Result::UNKNOWN_ERROR;
+ 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) {
+ filter_v1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+ status = r;
+ if (status == Result::SUCCESS) {
+ mFilterCallbacks[mFilterId]->setSharedHandle(avMemory);
+ mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
+ mAvSharedHandle = avMemory;
+ }
+ });
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::releaseShareAvHandle(uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
+ EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
+ status = mFilters[filterId]->releaseAvHandle(mAvSharedHandle, 0 /*dataId*/);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ status = mFilters[filterId]->configure(setting);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configAvFilterStreamType(AvStreamType type, uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ 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->configureAvStreamType(type);
+ } else {
+ ALOGW("[vts] Can't cast IFilter into v1_1.");
+ return failure();
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configIpFilterCid(uint32_t ipCid, uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Open Ip filter first.";
+
+ 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->configureIpCid(ipCid);
+ } else {
+ ALOGW("[vts] Can't cast IFilter into v1_1.");
+ return failure();
+ }
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getFilterMQDescriptor(uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
+
+ mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
+ mFilterMQDescriptor = filterMQDesc;
+ status = result;
+ });
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::startFilter(uint64_t filterId) {
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ Result status = mFilters[filterId]->start();
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::stopFilter(uint64_t filterId) {
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ Result status = mFilters[filterId]->stop();
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::closeFilter(uint64_t filterId) {
+ EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+ Result status = mFilters[filterId]->close();
+ if (status == Result::SUCCESS) {
+ for (int i = 0; i < mUsedFilterIds.size(); i++) {
+ if (mUsedFilterIds[i] == filterId) {
+ mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
+ break;
+ }
+ }
+ mFilterCallbacks.erase(filterId);
+ mFilters.erase(filterId);
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configureScramblingEvent(uint64_t filterId, uint32_t statuses) {
+ 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);
+ mFilterCallbacks[filterId]->testFilterScramblingEvent();
+ } else {
+ ALOGW("[vts] Can't cast IFilter into v1_1.");
+ return failure();
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
new file mode 100644
index 0000000..d88f171
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -0,0 +1,229 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <inttypes.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+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::IFilterCallback;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+enum FilterEventType : uint8_t {
+ UNDEFINED,
+ SECTION,
+ MEDIA,
+ PES,
+ RECORD,
+ MMTPRECORD,
+ DOWNLOAD,
+ TEMI,
+};
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+#define WAIT_TIMEOUT 3000000000
+
+class FilterCallback : public IFilterCallback {
+ public:
+ virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+ const DemuxFilterEventExt& filterEventExt) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ // Temprarily we treat the first coming back filter data on the matching pid a success
+ // once all of the MQ are cleared, means we got all the expected output
+ mFilterEvent = filterEvent;
+ mFilterEventExt = filterEventExt;
+ readFilterEventData();
+ mPidFilterOutputCount++;
+ mMsgCondition.signal();
+ return Void();
+ }
+
+ virtual Return<void> onFilterEvent(
+ const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& filterEvent) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ // Temprarily we treat the first coming back filter data on the matching pid a success
+ // once all of the MQ are cleared, means we got all the expected output
+ mFilterEvent = filterEvent;
+ readFilterEventData();
+ mPidFilterOutputCount++;
+ mMsgCondition.signal();
+ return Void();
+ }
+
+ virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
+ return Void();
+ }
+
+ void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+ void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
+ void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
+ void setSharedHandle(hidl_handle sharedHandle) { mAvSharedHandle = sharedHandle; }
+ void setMemSize(uint64_t size) { mAvSharedMemSize = size; }
+
+ void testFilterDataOutput();
+ void testFilterScramblingEvent();
+
+ void readFilterEventData();
+ bool dumpAvData(DemuxFilterMediaEvent event);
+
+ private:
+ uint32_t mFilterId;
+ sp<IFilter> mFilter;
+ FilterEventType mFilterEventType;
+ DemuxFilterEvent mFilterEvent;
+ DemuxFilterEventExt mFilterEventExt;
+
+ hidl_handle mAvSharedHandle = NULL;
+ uint64_t mAvSharedMemSize = -1;
+
+ android::Mutex mMsgLock;
+ android::Mutex mFilterOutputLock;
+ android::Condition mMsgCondition;
+
+ int mPidFilterOutputCount = 0;
+ int mScramblingStatusEvent = 0;
+};
+
+class FilterTests {
+ public:
+ void setService(sp<ITuner> tuner) { mService = tuner; }
+ void setDemux(sp<IDemux> demux) { mDemux = demux; }
+ sp<IFilter> getFilterById(uint64_t filterId) { return mFilters[filterId]; }
+
+ map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
+
+ AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
+ AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId);
+ AssertionResult getSharedAvMemoryHandle(uint64_t filterId);
+ AssertionResult releaseShareAvHandle(uint64_t filterId);
+ 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 getFilterMQDescriptor(uint64_t filterId);
+ AssertionResult startFilter(uint64_t filterId);
+ AssertionResult stopFilter(uint64_t filterId);
+ AssertionResult closeFilter(uint64_t filterId);
+
+ FilterEventType getFilterEventType(DemuxFilterType type) {
+ FilterEventType eventType = FilterEventType::UNDEFINED;
+ switch (type.mainType) {
+ case DemuxFilterMainType::TS:
+ switch (type.subType.tsFilterType()) {
+ case DemuxTsFilterType::UNDEFINED:
+ break;
+ case DemuxTsFilterType::SECTION:
+ eventType = FilterEventType::SECTION;
+ break;
+ case DemuxTsFilterType::PES:
+ eventType = FilterEventType::PES;
+ break;
+ case DemuxTsFilterType::TS:
+ break;
+ case DemuxTsFilterType::AUDIO:
+ case DemuxTsFilterType::VIDEO:
+ eventType = FilterEventType::MEDIA;
+ break;
+ case DemuxTsFilterType::PCR:
+ break;
+ case DemuxTsFilterType::RECORD:
+ eventType = FilterEventType::RECORD;
+ break;
+ case DemuxTsFilterType::TEMI:
+ eventType = FilterEventType::TEMI;
+ break;
+ }
+ break;
+ case DemuxFilterMainType::MMTP:
+ /*mmtpSettings*/
+ break;
+ case DemuxFilterMainType::IP:
+ /*ipSettings*/
+ break;
+ case DemuxFilterMainType::TLV:
+ /*tlvSettings*/
+ break;
+ case DemuxFilterMainType::ALP:
+ /*alpSettings*/
+ break;
+ default:
+ break;
+ }
+ return eventType;
+ }
+
+ protected:
+ static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+ static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+ sp<ITuner> mService;
+ sp<IFilter> mFilter;
+ sp<IDemux> mDemux;
+ map<uint64_t, sp<IFilter>> mFilters;
+ map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
+
+ sp<FilterCallback> mFilterCallback;
+ MQDesc mFilterMQDescriptor;
+ vector<uint64_t> mUsedFilterIds;
+
+ hidl_handle mAvSharedHandle = NULL;
+
+ uint64_t mFilterId = -1;
+};
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.cpp b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
new file mode 100644
index 0000000..0948f74
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
@@ -0,0 +1,494 @@
+/*
+ * 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 "FrontendTests.h"
+
+Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
+ mEventReceived = true;
+ mMsgCondition.signal();
+ switch (frontendEventType) {
+ case FrontendEventType::LOCKED:
+ mLockMsgReceived = true;
+ mLockMsgCondition.signal();
+ return Void();
+ default:
+ // do nothing
+ return Void();
+ }
+}
+
+Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type,
+ const FrontendScanMessage& message) {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mScanMsgProcessed) {
+ mMsgCondition.wait(mMsgLock);
+ }
+ ALOGD("[vts] frontend scan message. Type: %d", type);
+ mScanMessageReceived = true;
+ mScanMsgProcessed = false;
+ mScanMessageType = type;
+ mScanMessage = message;
+ mMsgCondition.signal();
+ return Void();
+}
+
+Return<void> FrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
+ const FrontendScanMessageExt1_1& message) {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ ALOGD("[vts] frontend ext1_1 scan message. Type: %d", type);
+ switch (message.getDiscriminator()) {
+ case FrontendScanMessageExt1_1::hidl_discriminator::modulation:
+ readFrontendScanMessageExt1_1Modulation(message.modulation());
+ break;
+ case FrontendScanMessageExt1_1::hidl_discriminator::isHighPriority:
+ ALOGD("[vts] frontend ext1_1 scan message high priority: %d", message.isHighPriority());
+ break;
+ case FrontendScanMessageExt1_1::hidl_discriminator::annex:
+ ALOGD("[vts] frontend ext1_1 scan message dvbc annex: %hhu", message.annex());
+ break;
+ default:
+ break;
+ }
+ return Void();
+}
+
+void FrontendCallback::readFrontendScanMessageExt1_1Modulation(FrontendModulation modulation) {
+ switch (modulation.getDiscriminator()) {
+ case FrontendModulation::hidl_discriminator::dvbc:
+ ALOGD("[vts] frontend ext1_1 scan message modulation dvbc: %d", modulation.dvbc());
+ break;
+ case FrontendModulation::hidl_discriminator::dvbs:
+ ALOGD("[vts] frontend ext1_1 scan message modulation dvbs: %d", modulation.dvbs());
+ break;
+ case FrontendModulation::hidl_discriminator::isdbs:
+ ALOGD("[vts] frontend ext1_1 scan message modulation isdbs: %d", modulation.isdbs());
+ break;
+ case FrontendModulation::hidl_discriminator::isdbs3:
+ ALOGD("[vts] frontend ext1_1 scan message modulation isdbs3: %d", modulation.isdbs3());
+ break;
+ case FrontendModulation::hidl_discriminator::isdbt:
+ ALOGD("[vts] frontend ext1_1 scan message modulation isdbt: %d", modulation.isdbt());
+ break;
+ case FrontendModulation::hidl_discriminator::atsc:
+ ALOGD("[vts] frontend ext1_1 scan message modulation atsc: %d", modulation.atsc());
+ break;
+ case FrontendModulation::hidl_discriminator::atsc3:
+ ALOGD("[vts] frontend ext1_1 scan message modulation atsc3: %d", modulation.atsc3());
+ break;
+ case FrontendModulation::hidl_discriminator::dvbt:
+ ALOGD("[vts] frontend ext1_1 scan message modulation dvbt: %d", modulation.dvbt());
+ break;
+ default:
+ break;
+ }
+}
+
+void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings,
+ FrontendSettingsExt1_1 settingsExt1_1) {
+ sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
+ frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
+ if (frontend_1_1 == nullptr) {
+ EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
+ return;
+ }
+
+ Result result = frontend_1_1->tune_1_1(settings, settingsExt1_1);
+ EXPECT_TRUE(result == Result::SUCCESS);
+
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mLockMsgReceived) {
+ if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
+ mLockMsgReceived = false;
+ return;
+ }
+ }
+ mLockMsgReceived = false;
+}
+
+void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config,
+ FrontendScanType type) {
+ sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
+ frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
+ if (frontend_1_1 == nullptr) {
+ EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
+ return;
+ }
+
+ uint32_t targetFrequency = getTargetFrequency(config.settings, config.type);
+ if (type == FrontendScanType::SCAN_BLIND) {
+ // reset the frequency in the scan configuration to test blind scan. The settings param of
+ // passed in means the real input config on the transponder connected to the DUT.
+ // We want the blind the test to start from lower frequency than this to check the blind
+ // scan implementation.
+ resetBlindScanStartingFrequency(config, targetFrequency - 100);
+ }
+
+ Result result = frontend_1_1->scan_1_1(config.settings, type, config.settingsExt1_1);
+ EXPECT_TRUE(result == Result::SUCCESS);
+
+ bool scanMsgLockedReceived = false;
+ bool targetFrequencyReceived = false;
+
+ android::Mutex::Autolock autoLock(mMsgLock);
+wait:
+ while (!mScanMessageReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "Scan message not received within timeout";
+ mScanMessageReceived = false;
+ mScanMsgProcessed = true;
+ return;
+ }
+ }
+
+ if (mScanMessageType != FrontendScanMessageType::END) {
+ if (mScanMessageType == FrontendScanMessageType::LOCKED) {
+ scanMsgLockedReceived = true;
+ Result result = frontend_1_1->scan_1_1(config.settings, type, config.settingsExt1_1);
+ EXPECT_TRUE(result == Result::SUCCESS);
+ }
+
+ if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
+ targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
+ mScanMessage.frequencies()[0] == targetFrequency;
+ }
+
+ if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
+ ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
+ }
+
+ mScanMessageReceived = false;
+ mScanMsgProcessed = true;
+ mMsgCondition.signal();
+ goto wait;
+ }
+
+ EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
+ EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
+ mScanMessageReceived = false;
+ mScanMsgProcessed = true;
+}
+
+uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
+ switch (type) {
+ case FrontendType::ANALOG:
+ return settings.analog().frequency;
+ case FrontendType::ATSC:
+ return settings.atsc().frequency;
+ case FrontendType::ATSC3:
+ return settings.atsc3().frequency;
+ case FrontendType::DVBC:
+ return settings.dvbc().frequency;
+ case FrontendType::DVBS:
+ return settings.dvbs().frequency;
+ case FrontendType::DVBT:
+ return settings.dvbt().frequency;
+ case FrontendType::ISDBS:
+ return settings.isdbs().frequency;
+ case FrontendType::ISDBS3:
+ return settings.isdbs3().frequency;
+ case FrontendType::ISDBT:
+ return settings.isdbt().frequency;
+ default:
+ return 0;
+ }
+}
+
+void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
+ uint32_t resetingFreq) {
+ switch (config.type) {
+ case FrontendType::ANALOG:
+ config.settings.analog().frequency = resetingFreq;
+ break;
+ case FrontendType::ATSC:
+ config.settings.atsc().frequency = resetingFreq;
+ break;
+ case FrontendType::ATSC3:
+ config.settings.atsc3().frequency = resetingFreq;
+ break;
+ case FrontendType::DVBC:
+ config.settings.dvbc().frequency = resetingFreq;
+ break;
+ case FrontendType::DVBS:
+ config.settings.dvbs().frequency = resetingFreq;
+ break;
+ case FrontendType::DVBT:
+ config.settings.dvbt().frequency = resetingFreq;
+ break;
+ case FrontendType::ISDBS:
+ config.settings.isdbs().frequency = resetingFreq;
+ break;
+ case FrontendType::ISDBS3:
+ config.settings.isdbs3().frequency = resetingFreq;
+ break;
+ case FrontendType::ISDBT:
+ config.settings.isdbt().frequency = resetingFreq;
+ break;
+ default:
+ // do nothing
+ return;
+ }
+}
+
+AssertionResult FrontendTests::getFrontendIds() {
+ Result status;
+ mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+ status = result;
+ mFeIds = frontendIds;
+ });
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
+ Result status;
+ mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
+ mFrontendInfo = frontendInfo;
+ status = result;
+ });
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
+ Result status;
+ mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
+ mFrontend = frontend;
+ status = result;
+ });
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::setFrontendCallback() {
+ EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+ mFrontendCallback = new FrontendCallback();
+ auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
+ return AssertionResult(callbackStatus.isOk());
+}
+
+AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
+ EXPECT_TRUE(mFrontendCallback)
+ << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+ EXPECT_TRUE(mFrontendInfo.type == config.type)
+ << "FrontendConfig does not match the frontend info of the given id.";
+
+ mFrontendCallback->scanTest(mFrontend, config, type);
+ return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::stopScanFrontend() {
+ EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+ Result status;
+ status = mFrontend->stopScan();
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::getFrontendDtmbCaps(uint32_t id) {
+ Result status;
+ mService->getFrontendDtmbCapabilities(
+ id, [&](Result result, const FrontendDtmbCapabilities& /*caps*/) { status = result; });
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::verifyFrontendStatusExt1_1(vector<FrontendStatusTypeExt1_1> statusTypes,
+ vector<FrontendStatusExt1_1> expectStatuses) {
+ ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
+ Result status;
+ vector<FrontendStatusExt1_1> realStatuses;
+
+ sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
+ frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
+ if (frontend_1_1 == nullptr) {
+ EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
+ return;
+ }
+
+ frontend_1_1->getStatusExt1_1(
+ statusTypes, [&](Result result, const hidl_vec<FrontendStatusExt1_1>& statuses) {
+ status = result;
+ realStatuses = statuses;
+ });
+
+ ASSERT_TRUE(realStatuses.size() == statusTypes.size());
+ for (int i = 0; i < statusTypes.size(); i++) {
+ FrontendStatusTypeExt1_1 type = statusTypes[i];
+ switch (type) {
+ case FrontendStatusTypeExt1_1::MODULATIONS: {
+ // TODO: verify modulations
+ break;
+ }
+ case FrontendStatusTypeExt1_1::BERS: {
+ ASSERT_TRUE(std::equal(realStatuses[i].bers().begin(), realStatuses[i].bers().end(),
+ expectStatuses[i].bers().begin()));
+ break;
+ }
+ case FrontendStatusTypeExt1_1::CODERATES: {
+ ASSERT_TRUE(std::equal(realStatuses[i].codeRates().begin(),
+ realStatuses[i].codeRates().end(),
+ expectStatuses[i].codeRates().begin()));
+ break;
+ }
+ case FrontendStatusTypeExt1_1::GUARD_INTERVAL: {
+ // TODO: verify interval
+ break;
+ }
+ case FrontendStatusTypeExt1_1::TRANSMISSION_MODE: {
+ // TODO: verify tranmission mode
+ break;
+ }
+ case FrontendStatusTypeExt1_1::UEC: {
+ ASSERT_TRUE(realStatuses[i].uec() == expectStatuses[i].uec());
+ break;
+ }
+ case FrontendStatusTypeExt1_1::T2_SYSTEM_ID: {
+ ASSERT_TRUE(realStatuses[i].systemId() == expectStatuses[i].systemId());
+ break;
+ }
+ case FrontendStatusTypeExt1_1::INTERLEAVINGS: {
+ ASSERT_TRUE(std::equal(realStatuses[i].interleaving().begin(),
+ realStatuses[i].interleaving().end(),
+ expectStatuses[i].interleaving().begin()));
+ break;
+ }
+ case FrontendStatusTypeExt1_1::ISDBT_SEGMENTS: {
+ ASSERT_TRUE(std::equal(realStatuses[i].isdbtSegment().begin(),
+ realStatuses[i].isdbtSegment().end(),
+ expectStatuses[i].isdbtSegment().begin()));
+ break;
+ }
+ case FrontendStatusTypeExt1_1::TS_DATA_RATES: {
+ ASSERT_TRUE(std::equal(realStatuses[i].tsDataRate().begin(),
+ realStatuses[i].tsDataRate().end(),
+ expectStatuses[i].tsDataRate().begin()));
+ break;
+ }
+ case FrontendStatusTypeExt1_1::ROLL_OFF: {
+ // TODO: verify roll off
+ break;
+ }
+ case FrontendStatusTypeExt1_1::IS_MISO: {
+ ASSERT_TRUE(realStatuses[i].isMiso() == expectStatuses[i].isMiso());
+ break;
+ }
+ case FrontendStatusTypeExt1_1::IS_LINEAR: {
+ ASSERT_TRUE(realStatuses[i].isLinear() == expectStatuses[i].isLinear());
+ break;
+ }
+ case FrontendStatusTypeExt1_1::IS_SHORT_FRAMES: {
+ ASSERT_TRUE(realStatuses[i].isShortFrames() == expectStatuses[i].isShortFrames());
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+ ASSERT_TRUE(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
+ EXPECT_TRUE(mFrontendCallback)
+ << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+ EXPECT_TRUE(mFrontendInfo.type == config.type)
+ << "FrontendConfig does not match the frontend info of the given id.";
+
+ mIsSoftwareFe = config.isSoftwareFe;
+ bool result = true;
+ if (mIsSoftwareFe && testWithDemux) {
+ result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
+ result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
+ result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
+ mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
+ mDvrConfig.settings.playback());
+ if (!result) {
+ ALOGW("[vts] Software frontend dvr configure failed.");
+ return failure();
+ }
+ }
+ mFrontendCallback->tuneTestOnLock(mFrontend, config.settings, config.settingsExt1_1);
+ return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
+ EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+ Result status;
+ status = mFrontend->stopTune();
+ if (mIsSoftwareFe && testWithDemux) {
+ mDvrTests.stopPlaybackThread();
+ mDvrTests.closeDvrPlayback();
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::closeFrontend() {
+ EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+ Result status;
+ status = mFrontend->close();
+ mFrontend = nullptr;
+ mFrontendCallback = nullptr;
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
+ ASSERT_TRUE(getFrontendIds());
+ ASSERT_TRUE(mFeIds.size() > 0);
+ for (size_t i = 0; i < mFeIds.size(); i++) {
+ ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+ if (mFrontendInfo.type != feType) {
+ continue;
+ }
+ feId = mFeIds[i];
+ return;
+ }
+ feId = INVALID_ID;
+}
+
+void FrontendTests::tuneTest(FrontendConfig frontendConf) {
+ uint32_t feId;
+ getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(openFrontendById(feId));
+ ASSERT_TRUE(setFrontendCallback());
+ ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+ verifyFrontendStatusExt1_1(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
+ ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+ ASSERT_TRUE(closeFrontend());
+}
+
+void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
+ uint32_t feId;
+ getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(openFrontendById(feId));
+ ASSERT_TRUE(setFrontendCallback());
+ ASSERT_TRUE(scanFrontend(frontendConf, scanType));
+ ASSERT_TRUE(stopScanFrontend());
+ ASSERT_TRUE(closeFrontend());
+}
+
+void FrontendTests::getFrontendDtmbCapsTest() {
+ uint32_t feId;
+ getFrontendIdByType(
+ static_cast<FrontendType>(android::hardware::tv::tuner::V1_1::FrontendType::DTMB),
+ feId);
+ if (feId != INVALID_ID) {
+ ALOGD("[vts] Found DTMB Frontend");
+ ASSERT_TRUE(getFrontendDtmbCaps(feId));
+ }
+}
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.h b/tv/tuner/1.1/vts/functional/FrontendTests.h
new file mode 100644
index 0000000..243d9de
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.h
@@ -0,0 +1,161 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <android/hardware/tv/tuner/1.1/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+#include "DvrTests.h"
+#include "VtsHalTvTunerV1_1TestConfigurations.h"
+
+#define WAIT_TIMEOUT 3000000000
+#define INVALID_ID -1
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::FrontendEventType;
+using android::hardware::tv::tuner::V1_0::FrontendId;
+using android::hardware::tv::tuner::V1_0::FrontendInfo;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using android::hardware::tv::tuner::V1_0::FrontendScanType;
+using android::hardware::tv::tuner::V1_0::IFrontend;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities;
+using android::hardware::tv::tuner::V1_1::FrontendModulation;
+using android::hardware::tv::tuner::V1_1::FrontendScanMessageExt1_1;
+using android::hardware::tv::tuner::V1_1::FrontendScanMessageTypeExt1_1;
+using android::hardware::tv::tuner::V1_1::IFrontendCallback;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+#define INVALID_ID -1
+#define WAIT_TIMEOUT 3000000000
+
+class FrontendCallback : public IFrontendCallback {
+ public:
+ virtual Return<void> onEvent(FrontendEventType frontendEventType) override;
+ virtual Return<void> onScanMessage(FrontendScanMessageType type,
+ const FrontendScanMessage& message) override;
+ virtual Return<void> onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
+ const FrontendScanMessageExt1_1& message) override;
+
+ void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings,
+ FrontendSettingsExt1_1 settingsExt1_1);
+ void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type);
+
+ // Helper methods
+ uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type);
+ void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq);
+
+ private:
+ void readFrontendScanMessageExt1_1Modulation(FrontendModulation modulation);
+
+ bool mEventReceived = false;
+ bool mScanMessageReceived = false;
+ bool mLockMsgReceived = false;
+ bool mScanMsgProcessed = true;
+ FrontendScanMessageType mScanMessageType;
+ FrontendScanMessage mScanMessage;
+ hidl_vec<uint8_t> mEventMessage;
+ android::Mutex mMsgLock;
+ android::Condition mMsgCondition;
+ android::Condition mLockMsgCondition;
+};
+
+class FrontendTests {
+ public:
+ sp<ITuner> mService;
+
+ void setService(sp<ITuner> tuner) {
+ mService = tuner;
+ mDvrTests.setService(tuner);
+ getDefaultSoftwareFrontendPlaybackConfig(mDvrConfig);
+ }
+
+ AssertionResult getFrontendIds();
+ AssertionResult getFrontendInfo(uint32_t frontendId);
+ AssertionResult openFrontendById(uint32_t frontendId);
+ AssertionResult setFrontendCallback();
+ AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type);
+ AssertionResult stopScanFrontend();
+ AssertionResult tuneFrontend(FrontendConfig config, bool testWithDemux);
+ void verifyFrontendStatusExt1_1(vector<FrontendStatusTypeExt1_1> statusTypes,
+ vector<FrontendStatusExt1_1> expectStatuses);
+ AssertionResult stopTuneFrontend(bool testWithDemux);
+ AssertionResult closeFrontend();
+ AssertionResult getFrontendDtmbCaps(uint32_t);
+
+ void getFrontendIdByType(FrontendType feType, uint32_t& feId);
+ void tuneTest(FrontendConfig frontendConf);
+ void scanTest(FrontendConfig frontend, FrontendScanType type);
+ void getFrontendDtmbCapsTest();
+
+ void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
+ void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+ void setSoftwareFrontendDvrConfig(DvrConfig conf) { mDvrConfig = conf; }
+
+ protected:
+ static AssertionResult failure() { return ::testing::AssertionFailure(); }
+ static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+ void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+ PlaybackSettings playbackSettings{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::ES,
+ .packetSize = 188,
+ };
+ dvrConfig.type = DvrType::PLAYBACK;
+ dvrConfig.playbackInputFile = "/data/local/tmp/test.es";
+ dvrConfig.bufferSize = FMQ_SIZE_4M;
+ dvrConfig.settings.playback(playbackSettings);
+ }
+
+ sp<IFrontend> mFrontend;
+ FrontendInfo mFrontendInfo;
+ sp<FrontendCallback> mFrontendCallback;
+ hidl_vec<FrontendId> mFeIds;
+
+ DvrTests mDvrTests;
+ bool mIsSoftwareFe = false;
+ DvrConfig mDvrConfig;
+};
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
new file mode 100644
index 0000000..17abf49
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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 "VtsHalTvTunerV1_1TargetTest.h"
+
+namespace {
+
+AssertionResult TunerBroadcastHidlTest::filterDataOutputTest() {
+ return filterDataOutputTestBase(mFilterTests);
+}
+
+AssertionResult TunerRecordHidlTest::filterDataOutputTest() {
+ return filterDataOutputTestBase(mFilterTests);
+}
+
+void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
+ 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));
+ mFilterTests.setDemux(demux);
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+ if (filterConf.type.mainType == DemuxFilterMainType::IP) {
+ ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));
+ }
+ if (filterConf.statuses > 0) {
+ ASSERT_TRUE(mFilterTests.configureScramblingEvent(filterId, filterConf.statuses));
+ }
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ 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;
+ 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.getSharedAvMemoryHandle(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+ ASSERT_TRUE(mFilterTests.configAvFilterStreamType(filterConf.streamType, filterId));
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ // tune test
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ ASSERT_TRUE(filterDataOutputTest());
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
+ FrontendConfig frontendConf, DvrConfig dvrConf) {
+ uint32_t feId;
+ uint32_t demuxId;
+ sp<IDemux> demux;
+ uint64_t filterId;
+ sp<IFilter> filter;
+
+ 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));
+ mFilterTests.setDemux(demux);
+ mDvrTests.setDemux(demux);
+ mFrontendTests.setDvrTests(mDvrTests);
+ ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+ ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+ ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
+ 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));
+ filter = mFilterTests.getFilterById(filterId);
+ ASSERT_TRUE(filter != nullptr);
+ mDvrTests.startRecordOutputThread(dvrConf.settings.record());
+ ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
+ ASSERT_TRUE(mDvrTests.startDvrRecord());
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ mDvrTests.testRecordOutput();
+ ASSERT_TRUE(filterDataOutputTest());
+ mDvrTests.stopRecordThread();
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mDvrTests.stopDvrRecord());
+ ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
+ ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+ mDvrTests.closeDvrRecord();
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+TEST_P(TunerFilterHidlTest, StartFilterInDemux) {
+ description("Open and start a filter in Demux.");
+ // TODO use parameterized tests
+ configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerFilterHidlTest, ConfigIpFilterInDemuxWithCid) {
+ description("Open and configure an ip filter in Demux.");
+ // TODO use parameterized tests
+ configSingleFilterInDemuxTest(filterArray[IP_IP0], 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]);
+}
+
+TEST_P(TunerFrontendHidlTest, TuneFrontendWithFrontendSettingsExt1_1) {
+ description("Tune one Frontend with v1_1 extended setting and check Lock event");
+ mFrontendTests.tuneTest(frontendArray[DVBT]);
+}
+
+TEST_P(TunerFrontendHidlTest, BlindScanFrontendWithEndFrequency) {
+ description("Run an blind frontend scan with v1_1 extended setting and check lock scanMessage");
+ mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
+}
+
+TEST_P(TunerBroadcastHidlTest, MediaFilterWithSharedMemoryHandle) {
+ description("Test the Media Filter with shared memory handle");
+ mediaFilterUsingSharedMemoryTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerFrontendHidlTest, GetFrontendDtmbCaps) {
+ description("Test to query Dtmb frontend caps if exists");
+ mFrontendTests.getFrontendDtmbCapsTest();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerBroadcastHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerFrontendHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerFilterHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerRecordHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+} // namespace
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
new file mode 100644
index 0000000..773224e
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
@@ -0,0 +1,151 @@
+/*
+ * 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 "DemuxTests.h"
+#include "FrontendTests.h"
+
+namespace {
+
+void initConfiguration() {
+ initFrontendConfig();
+ initFrontendScanConfig();
+ initFilterConfig();
+ initDvrConfig();
+}
+
+static AssertionResult success() {
+ return ::testing::AssertionSuccess();
+}
+
+AssertionResult filterDataOutputTestBase(FilterTests tests) {
+ // Data Verify Module
+ std::map<uint64_t, sp<FilterCallback>>::iterator it;
+ std::map<uint64_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
+ for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
+ it->second->testFilterDataOutput();
+ }
+ return success();
+}
+
+class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = ITuner::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ initConfiguration();
+
+ mFrontendTests.setService(mService);
+ mDemuxTests.setService(mService);
+ mFilterTests.setService(mService);
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
+
+ sp<ITuner> mService;
+ FrontendTests mFrontendTests;
+ DemuxTests mDemuxTests;
+ FilterTests mFilterTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFilterHidlTest);
+
+class TunerRecordHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = ITuner::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ initConfiguration();
+
+ mFrontendTests.setService(mService);
+ mDemuxTests.setService(mService);
+ mFilterTests.setService(mService);
+ mDvrTests.setService(mService);
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
+ DvrConfig dvrConf);
+ AssertionResult filterDataOutputTest();
+
+ sp<ITuner> mService;
+ FrontendTests mFrontendTests;
+ DemuxTests mDemuxTests;
+ FilterTests mFilterTests;
+ DvrTests mDvrTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordHidlTest);
+
+class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = ITuner::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ initConfiguration();
+
+ mFrontendTests.setService(mService);
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<ITuner> mService;
+ FrontendTests mFrontendTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+
+class TunerBroadcastHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = ITuner::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ initConfiguration();
+
+ mFrontendTests.setService(mService);
+ mDemuxTests.setService(mService);
+ mFilterTests.setService(mService);
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<ITuner> mService;
+ FrontendTests mFrontendTests;
+ DemuxTests mDemuxTests;
+ FilterTests mFilterTests;
+
+ AssertionResult filterDataOutputTest();
+
+ void mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, FrontendConfig frontendConf);
+};
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
+} // namespace
\ No newline at end of file
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
new file mode 100644
index 0000000..76bf765
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -0,0 +1,284 @@
+/*
+ * 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 <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxIpAddress;
+using android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::FrontendType;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+using android::hardware::tv::tuner::V1_1::AudioStreamType;
+using android::hardware::tv::tuner::V1_1::AvStreamType;
+using android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
+using android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
+using android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
+using android::hardware::tv::tuner::V1_1::VideoStreamType;
+
+using namespace std;
+
+const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_4M = 0x400000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
+
+typedef enum {
+ TS_VIDEO0,
+ TS_VIDEO1,
+ TS_AUDIO0,
+ TS_AUDIO1,
+ TS_PES0,
+ TS_PCR0,
+ TS_SECTION0,
+ TS_TS0,
+ TS_RECORD0,
+ IP_IP0,
+ FILTER_MAX,
+} Filter;
+
+typedef enum {
+ DVBT,
+ DVBS,
+ FRONTEND_MAX,
+} Frontend;
+
+typedef enum {
+ SCAN_DVBT,
+ SCAN_MAX,
+} FrontendScan;
+
+typedef enum {
+ DVR_RECORD0,
+ DVR_PLAYBACK0,
+ DVR_MAX,
+} Dvr;
+
+struct FilterConfig {
+ uint32_t bufferSize;
+ DemuxFilterType type;
+ DemuxFilterSettings settings;
+ AvStreamType streamType;
+ uint32_t ipCid;
+ uint32_t statuses;
+
+ bool operator<(const FilterConfig& /*c*/) const { return false; }
+};
+
+struct FrontendConfig {
+ bool isSoftwareFe;
+ FrontendType type;
+ FrontendSettings settings;
+ FrontendSettingsExt1_1 settingsExt1_1;
+ vector<FrontendStatusTypeExt1_1> tuneStatusTypes;
+ vector<FrontendStatusExt1_1> expectTuneStatuses;
+};
+
+struct DvrConfig {
+ DvrType type;
+ uint32_t bufferSize;
+ DvrSettings settings;
+ string playbackInputFile;
+};
+
+static FrontendConfig frontendArray[FILTER_MAX];
+static FrontendConfig frontendScanArray[SCAN_MAX];
+static FilterConfig filterArray[FILTER_MAX];
+static DvrConfig dvrArray[DVR_MAX];
+
+/** Configuration array for the frontend tune test */
+inline void initFrontendConfig() {
+ FrontendDvbtSettings dvbtSettings{
+ .frequency = 578000,
+ .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
+ .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+ .constellation = FrontendDvbtConstellation::AUTO,
+ .hierarchy = FrontendDvbtHierarchy::AUTO,
+ .hpCoderate = FrontendDvbtCoderate::AUTO,
+ .lpCoderate = FrontendDvbtCoderate::AUTO,
+ .guardInterval = FrontendDvbtGuardInterval::AUTO,
+ .isHighPriority = true,
+ .standard = FrontendDvbtStandard::T,
+ };
+ frontendArray[DVBT].type = FrontendType::DVBT, frontendArray[DVBT].settings.dvbt(dvbtSettings);
+ vector<FrontendStatusTypeExt1_1> types;
+ types.push_back(FrontendStatusTypeExt1_1::UEC);
+ types.push_back(FrontendStatusTypeExt1_1::IS_MISO);
+ vector<FrontendStatusExt1_1> statuses;
+ FrontendStatusExt1_1 status;
+ status.uec(4);
+ statuses.push_back(status);
+ status.isMiso(true);
+ statuses.push_back(status);
+
+ frontendArray[DVBT].tuneStatusTypes = types;
+ frontendArray[DVBT].expectTuneStatuses = statuses;
+ frontendArray[DVBT].isSoftwareFe = true;
+ frontendArray[DVBT].settingsExt1_1.settingExt.dvbt({
+ .transmissionMode =
+ android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode::MODE_8K_E,
+ });
+ frontendArray[DVBS].type = FrontendType::DVBS;
+ frontendArray[DVBS].isSoftwareFe = true;
+};
+
+/** Configuration array for the frontend scan test */
+inline void initFrontendScanConfig() {
+ frontendScanArray[SCAN_DVBT].type = FrontendType::DVBT;
+ frontendScanArray[SCAN_DVBT].settings.dvbt({
+ .frequency = 578000,
+ .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K,
+ .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+ .constellation = FrontendDvbtConstellation::AUTO,
+ .hierarchy = FrontendDvbtHierarchy::AUTO,
+ .hpCoderate = FrontendDvbtCoderate::AUTO,
+ .lpCoderate = FrontendDvbtCoderate::AUTO,
+ .guardInterval = FrontendDvbtGuardInterval::AUTO,
+ .isHighPriority = true,
+ .standard = FrontendDvbtStandard::T,
+ });
+ frontendScanArray[SCAN_DVBT].settingsExt1_1.endFrequency = 800000;
+ frontendScanArray[SCAN_DVBT].settingsExt1_1.settingExt.dvbt({
+ .transmissionMode =
+ android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode::MODE_8K_E,
+ });
+};
+
+/** Configuration array for the filter test */
+inline void initFilterConfig() {
+ // TS VIDEO filter setting for default implementation testing
+ filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+ 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_VIDEO1].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+ filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_VIDEO1].settings.ts().tpid = 256;
+ filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false});
+ filterArray[TS_VIDEO1].streamType.video(VideoStreamType::MPEG1);
+ // TS AUDIO filter setting
+ filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+ filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_AUDIO0].settings.ts().tpid = 256;
+ filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
+ filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+ filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_AUDIO1].settings.ts().tpid = 257;
+ filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
+ filterArray[TS_VIDEO1].streamType.audio(AudioStreamType::MP3);
+ // TS PES filter setting
+ filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
+ filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_PES0].settings.ts().tpid = 256;
+ filterArray[TS_PES0].settings.ts().filterSettings.pesData({
+ .isRaw = false,
+ .streamId = 0xbd,
+ });
+ // TS PCR filter setting
+ filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR);
+ filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_PCR0].settings.ts().tpid = 256;
+ filterArray[TS_PCR0].settings.ts().filterSettings.noinit();
+ // TS filter setting
+ filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS);
+ filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_TS0].settings.ts().tpid = 256;
+ filterArray[TS_TS0].settings.ts().filterSettings.noinit();
+ // TS SECTION filter setting
+ filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+ filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M;
+ filterArray[TS_SECTION0].settings.ts().tpid = 256;
+ filterArray[TS_SECTION0].settings.ts().filterSettings.section({
+ .isRaw = false,
+ });
+ // TS RECORD filter setting
+ filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS;
+ filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+ filterArray[TS_RECORD0].settings.ts().tpid = 256;
+ filterArray[TS_RECORD0].settings.ts().filterSettings.record({
+ .scIndexType = DemuxRecordScIndexType::NONE,
+ });
+ // IP filter setting
+ filterArray[IP_IP0].type.mainType = DemuxFilterMainType::IP;
+ filterArray[IP_IP0].type.subType.ipFilterType(DemuxIpFilterType::IP);
+ uint8_t src[4] = {192, 168, 1, 1};
+ uint8_t dest[4] = {192, 168, 1, 2};
+ DemuxIpAddress ipAddress;
+ ipAddress.srcIpAddress.v4(src);
+ ipAddress.dstIpAddress.v4(dest);
+ DemuxIpFilterSettings ipSettings{
+ .ipAddr = ipAddress,
+ };
+ filterArray[IP_IP0].settings.ip(ipSettings);
+ filterArray[IP_IP0].ipCid = 1;
+};
+
+/** Configuration array for the dvr test */
+inline void initDvrConfig() {
+ RecordSettings recordSettings{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::TS,
+ .packetSize = 188,
+ };
+ dvrArray[DVR_RECORD0].type = DvrType::RECORD;
+ dvrArray[DVR_RECORD0].bufferSize = FMQ_SIZE_4M;
+ dvrArray[DVR_RECORD0].settings.record(recordSettings);
+ PlaybackSettings playbackSettings{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::TS,
+ .packetSize = 188,
+ };
+ dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
+ dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
+ dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
+ dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
+};
diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
index 5f901cd..0123d58 100644
--- a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
+++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
@@ -360,6 +360,7 @@
if (!supported) EXPECT_GE(successCount, 9);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, UsbHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp
new file mode 100644
index 0000000..c7f824d
--- /dev/null
+++ b/vibrator/bench/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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_benchmark {
+ name: "VibratorHalIntegrationBenchmark",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "benchmark.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.vibrator-cpp",
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vibrator@1.2",
+ "android.hardware.vibrator@1.3",
+ "libbinder",
+ "libhardware",
+ "libhidlbase",
+ "libutils",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp
new file mode 100644
index 0000000..e19dc6f
--- /dev/null
+++ b/vibrator/bench/benchmark.cpp
@@ -0,0 +1,577 @@
+/*
+ * 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.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
+
+using ::android::enum_range;
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::details::hidl_enum_values;
+using ::benchmark::Counter;
+using ::benchmark::Fixture;
+using ::benchmark::kMicrosecond;
+using ::benchmark::State;
+using ::benchmark::internal::Benchmark;
+using ::std::chrono::duration;
+using ::std::chrono::duration_cast;
+using ::std::chrono::high_resolution_clock;
+
+namespace Aidl = ::android::hardware::vibrator;
+namespace V1_0 = ::android::hardware::vibrator::V1_0;
+namespace V1_1 = ::android::hardware::vibrator::V1_1;
+namespace V1_2 = ::android::hardware::vibrator::V1_2;
+namespace V1_3 = ::android::hardware::vibrator::V1_3;
+
+template <typename I>
+class BaseBench : public Fixture {
+ public:
+ void TearDown(State& /*state*/) override {
+ if (!mVibrator) {
+ return;
+ }
+ mVibrator->off();
+ }
+
+ static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }
+
+ static void DefaultArgs(Benchmark* /*b*/) { /* none */
+ }
+
+ protected:
+ auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
+
+ protected:
+ sp<I> mVibrator;
+};
+
+template <typename I>
+class VibratorBench : public BaseBench<I> {
+ public:
+ void SetUp(State& /*state*/) override { this->mVibrator = I::getService(); }
+};
+
+enum class EmptyEnum : uint32_t;
+template <>
+inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
+
+template <typename T, typename U>
+std::set<T> difference(const hidl_enum_range<T>& t, const hidl_enum_range<U>& u) {
+ class Compare {
+ public:
+ bool operator()(const T& a, const U& b) { return a < static_cast<T>(b); }
+ bool operator()(const U& a, const T& b) { return static_cast<T>(a) < b; }
+ };
+ std::set<T> ret;
+
+ std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
+ std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
+
+ return ret;
+}
+
+template <typename I, typename E1, typename E2 = EmptyEnum>
+class VibratorEffectsBench : public VibratorBench<I> {
+ public:
+ using Effect = E1;
+ using EffectStrength = V1_0::EffectStrength;
+ using Status = V1_0::Status;
+
+ public:
+ static void DefaultArgs(Benchmark* b) {
+ b->ArgNames({"Effect", "Strength"});
+ for (const auto& effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
+ for (const auto& strength : hidl_enum_range<EffectStrength>()) {
+ b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+ }
+ }
+ }
+
+ void performBench(State* state, Return<void> (I::*performApi)(Effect, EffectStrength,
+ typename I::perform_cb)) {
+ auto effect = getEffect(*state);
+ auto strength = getStrength(*state);
+ bool supported = true;
+
+ (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+ if (status == Status::UNSUPPORTED_OPERATION) {
+ supported = false;
+ }
+ });
+
+ if (!supported) {
+ return;
+ }
+
+ for (auto _ : *state) {
+ state->ResumeTiming();
+ (*this->mVibrator.*performApi)(effect, strength,
+ [](Status /*status*/, uint32_t /*lengthMs*/) {});
+ state->PauseTiming();
+ this->mVibrator->off();
+ }
+ }
+
+ protected:
+ auto getEffect(const State& state) const {
+ return static_cast<Effect>(this->getOtherArg(state, 0));
+ }
+
+ auto getStrength(const State& state) const {
+ return static_cast<EffectStrength>(this->getOtherArg(state, 1));
+ }
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code) \
+ BENCHMARK_DEFINE_F(fixt, test) \
+ /* NOLINTNEXTLINE */ \
+ (State & state) { \
+ if (!mVibrator) { \
+ return; \
+ } \
+ \
+ code \
+ } \
+ BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
+
+using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
+ uint32_t ms = UINT32_MAX;
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->on(ms);
+ state.PauseTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
+ uint32_t ms = UINT32_MAX;
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ mVibrator->on(ms);
+ state.ResumeTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
+ for (auto _ : state) {
+ mVibrator->supportsAmplitudeControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
+ uint8_t amplitude = UINT8_MAX;
+
+ if (!mVibrator->supportsAmplitudeControl()) {
+ return;
+ }
+
+ mVibrator->on(UINT32_MAX);
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->off();
+});
+
+using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
+ { performBench(&state, &V1_0::IVibrator::perform); });
+
+using VibratorEffectsBench_V1_1 =
+ VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
+ { performBench(&state, &V1_1::IVibrator::perform_1_1); });
+
+using VibratorEffectsBench_V1_2 =
+ VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
+ { performBench(&state, &V1_2::IVibrator::perform_1_2); });
+
+using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
+ for (auto _ : state) {
+ mVibrator->supportsExternalControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
+ bool enable = true;
+
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->setExternalControl(enable);
+ state.PauseTiming();
+ mVibrator->setExternalControl(false);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ mVibrator->setExternalControl(true);
+
+ for (auto _ : state) {
+ mVibrator->supportsAmplitudeControl();
+ }
+
+ mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
+ uint8_t amplitude = UINT8_MAX;
+
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ mVibrator->setExternalControl(true);
+
+ if (!mVibrator->supportsAmplitudeControl()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->setExternalControl(false);
+});
+
+using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
+ { performBench(&state, &V1_3::IVibrator::perform_1_3); });
+
+class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
+ public:
+ void SetUp(State& /*state*/) override {
+ this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
+ }
+};
+
+class HalCallback : public Aidl::BnVibratorCallback {
+ public:
+ HalCallback() = default;
+ ~HalCallback() = default;
+
+ android::binder::Status onComplete() override { return android::binder::Status::ok(); }
+};
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, on, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+
+ int32_t ms = INT32_MAX;
+ auto cb = (capabilities & Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->on(ms, cb);
+ state.PauseTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, off, {
+ for (auto _ : state) {
+ state.PauseTiming();
+ mVibrator->on(INT32_MAX, nullptr);
+ state.ResumeTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
+ int32_t capabilities = 0;
+
+ for (auto _ : state) {
+ mVibrator->getCapabilities(&capabilities);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
+ return;
+ }
+
+ float amplitude = 1.0f;
+ mVibrator->on(INT32_MAX, nullptr);
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->off();
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->setExternalControl(true);
+ state.PauseTiming();
+ mVibrator->setExternalControl(false);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0 ||
+ (capabilities & Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) == 0) {
+ return;
+ }
+
+ float amplitude = 1.0f;
+ mVibrator->setExternalControl(true);
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
+ std::vector<Aidl::Effect> supportedEffects;
+
+ for (auto _ : state) {
+ mVibrator->getSupportedEffects(&supportedEffects);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
+ std::vector<Aidl::Effect> supportedEffects;
+
+ for (auto _ : state) {
+ mVibrator->getSupportedAlwaysOnEffects(&supportedEffects);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
+ std::vector<Aidl::CompositePrimitive> supportedPrimitives;
+
+ for (auto _ : state) {
+ mVibrator->getSupportedPrimitives(&supportedPrimitives);
+ }
+});
+
+class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
+ public:
+ static void DefaultArgs(Benchmark* b) {
+ b->ArgNames({"Effect", "Strength"});
+ for (const auto& effect : enum_range<Aidl::Effect>()) {
+ for (const auto& strength : enum_range<Aidl::EffectStrength>()) {
+ b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+ }
+ }
+ }
+
+ protected:
+ auto getEffect(const State& state) const {
+ return static_cast<Aidl::Effect>(this->getOtherArg(state, 0));
+ }
+
+ auto getStrength(const State& state) const {
+ return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
+ }
+};
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
+ return;
+ }
+
+ int32_t id = 1;
+ auto effect = getEffect(state);
+ auto strength = getStrength(state);
+
+ std::vector<Aidl::Effect> supported;
+ mVibrator->getSupportedAlwaysOnEffects(&supported);
+ if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->alwaysOnEnable(id, effect, strength);
+ state.PauseTiming();
+ mVibrator->alwaysOnDisable(id);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
+ return;
+ }
+
+ int32_t id = 1;
+ auto effect = getEffect(state);
+ auto strength = getStrength(state);
+
+ std::vector<Aidl::Effect> supported;
+ mVibrator->getSupportedAlwaysOnEffects(&supported);
+ if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ mVibrator->alwaysOnEnable(id, effect, strength);
+ state.ResumeTiming();
+ mVibrator->alwaysOnDisable(id);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, perform, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+
+ auto effect = getEffect(state);
+ auto strength = getStrength(state);
+ auto cb = (capabilities & Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback() : nullptr;
+ int32_t lengthMs = 0;
+
+ std::vector<Aidl::Effect> supported;
+ mVibrator->getSupportedEffects(&supported);
+ if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->perform(effect, strength, cb, &lengthMs);
+ state.PauseTiming();
+ mVibrator->off();
+ }
+});
+
+class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
+ public:
+ static void DefaultArgs(Benchmark* b) {
+ b->ArgNames({"Primitive"});
+ for (const auto& primitive : enum_range<Aidl::CompositePrimitive>()) {
+ b->Args({static_cast<long>(primitive)});
+ }
+ }
+
+ protected:
+ auto getPrimitive(const State& state) const {
+ return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
+ }
+};
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
+ int32_t ms = 0;
+
+ for (auto _ : state) {
+ mVibrator->getCompositionDelayMax(&ms);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
+ int32_t size = 0;
+
+ for (auto _ : state) {
+ mVibrator->getCompositionSizeMax(&size);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
+ return;
+ }
+
+ auto primitive = getPrimitive(state);
+ int32_t ms = 0;
+
+ std::vector<Aidl::CompositePrimitive> supported;
+ mVibrator->getSupportedPrimitives(&supported);
+ if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ mVibrator->getPrimitiveDuration(primitive, &ms);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, compose, {
+ int32_t capabilities = 0;
+ mVibrator->getCapabilities(&capabilities);
+ if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
+ return;
+ }
+
+ Aidl::CompositeEffect effect;
+ effect.primitive = getPrimitive(state);
+ effect.scale = 1.0f;
+ effect.delayMs = 0;
+
+ std::vector<Aidl::CompositePrimitive> supported;
+ mVibrator->getSupportedPrimitives(&supported);
+ if (std::find(supported.begin(), supported.end(), effect.primitive) == supported.end()) {
+ return;
+ }
+
+ auto cb = new HalCallback();
+ std::vector<Aidl::CompositeEffect> effects;
+ effects.push_back(effect);
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->compose(effects, cb);
+ state.PauseTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_MAIN();
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 14a8509..30512a9 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -30,6 +30,8 @@
],
static_libs: [
"android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.5",
"libwifi-system-iface",
],
}
@@ -49,6 +51,8 @@
"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: [
@@ -69,6 +73,11 @@
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: [
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index 3599b94..96b4501 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -94,6 +94,7 @@
EXPECT_GT(status_and_freqs.second.size(), 0u);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiApIfaceHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
index 5a2c6a7..2e6ad32 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -176,6 +176,7 @@
EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlApTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlApTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
index bb7a3a6..49a25e5 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -181,6 +181,7 @@
EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlNanTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlNanTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 53131ce..6c8f560 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -18,7 +18,6 @@
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -94,23 +93,7 @@
uint32_t configureChipForStaIfaceAndGetCapabilities() {
configureChipForIfaceType(IfaceType::STA, true);
- sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
- ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
- std::pair<WifiStatus, uint32_t> status_and_caps;
-
- if (chip_converted != nullptr) {
- // Call the newer HAL version
- status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
- } else {
- status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
- }
-
- if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
- EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status_and_caps.first.code);
- return 0;
- }
- return status_and_caps.second;
+ return getChipCapabilitiesLatest(wifi_chip_);
}
std::string getIfaceName(const sp<IWifiIface>& iface) {
@@ -552,6 +535,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index f3c82da..109d116 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -52,6 +52,7 @@
// The creation of a proxy object is tested as part of SetUp method.
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 5b11dd3..e6e61cf 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -16,6 +16,8 @@
#include <android/log.h>
+#include <android/hardware/wifi/1.3/IWifiChip.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
#include <wifi_system/interface_tool.h>
#include "wifi_hidl_call_util.h"
@@ -112,7 +114,7 @@
const auto& status_and_chip_ids = HIDL_INVOKE(wifi, getChipIds);
const auto& chip_ids = status_and_chip_ids.second;
if (status_and_chip_ids.first.code != WifiStatusCode::SUCCESS ||
- chip_ids.size() != 1) {
+ chip_ids.size() < 1) {
return nullptr;
}
const auto& status_and_chip = HIDL_INVOKE(wifi, getChip, chip_ids[0]);
@@ -208,3 +210,24 @@
ASSERT_NE(wifi, nullptr);
HIDL_INVOKE(wifi, stop);
}
+
+uint32_t getChipCapabilitiesLatest(const sp<IWifiChip>& wifi_chip) {
+ sp<::android::hardware::wifi::V1_5::IWifiChip> chip_converted15 =
+ ::android::hardware::wifi::V1_5::IWifiChip::castFrom(wifi_chip);
+ sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted13 =
+ ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip);
+ std::pair<WifiStatus, uint32_t> status_and_caps;
+
+ if (chip_converted15 != nullptr) {
+ // Call the newer HAL 1.5 version
+ status_and_caps = HIDL_INVOKE(chip_converted15, getCapabilities_1_5);
+ } else if (chip_converted13 != nullptr) {
+ // Call the newer HAL 1.3 version
+ status_and_caps = HIDL_INVOKE(chip_converted13, getCapabilities_1_3);
+ } else {
+ status_and_caps = HIDL_INVOKE(wifi_chip, getCapabilities);
+ }
+
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+ return status_and_caps.second;
+}
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index 5c78637..62c015c 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -51,3 +51,5 @@
android::hardware::wifi::V1_0::ChipModeId* configured_mode_id);
// Used to trigger IWifi.stop() at the end of every test.
void stopWifi(const std::string& instance_name);
+uint32_t getChipCapabilitiesLatest(
+ const android::sp<android::hardware::wifi::V1_0::IWifiChip>& wifi_chip);
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index 2b63ddc..a74987c 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -20,6 +20,7 @@
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiNanIface.h>
#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.5/IWifiNanIface.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -483,6 +484,16 @@
TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
uint16_t inputCmdId = 10;
callbackType = INVALID;
+ sp<::android::hardware::wifi::V1_5::IWifiNanIface> iface_converted =
+ ::android::hardware::wifi::V1_5::IWifiNanIface::castFrom(iwifiNanIface);
+ if (iface_converted != nullptr) {
+ ASSERT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId)
+ .code);
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
+
ASSERT_EQ(
WifiStatusCode::SUCCESS,
HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
@@ -509,6 +520,7 @@
EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiNanIfaceHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
index fd175f5..ce525f0 100644
--- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
@@ -54,6 +54,7 @@
EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get());
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiP2pIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiP2pIfaceHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index 3c9ed9e..b1a918d 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -76,6 +76,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiRttControllerHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index e311c84..08d81ff 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -298,6 +298,7 @@
HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiStaIfaceHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 7dc78e4..9893137 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -26,6 +26,8 @@
"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: [
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
index 4b94acb..874aa83 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -18,7 +18,6 @@
#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/1.1/IWifiChip.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -64,20 +63,7 @@
EXPECT_TRUE(configureChipToSupportIfaceType(
wifi_chip_, IfaceType::STA, &mode_id));
- sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
- ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
- std::pair<WifiStatus, uint32_t> status_and_caps;
-
- if (chip_converted != nullptr) {
- // Call the newer HAL version
- status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
- } else {
- status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
- }
-
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
- return status_and_caps.second;
+ return getChipCapabilitiesLatest(wifi_chip_);
}
sp<IWifiChip> wifi_chip_;
@@ -114,6 +100,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index 159ba94..21d8388 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -27,6 +27,8 @@
"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",
],
disable_framework: true,
@@ -47,6 +49,9 @@
"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: [
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index b04acad..6113fbf 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -111,20 +111,7 @@
EXPECT_TRUE(
configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA, &mode_id));
- sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
- ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
- std::pair<WifiStatus, uint32_t> status_and_caps;
-
- if (chip_converted != nullptr) {
- // Call the newer HAL version
- status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
- } else {
- status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
- }
-
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
- return status_and_caps.second;
+ return getChipCapabilitiesLatest(wifi_chip_);
}
sp<IWifiChip> wifi_chip_;
@@ -186,6 +173,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index bc392a9..f1c751e 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -559,6 +559,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiNanIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
index 066dcaa..cfa67d4 100644
--- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -117,6 +117,7 @@
EXPECT_EQ(status_and_data.second, data);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiStaIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 3568330..7ee69c9 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -27,8 +27,13 @@
"android.hardware.wifi@1.1",
"android.hardware.wifi@1.2",
"android.hardware.wifi@1.3",
- "libwifi-system-iface"
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "libwifi-system-iface",
],
disable_framework: true,
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
index e99b34a..f2c2bea 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -68,10 +68,7 @@
ChipModeId mode_id;
EXPECT_TRUE(configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA,
&mode_id));
- const auto& status_and_caps =
- HIDL_INVOKE(wifi_chip_, getCapabilities_1_3);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
- return status_and_caps.second;
+ return getChipCapabilitiesLatest(wifi_chip_);
}
sp<IWifiChip> wifi_chip_;
@@ -125,6 +122,7 @@
EXPECT_NE(0u, status_and_caps.second);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index 41d4ebb..22efe08 100644
--- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -104,6 +104,7 @@
HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiStaIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index 59a35e0..0051d27 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -52,6 +52,7 @@
"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: [
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
index aff0ef7..fc7dcd6 100644
--- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -77,6 +77,7 @@
EXPECT_NE(all_zero, status_and_mac.second);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiApIfaceHidlTest,
testing::ValuesIn(
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
index be5c3bd..e8a2d0a 100644
--- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -150,6 +150,7 @@
}
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
index f6a1147..3ac047d 100644
--- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -20,6 +20,7 @@
#include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
#include <android/hardware/wifi/1.4/IWifi.h>
#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+#include <android/hardware/wifi/1.5/IWifiNanIface.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -488,6 +489,17 @@
callbackType = INVALID;
::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
+
+ sp<::android::hardware::wifi::V1_5::IWifiNanIface> iface_converted =
+ ::android::hardware::wifi::V1_5::IWifiNanIface::castFrom(iwifiNanIface);
+ if (iface_converted != nullptr) {
+ ASSERT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp)
+ .code);
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
ASSERT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
nanEnableRequest, nanConfigRequestSupp)
@@ -509,6 +521,17 @@
nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
+
+ sp<::android::hardware::wifi::V1_5::IWifiNanIface> iface_converted =
+ ::android::hardware::wifi::V1_5::IWifiNanIface::castFrom(iwifiNanIface);
+ if (iface_converted != nullptr) {
+ ASSERT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp)
+ .code);
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
nanEnableRequest, nanConfigRequestSupp)
@@ -523,6 +546,17 @@
callbackType = INVALID;
::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
+
+ sp<::android::hardware::wifi::V1_5::IWifiNanIface> iface_converted =
+ ::android::hardware::wifi::V1_5::IWifiNanIface::castFrom(iwifiNanIface);
+ if (iface_converted != nullptr) {
+ ASSERT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp)
+ .code);
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
ASSERT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
nanConfigRequest, nanConfigRequestSupp)
@@ -543,12 +577,25 @@
::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
+
+ sp<::android::hardware::wifi::V1_5::IWifiNanIface> iface_converted =
+ ::android::hardware::wifi::V1_5::IWifiNanIface::castFrom(iwifiNanIface);
+ if (iface_converted != nullptr) {
+ ASSERT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp)
+ .code);
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
+
ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
nanConfigRequest, nanConfigRequestSupp)
.code);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiNanIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
index 3efb8f4..3977cdd 100644
--- a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -289,6 +289,7 @@
EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiRttControllerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp
new file mode 100644
index 0000000..ecb0a35
--- /dev/null
+++ b/wifi/1.5/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi@1.5",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IWifi.hal",
+ "IWifiChip.hal",
+ "IWifiNanIface.hal",
+ "IWifiNanIfaceEventCallback.hal",
+ ],
+ interfaces: [
+ "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.hidl.base@1.0",
+ ],
+ gen_java: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+}
diff --git a/wifi/1.5/IWifi.hal b/wifi/1.5/IWifi.hal
new file mode 100644
index 0000000..66d0a9c
--- /dev/null
+++ b/wifi/1.5/IWifi.hal
@@ -0,0 +1,27 @@
+/*
+ * 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::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.5::IWifiChip
+ */
+interface IWifi extends @1.4::IWifi {};
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
new file mode 100644
index 0000000..5243baf
--- /dev/null
+++ b/wifi/1.5/IWifiChip.hal
@@ -0,0 +1,51 @@
+/*
+ * 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.0::WifiStatus;
+import @1.0::IWifiIface;
+import @1.3::IWifiChip;
+import @1.4::IWifiChip;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.4::IWifiChip {
+ /**
+ * Capabilities exposed by this chip.
+ */
+ enum ChipCapabilityMask : @1.3::IWifiChip.ChipCapabilityMask {
+ /**
+ * chip can operate in the 60GHz band(WiGig chip)
+ */
+ WIGIG = 1 << 14,
+ };
+
+ /**
+ * Get the capabilities supported by this chip.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return capabilities Bitset of |ChipCapabilityMask| values.
+ */
+ getCapabilities_1_5()
+ generates (WifiStatus status, bitfield<ChipCapabilityMask> capabilities);
+};
diff --git a/wifi/1.5/IWifiNanIface.hal b/wifi/1.5/IWifiNanIface.hal
new file mode 100644
index 0000000..93257b5
--- /dev/null
+++ b/wifi/1.5/IWifiNanIface.hal
@@ -0,0 +1,113 @@
+/*
+ * 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.0::CommandIdShort;
+import @1.0::WifiStatus;
+import @1.4::IWifiNanIface;
+import @1.4::NanConfigRequest;
+import @1.4::NanEnableRequest;
+import IWifiNanIfaceEventCallback;
+import NanConfigRequestSupplemental;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.4::IWifiNanIface {
+ /**
+ * Enable NAN: configures and activates NAN clustering (does not start
+ * a discovery session or set up data-interfaces or data-paths). Use the
+ * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+ * NAN interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+ *
+ * Note: supersedes the @1.4::IWifiNanIface.enableRequest() method which is deprecated as of
+ * HAL version 1.5.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanEnableRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ enableRequest_1_5(CommandIdShort cmdId, NanEnableRequest msg1,
+ NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+ /**
+ * Configure NAN: configures an existing NAN functionality (i.e. assumes
+ * |IWifiNanIface.enableRequest| already submitted and succeeded).
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+ *
+ * Note: supersedes the @1.4::IWifiNanIface.configRequest() method which is deprecated as of
+ * HAL version 1.5.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanConfigRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ configRequest_1_5(CommandIdShort cmdId, NanConfigRequest msg1,
+ NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+ /**
+ * Requests notifications of significant events on this iface. Multiple calls
+ * to this must register multiple callbacks each of which must receive all
+ * events.
+ *
+ * Note: supersedes the @1.2::IWifiNanIface.registerEventCallback() method which is deprecated
+ * as of HAL version 1.5.
+ *
+ * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+ * object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ registerEventCallback_1_5(IWifiNanIfaceEventCallback callback)
+ generates (WifiStatus status);
+
+ /**
+ * Get NAN capabilities. Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyCapabilitiesResponse|.
+
+ * Note: supersedes the @1.0::IWifiNanIface.getCapabilitiesRequest() method which is deprecated
+ * as of HAL version 1.5.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ getCapabilitiesRequest_1_5(CommandIdShort cmdId) generates (WifiStatus status);
+};
\ No newline at end of file
diff --git a/wifi/1.5/IWifiNanIfaceEventCallback.hal b/wifi/1.5/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..867c03c
--- /dev/null
+++ b/wifi/1.5/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,44 @@
+/*
+ * 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.0::CommandIdShort;
+import @1.0::WifiNanStatus;
+import @1.2::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.2::IWifiNanIfaceEventCallback {
+ /**
+ * Asynchronous callback invoked in response to a capability request
+ * |IWifiNanIface.getCapabilitiesRequest|.
+ *
+ * Note: supersedes the @1.2::IWifiNanIfaceEventCallback.notifyCapabilitiesResponse() method
+ * which is deprecated as of HAL version 1.5.
+ *
+ * @param cmdId command Id corresponding to the original request.
+ * @param status WifiNanStatus of the operation. Possible status codes are:
+ * |NanStatusType.SUCCESS|
+ * @param capabilities Capability data.
+ */
+ oneway notifyCapabilitiesResponse_1_5(CommandIdShort id, WifiNanStatus status,
+ NanCapabilities capabilities);
+};
\ No newline at end of file
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.5/default/Android.mk
similarity index 93%
rename from wifi/1.4/default/Android.mk
rename to wifi/1.5/default/Android.mk
index 6be7dad..dc9e89b 100644
--- a/wifi/1.4/default/Android.mk
+++ b/wifi/1.5/default/Android.mk
@@ -51,6 +51,7 @@
wifi_feature_flags.cpp \
wifi_iface_util.cpp \
wifi_legacy_hal.cpp \
+ wifi_legacy_hal_factory.cpp \
wifi_legacy_hal_stubs.cpp \
wifi_mode_controller.cpp \
wifi_nan_iface.cpp \
@@ -67,11 +68,14 @@
libutils \
libwifi-hal \
libwifi-system-iface \
+ libxml2 \
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.4 \
+ android.hardware.wifi@1.5
+LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_STATIC_LIBRARY)
@@ -95,11 +99,13 @@
libutils \
libwifi-hal \
libwifi-system-iface \
+ libxml2 \
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.4 \
+ android.hardware.wifi@1.5
LOCAL_STATIC_LIBRARIES := \
android.hardware.wifi@1.0-service-lib
LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
@@ -127,11 +133,13 @@
libutils \
libwifi-hal \
libwifi-system-iface \
+ libxml2 \
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.4 \
+ android.hardware.wifi@1.5
LOCAL_STATIC_LIBRARIES := \
android.hardware.wifi@1.0-service-lib
LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
@@ -164,6 +172,7 @@
android.hardware.wifi@1.2 \
android.hardware.wifi@1.3 \
android.hardware.wifi@1.4 \
+ android.hardware.wifi@1.5 \
android.hardware.wifi@1.0-service-lib
LOCAL_SHARED_LIBRARIES := \
libbase \
diff --git a/wifi/1.4/default/OWNERS b/wifi/1.5/default/OWNERS
similarity index 100%
rename from wifi/1.4/default/OWNERS
rename to wifi/1.5/default/OWNERS
diff --git a/wifi/1.4/default/THREADING.README b/wifi/1.5/default/THREADING.README
similarity index 100%
rename from wifi/1.4/default/THREADING.README
rename to wifi/1.5/default/THREADING.README
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
similarity index 100%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
rename to wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
similarity index 88%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.5/default/android.hardware.wifi@1.0-service.rc
index 64a51b0..05706ef 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
@@ -4,6 +4,7 @@
interface android.hardware.wifi@1.2::IWifi default
interface android.hardware.wifi@1.3::IWifi default
interface android.hardware.wifi@1.4::IWifi default
+ interface android.hardware.wifi@1.5::IWifi default
class hal
capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
similarity index 89%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
rename to wifi/1.5/default/android.hardware.wifi@1.0-service.xml
index b5d25cd..88dd1e3 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.wifi</name>
<transport>hwbinder</transport>
- <version>1.4</version>
+ <version>1.5</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
diff --git a/wifi/1.4/default/hidl_callback_util.h b/wifi/1.5/default/hidl_callback_util.h
similarity index 98%
rename from wifi/1.4/default/hidl_callback_util.h
rename to wifi/1.5/default/hidl_callback_util.h
index fc601b8..d144658 100644
--- a/wifi/1.4/default/hidl_callback_util.h
+++ b/wifi/1.5/default/hidl_callback_util.h
@@ -52,7 +52,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_callback_util {
template <typename CallbackType>
@@ -117,7 +117,7 @@
} // namespace hidl_callback_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/hidl_return_util.h b/wifi/1.5/default/hidl_return_util.h
similarity index 98%
rename from wifi/1.4/default/hidl_return_util.h
rename to wifi/1.5/default/hidl_return_util.h
index 99c7092..4455185 100644
--- a/wifi/1.4/default/hidl_return_util.h
+++ b/wifi/1.5/default/hidl_return_util.h
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_return_util {
using namespace android::hardware::wifi::V1_0;
@@ -113,7 +113,7 @@
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
similarity index 94%
rename from wifi/1.4/default/hidl_struct_util.cpp
rename to wifi/1.5/default/hidl_struct_util.cpp
index fd1d5b1..578f3e2 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_struct_util {
@@ -69,9 +69,9 @@
return {};
}
-V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
- uint32_t feature) {
- using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+ uint64_t feature) {
+ using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
switch (feature) {
case WIFI_FEATURE_SET_TX_POWER_LIMIT:
return HidlChipCaps::SET_TX_POWER_LIMIT;
@@ -81,6 +81,8 @@
return HidlChipCaps::D2D_RTT;
case WIFI_FEATURE_D2AP_RTT:
return HidlChipCaps::D2AP_RTT;
+ case WIFI_FEATURE_INFRA_60G:
+ return HidlChipCaps::WIGIG;
case WIFI_FEATURE_SET_LATENCY_MODE:
return HidlChipCaps::SET_LATENCY_MODE;
case WIFI_FEATURE_P2P_RAND_MAC:
@@ -126,7 +128,7 @@
}
bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
uint32_t* hidl_caps) {
if (!hidl_caps) {
return false;
@@ -143,10 +145,11 @@
convertLegacyLoggerFeatureToHidlChipCapability(feature);
}
}
- std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+ std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
WIFI_FEATURE_USE_BODY_HEAD_SAR,
WIFI_FEATURE_D2D_RTT,
WIFI_FEATURE_D2AP_RTT,
+ WIFI_FEATURE_INFRA_60G,
WIFI_FEATURE_SET_LATENCY_MODE,
WIFI_FEATURE_P2P_RAND_MAC};
for (const auto feature : features) {
@@ -314,7 +317,7 @@
bool convertLegacyWifiMacInfoToHidl(
const legacy_hal::WifiMacInfo& legacy_mac_info,
- IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+ V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
if (!hidl_radio_mode_info) {
return false;
}
@@ -326,21 +329,21 @@
if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
} else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
} else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
} else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ;
} else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ;
} else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
} else {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
}
std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
@@ -355,14 +358,15 @@
bool convertLegacyWifiMacInfosToHidl(
const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
- std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>*
+ hidl_radio_mode_infos) {
if (!hidl_radio_mode_infos) {
return false;
}
*hidl_radio_mode_infos = {};
for (const auto& legacy_mac_info : legacy_mac_infos) {
- IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+ V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
&hidl_radio_mode_info)) {
return false;
@@ -1079,7 +1083,7 @@
}
bool convertHidlNanEnableRequestToLegacy(
- const NanEnableRequest& hidl_request,
+ const V1_4::NanEnableRequest& hidl_request,
legacy_hal::NanEnableRequest* legacy_request) {
if (!legacy_request) {
LOG(ERROR)
@@ -1275,8 +1279,8 @@
}
bool convertHidlNanEnableRequest_1_4ToLegacy(
- const NanEnableRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ const V1_4::NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanEnableRequest* legacy_request) {
if (!legacy_request) {
LOG(ERROR)
@@ -1291,14 +1295,60 @@
legacy_request->config_discovery_beacon_int = 1;
legacy_request->discovery_beacon_interval =
- hidl_request2.discoveryBeaconIntervalMs;
+ hidl_request2.V1_2.discoveryBeaconIntervalMs;
legacy_request->config_nss = 1;
- legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->nss = hidl_request2.V1_2.numberOfSpatialStreamsInDiscovery;
legacy_request->config_dw_early_termination = 1;
legacy_request->enable_dw_termination =
- hidl_request2.enableDiscoveryWindowEarlyTermination;
+ hidl_request2.V1_2.enableDiscoveryWindowEarlyTermination;
legacy_request->config_enable_ranging = 1;
- legacy_request->enable_ranging = hidl_request2.enableRanging;
+ legacy_request->enable_ranging = hidl_request2.V1_2.enableRanging;
+
+ return true;
+}
+
+bool convertHidlNanEnableRequest_1_5ToLegacy(
+ const V1_4::NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanEnableRequest_1_5ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanEnableRequest_1_4ToLegacy(hidl_request1, hidl_request2,
+ legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_enable_instant_mode = 1;
+ legacy_request->enable_instant_mode =
+ hidl_request2.enableInstantCommunicationMode;
+
+ return true;
+}
+
+bool convertHidlNanConfigRequest_1_5ToLegacy(
+ const V1_4::NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanConfigRequest_1_5ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanConfigRequest_1_4ToLegacy(hidl_request1, hidl_request2,
+ legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_enable_instant_mode = 1;
+ legacy_request->enable_instant_mode =
+ hidl_request2.enableInstantCommunicationMode;
return true;
}
@@ -1674,7 +1724,7 @@
}
bool convertHidlNanConfigRequestToLegacy(
- const NanConfigRequest& hidl_request,
+ const V1_4::NanConfigRequest& hidl_request,
legacy_hal::NanConfigRequest* legacy_request) {
if (!legacy_request) {
LOG(ERROR)
@@ -1789,8 +1839,8 @@
}
bool convertHidlNanConfigRequest_1_4ToLegacy(
- const NanConfigRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ const V1_4::NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanConfigRequest* legacy_request) {
if (!legacy_request) {
LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
@@ -1805,14 +1855,14 @@
legacy_request->config_discovery_beacon_int = 1;
legacy_request->discovery_beacon_interval =
- hidl_request2.discoveryBeaconIntervalMs;
+ hidl_request2.V1_2.discoveryBeaconIntervalMs;
legacy_request->config_nss = 1;
- legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->nss = hidl_request2.V1_2.numberOfSpatialStreamsInDiscovery;
legacy_request->config_dw_early_termination = 1;
legacy_request->enable_dw_termination =
- hidl_request2.enableDiscoveryWindowEarlyTermination;
+ hidl_request2.V1_2.enableDiscoveryWindowEarlyTermination;
legacy_request->config_enable_ranging = 1;
- legacy_request->enable_ranging = hidl_request2.enableRanging;
+ legacy_request->enable_ranging = hidl_request2.V1_2.enableRanging;
return true;
}
@@ -2019,27 +2069,31 @@
}
*hidl_response = {};
- hidl_response->maxConcurrentClusters =
+ hidl_response->V1_0.maxConcurrentClusters =
legacy_response.max_concurrent_nan_clusters;
- hidl_response->maxPublishes = legacy_response.max_publishes;
- hidl_response->maxSubscribes = legacy_response.max_subscribes;
- hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
- hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
- hidl_response->maxTotalMatchFilterLen =
+ hidl_response->V1_0.maxPublishes = legacy_response.max_publishes;
+ hidl_response->V1_0.maxSubscribes = legacy_response.max_subscribes;
+ hidl_response->V1_0.maxServiceNameLen =
+ legacy_response.max_service_name_len;
+ hidl_response->V1_0.maxMatchFilterLen =
+ legacy_response.max_match_filter_len;
+ hidl_response->V1_0.maxTotalMatchFilterLen =
legacy_response.max_total_match_filter_len;
- hidl_response->maxServiceSpecificInfoLen =
+ hidl_response->V1_0.maxServiceSpecificInfoLen =
legacy_response.max_service_specific_info_len;
- hidl_response->maxExtendedServiceSpecificInfoLen =
+ hidl_response->V1_0.maxExtendedServiceSpecificInfoLen =
legacy_response.max_sdea_service_specific_info_len;
- hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
- hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
- hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
- hidl_response->maxQueuedTransmitFollowupMsgs =
+ hidl_response->V1_0.maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+ hidl_response->V1_0.maxNdpSessions = legacy_response.max_ndp_sessions;
+ hidl_response->V1_0.maxAppInfoLen = legacy_response.max_app_info_len;
+ hidl_response->V1_0.maxQueuedTransmitFollowupMsgs =
legacy_response.max_queued_transmit_followup_msgs;
- hidl_response->maxSubscribeInterfaceAddresses =
+ hidl_response->V1_0.maxSubscribeInterfaceAddresses =
legacy_response.max_subscribe_address;
- hidl_response->supportedCipherSuites =
+ hidl_response->V1_0.supportedCipherSuites =
legacy_response.cipher_suites_supported;
+ hidl_response->instantCommunicationModeSupportFlag =
+ legacy_response.is_instant_mode_supported;
return true;
}
@@ -2298,30 +2352,32 @@
CHECK(false) << "Unknown legacy type: " << type;
}
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(
+ V1_4::RttPreamble type) {
switch (type) {
- case RttPreamble::LEGACY:
+ case V1_4::RttPreamble::LEGACY:
return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
- case RttPreamble::HT:
+ case V1_4::RttPreamble::HT:
return legacy_hal::WIFI_RTT_PREAMBLE_HT;
- case RttPreamble::VHT:
+ case V1_4::RttPreamble::VHT:
return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
- case RttPreamble::HE:
+ case V1_4::RttPreamble::HE:
return legacy_hal::WIFI_RTT_PREAMBLE_HE;
};
CHECK(false);
}
-RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+V1_4::RttPreamble convertLegacyRttPreambleToHidl(
+ legacy_hal::wifi_rtt_preamble type) {
switch (type) {
case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
- return RttPreamble::LEGACY;
+ return V1_4::RttPreamble::LEGACY;
case legacy_hal::WIFI_RTT_PREAMBLE_HT:
- return RttPreamble::HT;
+ return V1_4::RttPreamble::HT;
case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
- return RttPreamble::VHT;
+ return V1_4::RttPreamble::VHT;
case legacy_hal::WIFI_RTT_PREAMBLE_HE:
- return RttPreamble::HE;
+ return V1_4::RttPreamble::HE;
};
CHECK(false) << "Unknown legacy type: " << type;
}
@@ -2375,20 +2431,20 @@
CHECK(false);
}
-WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+V1_4::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
switch (preamble) {
case 0:
- return WifiRatePreamble::OFDM;
+ return V1_4::WifiRatePreamble::OFDM;
case 1:
- return WifiRatePreamble::CCK;
+ return V1_4::WifiRatePreamble::CCK;
case 2:
- return WifiRatePreamble::HT;
+ return V1_4::WifiRatePreamble::HT;
case 3:
- return WifiRatePreamble::VHT;
+ return V1_4::WifiRatePreamble::VHT;
case 4:
- return WifiRatePreamble::HE;
+ return V1_4::WifiRatePreamble::HE;
default:
- return WifiRatePreamble::RESERVED;
+ return V1_4::WifiRatePreamble::RESERVED;
};
CHECK(false) << "Unknown legacy preamble: " << preamble;
}
@@ -2478,7 +2534,7 @@
return true;
}
-bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+bool convertHidlRttConfigToLegacy(const V1_4::RttConfig& hidl_config,
legacy_hal::wifi_rtt_config* legacy_config) {
if (!legacy_config) {
return false;
@@ -2509,7 +2565,7 @@
}
bool convertHidlVectorOfRttConfigToLegacy(
- const std::vector<RttConfig>& hidl_configs,
+ const std::vector<V1_4::RttConfig>& hidl_configs,
std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
if (!legacy_configs) {
return false;
@@ -2566,7 +2622,7 @@
}
bool convertHidlRttResponderToLegacy(
- const RttResponder& hidl_responder,
+ const V1_4::RttResponder& hidl_responder,
legacy_hal::wifi_rtt_responder* legacy_responder) {
if (!legacy_responder) {
return false;
@@ -2583,7 +2639,7 @@
bool convertLegacyRttResponderToHidl(
const legacy_hal::wifi_rtt_responder& legacy_responder,
- RttResponder* hidl_responder) {
+ V1_4::RttResponder* hidl_responder) {
if (!hidl_responder) {
return false;
}
@@ -2599,7 +2655,7 @@
bool convertLegacyRttCapabilitiesToHidl(
const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- RttCapabilities* hidl_capabilities) {
+ V1_4::RttCapabilities* hidl_capabilities) {
if (!hidl_capabilities) {
return false;
}
@@ -2618,7 +2674,7 @@
legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
if (legacy_capabilities.preamble_support & flag) {
hidl_capabilities->preambleSupport |=
- static_cast<std::underlying_type<RttPreamble>::type>(
+ static_cast<std::underlying_type<V1_4::RttPreamble>::type>(
convertLegacyRttPreambleToHidl(flag));
}
}
@@ -2638,7 +2694,7 @@
}
bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
- WifiRateInfo* hidl_rate) {
+ V1_4::WifiRateInfo* hidl_rate) {
if (!hidl_rate) {
return false;
}
@@ -2654,7 +2710,8 @@
}
bool convertLegacyRttResultToHidl(
- const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+ const legacy_hal::wifi_rtt_result& legacy_result,
+ V1_4::RttResult* hidl_result) {
if (!hidl_result) {
return false;
}
@@ -2701,13 +2758,13 @@
bool convertLegacyVectorOfRttResultToHidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<RttResult>* hidl_results) {
+ std::vector<V1_4::RttResult>* hidl_results) {
if (!hidl_results) {
return false;
}
*hidl_results = {};
for (const auto legacy_result : legacy_results) {
- RttResult hidl_result;
+ V1_4::RttResult hidl_result;
if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
return false;
}
@@ -2732,7 +2789,7 @@
}
} // namespace hidl_struct_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
similarity index 86%
rename from wifi/1.4/default/hidl_struct_util.h
rename to wifi/1.5/default/hidl_struct_util.h
index 929f877..b0b1d22 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -22,10 +22,11 @@
#include <android/hardware/wifi/1.0/IWifiChip.h>
#include <android/hardware/wifi/1.0/types.h>
#include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
#include <android/hardware/wifi/1.3/types.h>
#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
#include <android/hardware/wifi/1.4/types.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
+#include <android/hardware/wifi/1.5/types.h>
#include "wifi_legacy_hal.h"
@@ -38,14 +39,14 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_struct_util {
using namespace android::hardware::wifi::V1_0;
// Chip conversion methods.
bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
uint32_t* hidl_caps);
bool convertLegacyDebugRingBufferStatusToHidl(
const legacy_hal::wifi_ring_buffer_status& legacy_status,
@@ -64,7 +65,8 @@
V1_2::IWifiChip::TxPowerScenario hidl_scenario);
bool convertLegacyWifiMacInfosToHidl(
const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
- std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>*
+ hidl_radio_mode_infos);
legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
IfaceType hidl_interface_type);
@@ -114,18 +116,26 @@
void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
size_t max_len, WifiNanStatus* wifiNanStatus);
bool convertHidlNanEnableRequestToLegacy(
- const NanEnableRequest& hidl_request,
+ const V1_4::NanEnableRequest& hidl_request,
legacy_hal::NanEnableRequest* legacy_request);
bool convertHidlNanConfigRequestToLegacy(
- const NanConfigRequest& hidl_request,
+ const V1_4::NanConfigRequest& hidl_request,
legacy_hal::NanConfigRequest* legacy_request);
bool convertHidlNanEnableRequest_1_4ToLegacy(
- const NanEnableRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ const V1_4::NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanEnableRequest* legacy_request);
bool convertHidlNanConfigRequest_1_4ToLegacy(
- const NanConfigRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ const V1_4::NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_5ToLegacy(
+ const V1_4::NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_5ToLegacy(
+ const V1_4::NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanConfigRequest* legacy_request);
bool convertHidlNanPublishRequestToLegacy(
const NanPublishRequest& hidl_request,
@@ -165,7 +175,7 @@
// RTT controller conversion methods.
bool convertHidlVectorOfRttConfigToLegacy(
- const std::vector<RttConfig>& hidl_configs,
+ const std::vector<V1_4::RttConfig>& hidl_configs,
std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
bool convertHidlRttLciInformationToLegacy(
const RttLciInformation& hidl_info,
@@ -174,23 +184,23 @@
const RttLcrInformation& hidl_info,
legacy_hal::wifi_lcr_information* legacy_info);
bool convertHidlRttResponderToLegacy(
- const RttResponder& hidl_responder,
+ const V1_4::RttResponder& hidl_responder,
legacy_hal::wifi_rtt_responder* legacy_responder);
bool convertHidlWifiChannelInfoToLegacy(
const WifiChannelInfo& hidl_info,
legacy_hal::wifi_channel_info* legacy_info);
bool convertLegacyRttResponderToHidl(
const legacy_hal::wifi_rtt_responder& legacy_responder,
- RttResponder* hidl_responder);
+ V1_4::RttResponder* hidl_responder);
bool convertLegacyRttCapabilitiesToHidl(
const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- RttCapabilities* hidl_capabilities);
+ V1_4::RttCapabilities* hidl_capabilities);
bool convertLegacyVectorOfRttResultToHidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<RttResult>* hidl_results);
+ std::vector<V1_4::RttResult>* hidl_results);
} // namespace hidl_struct_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.cpp b/wifi/1.5/default/hidl_sync_util.cpp
similarity index 96%
rename from wifi/1.4/default/hidl_sync_util.cpp
rename to wifi/1.5/default/hidl_sync_util.cpp
index 593a3bc..93eefe9 100644
--- a/wifi/1.4/default/hidl_sync_util.cpp
+++ b/wifi/1.5/default/hidl_sync_util.cpp
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_sync_util {
@@ -33,7 +33,7 @@
} // namespace hidl_sync_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.h b/wifi/1.5/default/hidl_sync_util.h
similarity index 96%
rename from wifi/1.4/default/hidl_sync_util.h
rename to wifi/1.5/default/hidl_sync_util.h
index 0244421..e706f4c 100644
--- a/wifi/1.4/default/hidl_sync_util.h
+++ b/wifi/1.5/default/hidl_sync_util.h
@@ -24,13 +24,13 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace hidl_sync_util {
std::unique_lock<std::recursive_mutex> acquireGlobalLock();
} // namespace hidl_sync_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/ringbuffer.cpp b/wifi/1.5/default/ringbuffer.cpp
similarity index 97%
rename from wifi/1.4/default/ringbuffer.cpp
rename to wifi/1.5/default/ringbuffer.cpp
index 0fe8ef4..26971ff 100644
--- a/wifi/1.4/default/ringbuffer.cpp
+++ b/wifi/1.5/default/ringbuffer.cpp
@@ -21,7 +21,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
@@ -48,7 +48,7 @@
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/ringbuffer.h b/wifi/1.5/default/ringbuffer.h
similarity index 97%
rename from wifi/1.4/default/ringbuffer.h
rename to wifi/1.5/default/ringbuffer.h
index ddce648..d8b87f2 100644
--- a/wifi/1.4/default/ringbuffer.h
+++ b/wifi/1.5/default/ringbuffer.h
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
/**
@@ -45,7 +45,7 @@
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/service.cpp b/wifi/1.5/default/service.cpp
similarity index 76%
rename from wifi/1.4/default/service.cpp
rename to wifi/1.5/default/service.cpp
index 3f7f609..8539a37 100644
--- a/wifi/1.4/default/service.cpp
+++ b/wifi/1.5/default/service.cpp
@@ -23,16 +23,19 @@
#include "wifi.h"
#include "wifi_feature_flags.h"
#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
#include "wifi_mode_controller.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_4::implementation::feature_flags::
+using android::hardware::wifi::V1_5::implementation::feature_flags::
WifiFeatureFlags;
-using android::hardware::wifi::V1_4::implementation::iface_util::WifiIfaceUtil;
-using android::hardware::wifi::V1_4::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_4::implementation::mode_controller::
+using android::hardware::wifi::V1_5::implementation::iface_util::WifiIfaceUtil;
+using android::hardware::wifi::V1_5::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_5::implementation::legacy_hal::
+ WifiLegacyHalFactory;
+using android::hardware::wifi::V1_5::implementation::mode_controller::
WifiModeController;
#ifdef LAZY_SERVICE
@@ -50,10 +53,13 @@
const auto iface_tool =
std::make_shared<android::wifi_system::InterfaceTool>();
+ const auto legacy_hal_factory =
+ std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
// Setup hwbinder service
- android::sp<android::hardware::wifi::V1_4::IWifi> service =
- new android::hardware::wifi::V1_4::implementation::Wifi(
- iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
+ android::sp<android::hardware::wifi::V1_5::IWifi> service =
+ new android::hardware::wifi::V1_5::implementation::Wifi(
+ iface_tool, legacy_hal_factory,
std::make_shared<WifiModeController>(),
std::make_shared<WifiIfaceUtil>(iface_tool),
std::make_shared<WifiFeatureFlags>());
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
similarity index 91%
rename from wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
rename to wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index b71d549..81eb14e 100644
--- a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -34,7 +34,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
@@ -55,14 +55,15 @@
legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
legacy_mac_infos.push_back(legacy_mac_info1);
- std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
+ hidl_radio_mode_infos;
ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
legacy_mac_infos, &hidl_radio_mode_infos));
ASSERT_EQ(1u, hidl_radio_mode_infos.size());
auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
- EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+ EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
@@ -89,20 +90,22 @@
legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
legacy_mac_infos.push_back(legacy_mac_info2);
- std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
+ hidl_radio_mode_infos;
ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
legacy_mac_infos, &hidl_radio_mode_infos));
ASSERT_EQ(2u, hidl_radio_mode_infos.size());
// Find mac info 1.
- const auto hidl_radio_mode_info1 = std::find_if(
- hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
- [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
- return x.radioId == legacy_mac_info1.wlan_mac_id;
- });
+ const auto hidl_radio_mode_info1 =
+ std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info1](
+ const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info1.wlan_mac_id;
+ });
ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
- EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+ EXPECT_EQ(V1_4::WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
@@ -110,13 +113,14 @@
hidl_iface_info1.channel);
// Find mac info 2.
- const auto hidl_radio_mode_info2 = std::find_if(
- hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
- [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
- return x.radioId == legacy_mac_info2.wlan_mac_id;
- });
+ const auto hidl_radio_mode_info2 =
+ std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info2](
+ const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info2.wlan_mac_id;
+ });
ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
- EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+ EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
@@ -288,7 +292,7 @@
hidle_caps);
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/main.cpp b/wifi/1.5/default/tests/main.cpp
similarity index 100%
rename from wifi/1.4/default/tests/main.cpp
rename to wifi/1.5/default/tests/main.cpp
diff --git a/wifi/1.4/default/tests/mock_interface_tool.cpp b/wifi/1.5/default/tests/mock_interface_tool.cpp
similarity index 100%
rename from wifi/1.4/default/tests/mock_interface_tool.cpp
rename to wifi/1.5/default/tests/mock_interface_tool.cpp
diff --git a/wifi/1.4/default/tests/mock_interface_tool.h b/wifi/1.5/default/tests/mock_interface_tool.h
similarity index 100%
rename from wifi/1.4/default/tests/mock_interface_tool.h
rename to wifi/1.5/default/tests/mock_interface_tool.h
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
rename to wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
index b1fa432..2f66ba1 100644
--- a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
@@ -21,7 +21,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace feature_flags {
@@ -29,7 +29,7 @@
} // namespace feature_flags
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.h b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
similarity index 89%
rename from wifi/1.4/default/tests/mock_wifi_feature_flags.h
rename to wifi/1.5/default/tests/mock_wifi_feature_flags.h
index 72d2304..c3877ed 100644
--- a/wifi/1.4/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
@@ -25,7 +25,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace feature_flags {
@@ -33,13 +33,14 @@
public:
MockWifiFeatureFlags();
- MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+ MOCK_METHOD1(getChipModes,
+ std::vector<V1_0::IWifiChip::ChipMode>(bool is_primary));
MOCK_METHOD0(isApMacRandomizationDisabled, bool());
};
} // namespace feature_flags
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp b/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_iface_util.cpp
rename to wifi/1.5/default/tests/mock_wifi_iface_util.cpp
index 0968569..fe6e9e2 100644
--- a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace iface_util {
@@ -33,7 +33,7 @@
: WifiIfaceUtil(iface_tool) {}
} // namespace iface_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.h b/wifi/1.5/default/tests/mock_wifi_iface_util.h
similarity index 97%
rename from wifi/1.4/default/tests/mock_wifi_iface_util.h
rename to wifi/1.5/default/tests/mock_wifi_iface_util.h
index 8d77a7d..a719fec 100644
--- a/wifi/1.4/default/tests/mock_wifi_iface_util.h
+++ b/wifi/1.5/default/tests/mock_wifi_iface_util.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace iface_util {
@@ -45,7 +45,7 @@
};
} // namespace iface_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
similarity index 84%
rename from wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
rename to wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
index 8d65c59..d13c556 100644
--- a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
@@ -24,16 +24,17 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace legacy_hal {
MockWifiLegacyHal::MockWifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : WifiLegacyHal(iface_tool) {}
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary)
+ : WifiLegacyHal(iface_tool, fn, is_primary) {}
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_legacy_hal.h
rename to wifi/1.5/default/tests/mock_wifi_legacy_hal.h
index 3bb7b54..9ab2fd5 100644
--- a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
@@ -24,14 +24,15 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace legacy_hal {
class MockWifiLegacyHal : public WifiLegacyHal {
public:
MockWifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary);
MOCK_METHOD0(initialize, wifi_error());
MOCK_METHOD0(start, wifi_error());
MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
@@ -64,7 +65,7 @@
};
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
rename to wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
index ee09029..e7ab22a 100644
--- a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
@@ -24,14 +24,14 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace mode_controller {
MockWifiModeController::MockWifiModeController() : WifiModeController() {}
} // namespace mode_controller
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.h b/wifi/1.5/default/tests/mock_wifi_mode_controller.h
similarity index 97%
rename from wifi/1.4/default/tests/mock_wifi_mode_controller.h
rename to wifi/1.5/default/tests/mock_wifi_mode_controller.h
index 1e1ce69..b9151f1 100644
--- a/wifi/1.4/default/tests/mock_wifi_mode_controller.h
+++ b/wifi/1.5/default/tests/mock_wifi_mode_controller.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace mode_controller {
@@ -38,7 +38,7 @@
};
} // namespace mode_controller
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
similarity index 98%
rename from wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
rename to wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
index a65347f..6fd34ee 100644
--- a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
+++ b/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
class RingbufferTest : public Test {
@@ -91,7 +91,7 @@
EXPECT_EQ(input, buffer_.getData().front());
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/runtests.sh b/wifi/1.5/default/tests/runtests.sh
similarity index 100%
rename from wifi/1.4/default/tests/runtests.sh
rename to wifi/1.5/default/tests/runtests.sh
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
similarity index 95%
rename from wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
index 323d2ff..d99bfbd 100644
--- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
@@ -41,7 +41,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
class WifiChipTest : public Test {
@@ -59,7 +59,7 @@
{feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -76,7 +76,7 @@
{feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -89,7 +89,7 @@
{feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -103,7 +103,7 @@
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -116,7 +116,7 @@
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -129,7 +129,7 @@
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
+ EXPECT_CALL(*feature_flags_, getChipModes(true))
.WillRepeatedly(testing::Return(modes));
}
@@ -173,18 +173,18 @@
std::string createIface(const IfaceType& type) {
std::string iface_name;
if (type == IfaceType::AP) {
- chip_->createApIface([&iface_name](
- const WifiStatus& status,
- const sp<V1_0::IWifiApIface>& iface) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(iface.get(), nullptr);
- iface->getName([&iface_name](const WifiStatus& status,
- const hidl_string& name) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- iface_name = name.c_str();
- });
- }
- });
+ chip_->createApIface(
+ [&iface_name](const WifiStatus& status,
+ const sp<V1_0::IWifiApIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
} else if (type == IfaceType::NAN) {
chip_->createNanIface(
[&iface_name](
@@ -263,12 +263,16 @@
return success;
}
+ static void subsystemRestartHandler(const std::string& /*error*/) {}
+
sp<WifiChip> chip_;
ChipId chip_id_ = kFakeChipId;
+ legacy_hal::wifi_hal_fn fake_func_table_;
std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
new NiceMock<wifi_system::MockInterfaceTool>};
std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+ fake_func_table_, true)};
std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
@@ -278,8 +282,9 @@
public:
void SetUp() override {
- chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
- iface_util_, feature_flags_);
+ chip_ =
+ new WifiChip(chip_id_, true, legacy_hal_, mode_controller_,
+ iface_util_, feature_flags_, subsystemRestartHandler);
EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
.WillRepeatedly(testing::Return(true));
@@ -894,7 +899,7 @@
ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
similarity index 98%
rename from wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
index 03394bc..d70e42f 100644
--- a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
@@ -41,7 +41,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace iface_util {
class WifiIfaceUtilTest : public Test {
@@ -90,7 +90,7 @@
}
} // namespace iface_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
similarity index 93%
rename from wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
index 70424db..52f0c2b 100644
--- a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -38,10 +38,9 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
-using android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback;
using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
bool CaptureIfaceEventHandlers(
@@ -56,9 +55,10 @@
public:
MockNanIfaceEventCallback() = default;
- MOCK_METHOD3(notifyCapabilitiesResponse,
- Return<void>(uint16_t, const WifiNanStatus&,
- const NanCapabilities&));
+ MOCK_METHOD3(
+ notifyCapabilitiesResponse,
+ Return<void>(uint16_t, const WifiNanStatus&,
+ const android::hardware::wifi::V1_0::NanCapabilities&));
MOCK_METHOD2(notifyEnableResponse,
Return<void>(uint16_t, const WifiNanStatus&));
MOCK_METHOD2(notifyConfigResponse,
@@ -108,14 +108,19 @@
Return<void>(const NanDataPathConfirmInd&));
MOCK_METHOD1(eventDataPathScheduleUpdate,
Return<void>(const NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
+ Return<void>(uint16_t, const WifiNanStatus&,
+ const NanCapabilities&));
};
class WifiNanIfaceTest : public Test {
protected:
+ legacy_hal::wifi_hal_fn fake_func_table_;
std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
new NiceMock<wifi_system::MockInterfaceTool>};
std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+ fake_func_table_, true)};
std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
};
@@ -151,7 +156,7 @@
captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.5/default/wifi.cpp
similarity index 64%
rename from wifi/1.4/default/wifi.cpp
rename to wifi/1.5/default/wifi.cpp
index 9c6b0f0..17db51d 100644
--- a/wifi/1.4/default/wifi.cpp
+++ b/wifi/1.5/default/wifi.cpp
@@ -21,26 +21,26 @@
#include "wifi_status_util.h"
namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+// Starting Chip ID, will be assigned to primary chip
+static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
} // namespace
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
using hidl_return_util::validateAndCallWithLock;
Wifi::Wifi(
const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
- const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
: iface_tool_(iface_tool),
- legacy_hal_(legacy_hal),
+ legacy_hal_factory_(legacy_hal_factory),
mode_controller_(mode_controller),
iface_util_(iface_util),
feature_flags_(feature_flags),
@@ -84,10 +84,16 @@
Return<void> Wifi::debug(const hidl_handle& handle,
const hidl_vec<hidl_string>&) {
LOG(INFO) << "-----------Debug is called----------------";
- if (!chip_.get()) {
+ if (chips_.size() == 0) {
return Void();
}
- return chip_->debug(handle, {});
+
+ for (sp<WifiChip> chip : chips_) {
+ if (!chip.get()) continue;
+
+ chip->debug(handle, {});
+ }
+ return Void();
}
WifiStatus Wifi::registerEventCallbackInternal(
@@ -107,9 +113,26 @@
}
WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
if (wifi_status.code == WifiStatusCode::SUCCESS) {
+ // Register the callback for subsystem restart
+ const auto& on_subsystem_restart_callback =
+ [this](const std::string& error) {
+ WifiStatus wifi_status =
+ createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onFailure(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onFailure callback";
+ }
+ }
+ };
+
// Create the chip instance once the HAL is started.
- chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
- iface_util_, feature_flags_);
+ android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
+ for (auto& hal : legacy_hals_) {
+ chips_.push_back(new WifiChip(
+ chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+ iface_util_, feature_flags_, on_subsystem_restart_callback));
+ chipId++;
+ }
run_state_ = RunState::STARTED;
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onStart().isOk()) {
@@ -140,10 +163,13 @@
}
// Clear the chip object and its child objects since the HAL is now
// stopped.
- if (chip_.get()) {
- chip_->invalidate();
- chip_.clear();
+ for (auto& chip : chips_) {
+ if (chip.get()) {
+ chip->invalidate();
+ chip.clear();
+ }
}
+ chips_.clear();
WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
if (wifi_status.code == WifiStatusCode::SUCCESS) {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -167,20 +193,23 @@
std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
std::vector<ChipId> chip_ids;
- if (chip_.get()) {
- chip_ids.emplace_back(kChipId);
+
+ for (auto& chip : chips_) {
+ ChipId chip_id = getChipIdFromWifiChip(chip);
+ if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
}
return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
}
-std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
- if (!chip_.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(
+ ChipId chip_id) {
+ for (auto& chip : chips_) {
+ ChipId cand_id = getChipIdFromWifiChip(chip);
+ if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
+ return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
}
- if (chip_id != kChipId) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
}
WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
@@ -188,23 +217,46 @@
LOG(ERROR) << "Failed to initialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
- legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to initialize legacy HAL: "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
+
+ legacy_hals_ = legacy_hal_factory_->getHals();
+ if (legacy_hals_.empty())
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ int index = 0; // for failure log
+ for (auto& hal : legacy_hals_) {
+ legacy_hal::wifi_error legacy_status = hal->initialize();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ // Currently WifiLegacyHal::initialize does not allocate extra mem,
+ // only initializes the function table. If this changes, need to
+ // implement WifiLegacyHal::deinitialize and deinitalize the
+ // HALs already initialized
+ LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+ << " error: " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ index++;
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+ legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+ int index = 0;
+
run_state_ = RunState::STOPPING;
- legacy_hal::wifi_error legacy_status =
- legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+ for (auto& hal : legacy_hals_) {
+ legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+ if (tmp != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+ << " error: " << legacyErrorToString(legacy_status);
+ legacy_status = tmp;
+ }
+ index++;
+ }
+ run_state_ = RunState::STOPPED;
+
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to stop legacy HAL: "
- << legacyErrorToString(legacy_status);
+ LOG(ERROR) << "One or more legacy HALs failed to stop";
return createWifiStatusFromLegacyError(legacy_status);
}
if (!mode_controller_->deinitialize()) {
@@ -213,8 +265,21 @@
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
+
+ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
+ ChipId chip_id = UINT32_MAX;
+ if (chip.get()) {
+ chip->getId([&](WifiStatus status, uint32_t id) {
+ if (status.code == WifiStatusCode::SUCCESS) {
+ chip_id = id;
+ }
+ });
+ }
+
+ return chip_id;
+}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi.h b/wifi/1.5/default/wifi.h
similarity index 84%
rename from wifi/1.4/default/wifi.h
rename to wifi/1.5/default/wifi.h
index 087d6f7..9f5a1b0 100644
--- a/wifi/1.4/default/wifi.h
+++ b/wifi/1.5/default/wifi.h
@@ -20,28 +20,30 @@
#include <functional>
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifi.h>
#include <utils/Looper.h>
#include "hidl_callback_util.h"
#include "wifi_chip.h"
#include "wifi_feature_flags.h"
#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
#include "wifi_mode_controller.h"
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
/**
* Root HIDL interface object used to control the Wifi HAL.
*/
-class Wifi : public V1_4::IWifi {
+class Wifi : public V1_5::IWifi {
public:
Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
- const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::shared_ptr<legacy_hal::WifiLegacyHalFactory>
+ legacy_hal_factory,
const std::shared_ptr<mode_controller::WifiModeController>
mode_controller,
const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
@@ -70,21 +72,23 @@
WifiStatus startInternal();
WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
- std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
+ std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
WifiStatus initializeModeControllerAndLegacyHal();
WifiStatus stopLegacyHalAndDeinitializeModeController(
std::unique_lock<std::recursive_mutex>* lock);
+ ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
// Instance is created in this root level |IWifi| HIDL interface object
// and shared with all the child HIDL interface objects.
std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
- std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+ std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
RunState run_state_;
- sp<WifiChip> chip_;
+ std::vector<sp<WifiChip>> chips_;
hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
event_cb_handler_;
@@ -92,7 +96,7 @@
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.5/default/wifi_ap_iface.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_ap_iface.cpp
rename to wifi/1.5/default/wifi_ap_iface.cpp
index 8777a4c..04e382a 100644
--- a/wifi/1.4/default/wifi_ap_iface.cpp
+++ b/wifi/1.5/default/wifi_ap_iface.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -131,7 +131,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.5/default/wifi_ap_iface.h
similarity index 98%
rename from wifi/1.4/default/wifi_ap_iface.h
rename to wifi/1.5/default/wifi_ap_iface.h
index bf16d5e..48b444a 100644
--- a/wifi/1.4/default/wifi_ap_iface.h
+++ b/wifi/1.5/default/wifi_ap_iface.h
@@ -26,7 +26,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
@@ -76,7 +76,7 @@
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
similarity index 94%
rename from wifi/1.4/default/wifi_chip.cpp
rename to wifi/1.5/default/wifi_chip.cpp
index 8cba464..ebff722 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -281,9 +281,6 @@
continue;
}
std::string cur_file_name(dp->d_name);
- // string.size() does not include the null terminator. The cpio FreeBSD
- // file header expects the null character to be included in the length.
- const size_t file_name_len = cur_file_name.size() + 1;
struct stat st;
const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
if (stat(cur_file_path.c_str(), &st) == -1) {
@@ -297,8 +294,15 @@
n_error++;
continue;
}
+ std::string file_name_with_last_modified_time =
+ cur_file_name + "-" + std::to_string(st.st_mtime);
+ // string.size() does not include the null terminator. The cpio FreeBSD
+ // file header expects the null character to be included in the length.
+ const size_t file_name_len =
+ file_name_with_last_modified_time.size() + 1;
unique_fd file_auto_closer(fd_read);
- if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
+ if (!cpioWriteHeader(out_fd, st,
+ file_name_with_last_modified_time.c_str(),
file_name_len)) {
return ++n_error;
}
@@ -326,24 +330,27 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
using hidl_return_util::validateAndCallWithLock;
WifiChip::WifiChip(
- ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ ChipId chip_id, bool is_primary,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+ const std::function<void(const std::string&)>& handler)
: chip_id_(chip_id),
legacy_hal_(legacy_hal),
mode_controller_(mode_controller),
iface_util_(iface_util),
is_valid_(true),
current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
- modes_(feature_flags.lock()->getChipModes()),
- debug_ring_buffer_cb_registered_(false) {
+ modes_(feature_flags.lock()->getChipModes(is_primary)),
+ debug_ring_buffer_cb_registered_(false),
+ subsystemCallbackHandler_(handler) {
setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
}
@@ -360,7 +367,7 @@
bool WifiChip::isValid() { return is_valid_; }
-std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
return event_cb_handler_.getCallbacks();
}
@@ -621,6 +628,13 @@
hidl_status_cb);
}
+Return<void> WifiChip::getCapabilities_1_5(
+ getCapabilities_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal_1_5,
+ hidl_status_cb);
+}
+
Return<void> WifiChip::debug(const hidl_handle& handle,
const hidl_vec<hidl_string>&) {
if (handle != nullptr && handle->numFds >= 1) {
@@ -657,7 +671,7 @@
}
Return<void> WifiChip::registerEventCallback_1_4(
- const sp<IWifiChipEventCallback>& event_callback,
+ const sp<V1_4::IWifiChipEventCallback>& event_callback,
registerEventCallback_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::registerEventCallbackInternal_1_4,
@@ -679,9 +693,10 @@
void WifiChip::invalidateAndRemoveDependencies(
const std::string& removed_iface_name) {
- for (const auto& nan_iface : nan_ifaces_) {
+ for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+ auto nan_iface = *it;
if (nan_iface->getName() == removed_iface_name) {
- invalidateAndClear(nan_ifaces_, nan_iface);
+ nan_iface->invalidate();
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback
->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
@@ -689,11 +704,19 @@
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
+ it = nan_ifaces_.erase(it);
+ } else {
+ ++it;
}
}
- for (const auto& rtt : rtt_controllers_) {
+
+ for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+ auto rtt = *it;
if (rtt->getIfaceName() == removed_iface_name) {
- invalidateAndClear(rtt_controllers_, rtt);
+ rtt->invalidate();
+ it = rtt_controllers_.erase(it);
+ } else {
+ ++it;
}
}
}
@@ -713,7 +736,7 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
}
-std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
+std::pair<WifiStatus, std::vector<V1_4::IWifiChip::ChipMode>>
WifiChip::getAvailableModesInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
}
@@ -746,6 +769,10 @@
current_mode_id_ = mode_id;
LOG(INFO) << "Configured chip in mode " << mode_id;
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+ legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(
+ subsystemCallbackHandler_);
+
return status;
}
@@ -757,9 +784,9 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
}
-std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo>
WifiChip::requestChipDebugInfoInternal() {
- IWifiChip::ChipDebugInfo result;
+ V1_4::IWifiChip::ChipDebugInfo result;
legacy_hal::wifi_error legacy_status;
std::string driver_desc;
const auto ifname = getFirstActiveWlanIfaceName();
@@ -888,7 +915,8 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>>
+WifiChip::createNanIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
@@ -919,7 +947,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
}
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(nan_ifaces_, ifname);
if (!iface.get()) {
@@ -1216,8 +1244,13 @@
}
std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+ // Deprecated support for this callback.
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
legacy_hal::wifi_error legacy_status;
- uint32_t legacy_feature_set;
+ uint64_t legacy_feature_set;
uint32_t legacy_logger_feature_set;
const auto ifname = getFirstActiveWlanIfaceName();
std::tie(legacy_status, legacy_feature_set) =
@@ -1239,7 +1272,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
}
-std::pair<WifiStatus, sp<IWifiRttController>>
+std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
WifiChip::createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface) {
if (sta_ifaces_.size() == 0 &&
!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
@@ -1255,7 +1288,7 @@
}
WifiStatus WifiChip::registerEventCallbackInternal_1_4(
- const sp<IWifiChipEventCallback>& event_callback) {
+ const sp<V1_4::IWifiChipEventCallback>& event_callback) {
if (!event_cb_handler_.addCallback(event_callback)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
@@ -1303,7 +1336,7 @@
LOG(ERROR) << "Failed to register radio mode change callback";
}
// Extract and save the version information into property.
- std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
+ std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
version_info = WifiChip::requestChipDebugInfoInternal();
if (WifiStatusCode::SUCCESS == version_info.first.code) {
property_set("vendor.wlan.firmware.version",
@@ -1369,7 +1402,7 @@
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
- std::vector<IWifiChipEventCallback::RadioModeInfo>
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
hidl_radio_mode_infos;
if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
mac_infos, &hidl_radio_mode_infos)) {
@@ -1390,7 +1423,7 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-std::vector<IWifiChip::ChipIfaceCombination>
+std::vector<V1_4::IWifiChip::ChipIfaceCombination>
WifiChip::getCurrentModeIfaceCombinations() {
if (!isValidModeId(current_mode_id_)) {
LOG(ERROR) << "Chip not configured in a mode yet";
@@ -1421,7 +1454,7 @@
// of ifaces of each type in the combination.
// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
- const IWifiChip::ChipIfaceCombination& combination) {
+ const V1_4::IWifiChip::ChipIfaceCombination& combination) {
uint32_t num_expanded_combos = 1;
for (const auto& limit : combination.limits) {
for (uint32_t i = 0; i < limit.maxIfaces; i++) {
@@ -1583,15 +1616,16 @@
// This could happen if the chip call is made before any STA/AP
// iface is created. Default to wlan0 for such cases.
LOG(WARNING) << "No active wlan interfaces in use! Using default";
- return getWlanIfaceName(0);
+ return getWlanIfaceNameWithType(IfaceType::STA, 0);
}
// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
// not already in use.
// Note: This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type,
+ uint32_t start_idx) {
for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
- const auto ifname = getWlanIfaceName(idx);
+ const auto ifname = getWlanIfaceNameWithType(type, idx);
if (findUsingName(ap_ifaces_, ifname)) continue;
if (findUsingName(sta_ifaces_, ifname)) continue;
return ifname;
@@ -1609,7 +1643,8 @@
if (!ifname.empty()) {
return ifname;
}
- return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
+ return allocateApOrStaIfaceName(IfaceType::AP,
+ (isStaApConcurrencyAllowedInCurrentMode() &&
!isDualApAllowedInCurrentMode())
? 1
: 0);
@@ -1618,7 +1653,7 @@
// STA iface names start with idx 0.
// Primary STA iface will always be 0.
std::string WifiChip::allocateStaIfaceName() {
- return allocateApOrStaIfaceName(0);
+ return allocateApOrStaIfaceName(IfaceType::STA, 0);
}
bool WifiChip::writeRingbufferFilesInternal() {
@@ -1654,8 +1689,19 @@
return true;
}
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+ std::string ifname;
+
+ // let the legacy hal override the interface name
+ legacy_hal::wifi_error err =
+ legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+ if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+ return getWlanIfaceName(idx);
+}
+
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
similarity index 88%
rename from wifi/1.4/default/wifi_chip.h
rename to wifi/1.5/default/wifi_chip.h
index 98e18bb..8cc0452 100644
--- a/wifi/1.4/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -22,8 +22,8 @@
#include <mutex>
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifiChip.h>
#include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
#include "hidl_callback_util.h"
#include "ringbuffer.h"
@@ -39,7 +39,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
@@ -48,15 +48,16 @@
* Since there is only a single chip instance used today, there is no
* identifying handle information stored here.
*/
-class WifiChip : public V1_4::IWifiChip {
+class WifiChip : public V1_5::IWifiChip {
public:
- WifiChip(
- ChipId chip_id,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<mode_controller::WifiModeController>
- mode_controller,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+ WifiChip(ChipId chip_id, bool is_primary,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<mode_controller::WifiModeController>
+ mode_controller,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+ const std::function<void(const std::string&)>&
+ subsystemCallbackHandler);
// HIDL does not provide a built-in mechanism to let the server invalidate
// a HIDL interface object after creation. If any client process holds onto
// a reference to the object in their context, any method calls on that
@@ -72,7 +73,7 @@
// marked valid before processing them.
void invalidate();
bool isValid();
- std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+ std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
// HIDL methods exposed.
Return<void> getId(getId_cb hidl_status_cb) override;
@@ -152,13 +153,15 @@
selectTxPowerScenario_cb hidl_status_cb) override;
Return<void> getCapabilities_1_3(
getCapabilities_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_5(
+ getCapabilities_1_5_cb hidl_status_cb) override;
Return<void> debug(const hidl_handle& handle,
const hidl_vec<hidl_string>& options) override;
Return<void> createRttController_1_4(
const sp<IWifiIface>& bound_iface,
createRttController_1_4_cb hidl_status_cb) override;
Return<void> registerEventCallback_1_4(
- const sp<IWifiChipEventCallback>& event_callback,
+ const sp<V1_4::IWifiChipEventCallback>& event_callback,
registerEventCallback_1_4_cb hidl_status_cb) override;
private:
@@ -188,9 +191,9 @@
std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
const std::string& ifname);
WifiStatus removeApIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
+ std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
+ std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(
const std::string& ifname);
WifiStatus removeNanIfaceInternal(const std::string& ifname);
std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
@@ -225,21 +228,22 @@
const sp<V1_2::IWifiChipEventCallback>& event_callback);
WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
- std::pair<WifiStatus, sp<IWifiRttController>>
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
+ std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
WifiStatus registerEventCallbackInternal_1_4(
- const sp<IWifiChipEventCallback>& event_callback);
+ const sp<V1_4::IWifiChipEventCallback>& event_callback);
WifiStatus handleChipConfiguration(
std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
WifiStatus registerDebugRingBufferCallback();
WifiStatus registerRadioModeChangeCallback();
- std::vector<IWifiChip::ChipIfaceCombination>
+ std::vector<V1_4::IWifiChip::ChipIfaceCombination>
getCurrentModeIfaceCombinations();
std::map<IfaceType, size_t> getCurrentIfaceCombination();
std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
- const IWifiChip::ChipIfaceCombination& combination);
+ const V1_4::IWifiChip::ChipIfaceCombination& combination);
bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
const std::map<IfaceType, size_t>& expanded_combo,
IfaceType requested_type);
@@ -255,10 +259,11 @@
bool isStaApConcurrencyAllowedInCurrentMode();
bool isDualApAllowedInCurrentMode();
std::string getFirstActiveWlanIfaceName();
- std::string allocateApOrStaIfaceName(uint32_t start_idx);
+ std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
std::string allocateApIfaceName();
std::string allocateStaIfaceName();
bool writeRingbufferFilesInternal();
+ std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
@@ -274,19 +279,21 @@
// Members pertaining to chip configuration.
uint32_t current_mode_id_;
std::mutex lock_t;
- std::vector<IWifiChip::ChipMode> modes_;
+ std::vector<V1_4::IWifiChip::ChipMode> modes_;
// The legacy ring buffer callback API has only a global callback
// registration mechanism. Use this to check if we have already
// registered a callback.
bool debug_ring_buffer_cb_registered_;
- hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+ hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback>
event_cb_handler_;
+ const std::function<void(const std::string&)> subsystemCallbackHandler_;
+
DISALLOW_COPY_AND_ASSIGN(WifiChip);
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
similarity index 93%
rename from wifi/1.4/default/wifi_feature_flags.cpp
rename to wifi/1.5/default/wifi_feature_flags.cpp
index 195b460..9f91bd7 100644
--- a/wifi/1.4/default/wifi_feature_flags.cpp
+++ b/wifi/1.5/default/wifi_feature_flags.cpp
@@ -19,7 +19,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace feature_flags {
@@ -139,6 +139,13 @@
ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
#endif
};
+
+static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+ {chip_mode_ids::kV3, ChipIfaceCombination::make_vec(
+ {WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
#undef STA
#undef AP
#undef P2P
@@ -154,13 +161,14 @@
WifiFeatureFlags::WifiFeatureFlags() {}
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
- return kChipModes;
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(
+ bool is_primary) {
+ return (is_primary) ? kChipModes : kChipModesSecondary;
}
} // namespace feature_flags
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.5/default/wifi_feature_flags.h
similarity index 95%
rename from wifi/1.4/default/wifi_feature_flags.h
rename to wifi/1.5/default/wifi_feature_flags.h
index 292dedf..cb68b8c 100644
--- a/wifi/1.4/default/wifi_feature_flags.h
+++ b/wifi/1.5/default/wifi_feature_flags.h
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace feature_flags {
@@ -42,12 +42,13 @@
WifiFeatureFlags();
virtual ~WifiFeatureFlags() = default;
- virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+ virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(
+ bool is_primary);
};
} // namespace feature_flags
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_iface_util.cpp
rename to wifi/1.5/default/wifi_iface_util.cpp
index 49b7674..07175e4 100644
--- a/wifi/1.4/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -36,7 +36,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace iface_util {
@@ -129,7 +129,7 @@
}
} // namespace iface_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.h b/wifi/1.5/default/wifi_iface_util.h
similarity index 98%
rename from wifi/1.4/default/wifi_iface_util.h
rename to wifi/1.5/default/wifi_iface_util.h
index 126b6ca..7b812fa 100644
--- a/wifi/1.4/default/wifi_iface_util.h
+++ b/wifi/1.5/default/wifi_iface_util.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace iface_util {
@@ -69,7 +69,7 @@
} // namespace iface_util
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
similarity index 95%
rename from wifi/1.4/default/wifi_legacy_hal.cpp
rename to wifi/1.5/default/wifi_legacy_hal.cpp
index 75f22ec..398bfac 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -36,7 +36,8 @@
static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+// need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
static constexpr char kDriverPropName[] = "wlan.driver.status";
// Helper function to create a non-const char* for legacy Hal API's.
@@ -51,9 +52,10 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace legacy_hal {
+
// Legacy HAL functions accept "C" style function pointers, so use global
// functions to pass to the legacy HAL function and store the corresponding
// std::function methods to be invoked.
@@ -162,6 +164,15 @@
}
}
+// Callback to be invoked to report subsystem restart
+std::function<void(const char*)> on_subsystem_restart_internal_callback;
+void onAsyncSubsystemRestart(const char* error) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_subsystem_restart_internal_callback) {
+ on_subsystem_restart_internal_callback(error);
+ }
+}
+
// Callback to be invoked for rtt results results.
std::function<void(wifi_request_id, unsigned num_results,
wifi_rtt_result* rtt_results[])>
@@ -335,26 +346,20 @@
// End of the free-standing "C" style callbacks.
WifiLegacyHal::WifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : global_handle_(nullptr),
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary)
+ : global_func_table_(fn),
+ global_handle_(nullptr),
awaiting_event_loop_termination_(false),
is_started_(false),
- iface_tool_(iface_tool) {}
+ iface_tool_(iface_tool),
+ is_primary_(is_primary) {}
wifi_error WifiLegacyHal::initialize() {
LOG(DEBUG) << "Initialize legacy HAL";
- // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
- // for now is this function call which we can directly call.
- if (!initHalFuncTableWithStubs(&global_func_table_)) {
- LOG(ERROR)
- << "Failed to initialize legacy hal function table with stubs";
- return WIFI_ERROR_UNKNOWN;
- }
- wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
- if (status != WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to initialize legacy hal function table";
- }
- return status;
+ // this now does nothing, since HAL function table is provided
+ // to the constructor
+ return WIFI_SUCCESS;
}
wifi_error WifiLegacyHal::start() {
@@ -371,13 +376,17 @@
LOG(ERROR) << "Failed or timed out awaiting driver ready";
return status;
}
- property_set(kDriverPropName, "ok");
+
+ if (is_primary_) {
+ property_set(kDriverPropName, "ok");
+
+ if (!iface_tool_.lock()->SetWifiUpState(true)) {
+ LOG(ERROR) << "Failed to set WiFi interface up";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ }
LOG(DEBUG) << "Starting legacy HAL";
- if (!iface_tool_.lock()->SetWifiUpState(true)) {
- LOG(ERROR) << "Failed to set WiFi interface up";
- return WIFI_ERROR_UNKNOWN;
- }
status = global_func_table_.wifi_initialize(&global_handle_);
if (status != WIFI_SUCCESS || !global_handle_) {
LOG(ERROR) << "Failed to retrieve global handle";
@@ -410,7 +419,7 @@
// Invalidate all the internal pointers now that the HAL is
// stopped.
invalidate();
- iface_tool_.lock()->SetWifiUpState(false);
+ if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
on_stop_complete_user_callback();
is_started_ = false;
};
@@ -477,14 +486,23 @@
return {status, std::move(firmware_dump)};
}
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
+std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
const std::string& iface_name) {
- feature_set set;
+ feature_set set = 0, chip_set = 0;
+ wifi_error status = WIFI_SUCCESS;
+
static_assert(sizeof(set) == sizeof(uint64_t),
"Some feature_flags can not be represented in output");
- wifi_error status = global_func_table_.wifi_get_supported_feature_set(
- getIfaceHandle(iface_name), &set);
- return {status, static_cast<uint32_t>(set)};
+ wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+ global_func_table_.wifi_get_chip_feature_set(
+ global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+ if (iface_handle) {
+ status = global_func_table_.wifi_get_supported_feature_set(iface_handle,
+ &set);
+ }
+ return {status, static_cast<uint64_t>(set | chip_set)};
}
std::pair<wifi_error, PacketFilterCapabilities>
@@ -836,10 +854,15 @@
std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
const std::string& iface_name) {
- uint32_t supported_feature_flags;
- wifi_error status =
- global_func_table_.wifi_get_logger_supported_feature_set(
- getIfaceHandle(iface_name), &supported_feature_flags);
+ uint32_t supported_feature_flags = 0;
+ wifi_error status = WIFI_SUCCESS;
+
+ wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+ if (iface_handle) {
+ status = global_func_table_.wifi_get_logger_supported_feature_set(
+ iface_handle, &supported_feature_flags);
+ }
return {status, supported_feature_flags};
}
@@ -1049,6 +1072,23 @@
return status;
}
+wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
+ const on_subsystem_restart_callback& on_restart_callback) {
+ if (on_subsystem_restart_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_subsystem_restart_internal_callback =
+ [on_restart_callback](const char* error) {
+ on_restart_callback(error);
+ };
+ wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
+ global_handle_, {onAsyncSubsystemRestart});
+ if (status != WIFI_SUCCESS) {
+ on_subsystem_restart_internal_callback = nullptr;
+ }
+ return status;
+}
+
wifi_error WifiLegacyHal::startRttRangeRequest(
const std::string& iface_name, wifi_request_id id,
const std::vector<wifi_rtt_config>& rtt_configs,
@@ -1459,6 +1499,17 @@
return status;
}
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type,
+ std::string& ifname) {
+ std::array<char, IFNAMSIZ> buffer;
+
+ wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+ global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+ if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+ return res;
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
@@ -1471,6 +1522,7 @@
on_ring_buffer_data_internal_callback = nullptr;
on_error_alert_internal_callback = nullptr;
on_radio_mode_change_internal_callback = nullptr;
+ on_subsystem_restart_internal_callback = nullptr;
on_rtt_results_internal_callback = nullptr;
on_nan_notify_response_user_callback = nullptr;
on_nan_event_publish_terminated_user_callback = nullptr;
@@ -1493,7 +1545,7 @@
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal.h
rename to wifi/1.5/default/wifi_legacy_hal.h
index 9964460..9a06efd 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -35,7 +35,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
// This is in a separate namespace to prevent typename conflicts between
// the legacy HAL types and the HIDL interface types.
@@ -142,6 +142,9 @@
using on_error_alert_callback =
std::function<void(int32_t, const std::vector<uint8_t>&)>;
+// Callback for subsystem restart
+using on_subsystem_restart_callback = std::function<void(const std::string&)>;
+
// Struct for the mac info from the legacy HAL. This is a cleaner version
// of the |wifi_mac_info| & |wifi_iface_info|.
typedef struct {
@@ -170,7 +173,8 @@
*/
class WifiLegacyHal {
public:
- WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary);
virtual ~WifiLegacyHal() = default;
// Initialize the legacy HAL function table.
@@ -192,7 +196,7 @@
const std::string& iface_name);
std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
const std::string& iface_name);
- std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
+ std::pair<wifi_error, uint64_t> getSupportedFeatureSet(
const std::string& iface_name);
// APF functions.
std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
@@ -277,6 +281,8 @@
const on_ring_buffer_data_callback& on_data_callback);
wifi_error deregisterRingBufferCallbackHandler(
const std::string& iface_name);
+ wifi_error registerSubsystemRestartCallbackHandler(
+ const on_subsystem_restart_callback& on_restart_callback);
std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
getRingBuffersStatus(const std::string& iface_name);
wifi_error startRingBufferLogging(const std::string& iface_name,
@@ -374,6 +380,7 @@
virtual wifi_error createVirtualInterface(const std::string& ifname,
wifi_interface_type iftype);
virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+ wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
private:
// Retrieve interface handles for all the available interfaces.
@@ -403,11 +410,16 @@
// Flag to indicate if the legacy HAL has been started.
bool is_started_;
std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ // flag to indicate if this HAL is for the primary chip. This is used
+ // in order to avoid some hard-coded behavior used with older HALs,
+ // such as bring wlan0 interface up/down on start/stop HAL.
+ // it may be removed once vendor HALs are updated.
+ bool is_primary_;
};
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.cpp b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..fbaa284
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,263 @@
+/*
+ * 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 <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+ bool isDir = false;
+ if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+ isDir = (entryPtr->d_type == DT_DIR);
+ } else {
+ struct stat entryStat;
+ stat(entryPtr->d_name, &entryStat);
+ isDir = S_ISDIR(entryStat.st_mode);
+ }
+ return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+ if (name == NULL) return false;
+ if (ext == NULL) return false;
+
+ size_t extLen = strlen(ext);
+ size_t nameLen = strlen(name);
+
+ if (extLen > nameLen) return false;
+
+ if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+ return true;
+}
+}; // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+ if (legacy_hals_.empty()) {
+ if (!initVendorHalDescriptorFromLinked())
+ initVendorHalsDescriptorList();
+ for (auto& desc : descs_) {
+ std::shared_ptr<WifiLegacyHal> hal =
+ std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn,
+ desc.primary);
+ legacy_hals_.push_back(hal);
+ }
+ }
+
+ return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+ wifi_hal_lib_desc desc;
+
+ if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+ desc.primary = true;
+ desc.handle = NULL;
+ descs_.push_back(desc);
+ return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+ init_wifi_vendor_hal_func_table_t initfn;
+
+ initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+ RTLD_DEFAULT, "init_wifi_vendor_hal_func_table");
+ if (!initfn) {
+ LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+ return false;
+ }
+
+ if (!initHalFuncTableWithStubs(hal_fn)) {
+ LOG(ERROR) << "Can not initialize the basic function pointer table";
+ return false;
+ }
+
+ if (initfn(hal_fn) != WIFI_SUCCESS) {
+ LOG(ERROR) << "Can not initialize the vendor function pointer table";
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+ xmlDocPtr xml;
+ xmlNodePtr node, cnode;
+ char* version;
+ std::string path;
+ xmlChar* value;
+ wifi_hal_lib_desc desc;
+
+ LOG(INFO) << "processing vendor HALs descriptions in "
+ << kVendorHalsDescPath;
+ DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+ if (dirPtr == NULL) {
+ LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+ return;
+ }
+ for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+ entryPtr = ::readdir(dirPtr)) {
+ if (isDirectory(entryPtr)) continue;
+
+ if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+ continue; // only process .xml files
+
+ LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+ std::string fullPath(kVendorHalsDescPath);
+ fullPath.append("/");
+ fullPath.append(entryPtr->d_name);
+ xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+ if (!xml) {
+ LOG(ERROR) << "failed to parse: " << entryPtr->d_name
+ << " skipping...";
+ continue;
+ }
+ node = xmlDocGetRootElement(xml);
+ if (!node) {
+ LOG(ERROR) << "empty config file: " << entryPtr->d_name
+ << " skipping...";
+ goto skip;
+ }
+ if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+ LOG(ERROR) << "bad config, root element not WifiVendorHal: "
+ << entryPtr->d_name << " skipping...";
+ goto skip;
+ }
+ version = (char*)xmlGetProp(node, BAD_CAST "version");
+ if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+ LOG(ERROR) << "conf file: " << entryPtr->d_name
+ << "must have version: " << kVendorHalsDescVersion
+ << ", skipping...";
+ goto skip;
+ }
+ cnode = node->children;
+ path.clear();
+ desc.primary = false;
+ while (cnode) {
+ if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+ value = xmlNodeListGetString(xml, cnode->children, 1);
+ if (value) path = (char*)value;
+ xmlFree(value);
+ } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+ value = xmlNodeListGetString(xml, cnode->children, 1);
+ desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+ xmlFree(value);
+ }
+ cnode = cnode->next;
+ }
+ if (path.empty()) {
+ LOG(ERROR) << "hal library path not provided in: "
+ << entryPtr->d_name << ", skipping...";
+ goto skip;
+ }
+ if (loadVendorHalLib(path, desc)) {
+ if (desc.primary)
+ descs_.insert(descs_.begin(), desc);
+ else
+ descs_.push_back(desc);
+ }
+ skip:
+ xmlFreeDoc(xml);
+ }
+ ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path,
+ wifi_hal_lib_desc& desc) {
+ void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+ init_wifi_vendor_hal_func_table_t initfn;
+ wifi_error res;
+
+ if (!h) {
+ LOG(ERROR) << "failed to open vendor hal library: " << path;
+ return false;
+ }
+ initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+ h, "init_wifi_vendor_hal_func_table");
+ if (!initfn) {
+ LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+ goto out_err;
+ }
+
+ if (!initHalFuncTableWithStubs(&desc.fn)) {
+ LOG(ERROR) << "Can not initialize the basic function pointer table";
+ goto out_err;
+ }
+ res = initfn(&desc.fn);
+ if (res != WIFI_SUCCESS) {
+ LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+ << " error: " << res;
+ goto out_err;
+ }
+
+ res = desc.fn.wifi_early_initialize();
+ // vendor HALs which do not implement early_initialize will return
+ // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+ if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+ LOG(ERROR) << "early initialization failed in: " << path
+ << " error: " << res;
+ goto out_err;
+ }
+
+ desc.handle = h;
+ return true;
+out_err:
+ dlclose(h);
+ return false;
+}
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_5
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.h b/wifi/1.5/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..e3440fa
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.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 WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+ public:
+ WifiLegacyHalFactory(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ virtual ~WifiLegacyHalFactory() = default;
+
+ std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+ private:
+ typedef struct {
+ wifi_hal_fn fn;
+ bool primary;
+ void* handle;
+ } wifi_hal_lib_desc;
+
+ bool initVendorHalDescriptorFromLinked();
+ void initVendorHalsDescriptorList();
+ bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+ bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::vector<wifi_hal_lib_desc> descs_;
+ std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_5
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal_stubs.cpp
rename to wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 153a685..a1122e9 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -20,7 +20,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace legacy_hal {
template <typename>
@@ -143,11 +143,16 @@
populateStubFor(&hal_fn->wifi_virtual_interface_delete);
populateStubFor(&hal_fn->wifi_map_dscp_access_category);
populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+ populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+ populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+ populateStubFor(&hal_fn->wifi_early_initialize);
+ populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+
return true;
}
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.h b/wifi/1.5/default/wifi_legacy_hal_stubs.h
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal_stubs.h
rename to wifi/1.5/default/wifi_legacy_hal_stubs.h
index 577a545..7e4eb0a 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.h
@@ -20,7 +20,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace legacy_hal {
#include <hardware_legacy/wifi_hal.h>
@@ -28,7 +28,7 @@
bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
} // namespace legacy_hal
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.cpp b/wifi/1.5/default/wifi_mode_controller.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_mode_controller.cpp
rename to wifi/1.5/default/wifi_mode_controller.cpp
index 252121a..b1db8b3 100644
--- a/wifi/1.4/default/wifi_mode_controller.cpp
+++ b/wifi/1.5/default/wifi_mode_controller.cpp
@@ -48,7 +48,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace mode_controller {
@@ -85,7 +85,7 @@
}
} // namespace mode_controller
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.h b/wifi/1.5/default/wifi_mode_controller.h
similarity index 97%
rename from wifi/1.4/default/wifi_mode_controller.h
rename to wifi/1.5/default/wifi_mode_controller.h
index 45fa999..2eeca78 100644
--- a/wifi/1.4/default/wifi_mode_controller.h
+++ b/wifi/1.5/default/wifi_mode_controller.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
namespace mode_controller {
using namespace android::hardware::wifi::V1_0;
@@ -55,7 +55,7 @@
} // namespace mode_controller
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.5/default/wifi_nan_iface.cpp
similarity index 91%
rename from wifi/1.4/default/wifi_nan_iface.cpp
rename to wifi/1.5/default/wifi_nan_iface.cpp
index 24ffb17..0cc6cd5 100644
--- a/wifi/1.4/default/wifi_nan_iface.cpp
+++ b/wifi/1.5/default/wifi_nan_iface.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -166,10 +166,10 @@
return;
}
for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
+ shared_ptr_this->getEventCallbacks_1_5()) {
if (!callback
- ->notifyCapabilitiesResponse(id, wifiNanStatus,
- hidl_struct)
+ ->notifyCapabilitiesResponse_1_5(id, wifiNanStatus,
+ hidl_struct)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
@@ -545,6 +545,7 @@
legacy_hal_.reset();
event_cb_handler_.invalidate();
event_cb_handler_1_2_.invalidate();
+ event_cb_handler_1_5_.invalidate();
is_valid_ = false;
if (is_dedicated_iface_) {
// If using a dedicated iface, set the iface down.
@@ -566,6 +567,10 @@
return event_cb_handler_1_2_.getCallbacks();
}
+std::set<sp<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_5() {
+ return event_cb_handler_1_5_.getCallbacks();
+}
+
Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::getNameInternal, hidl_status_cb);
@@ -721,7 +726,7 @@
}
Return<void> WifiNanIface::enableRequest_1_4(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
enableRequest_1_4_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -730,7 +735,7 @@
}
Return<void> WifiNanIface::configRequest_1_4(
- uint16_t cmd_id, const NanConfigRequest& msg1,
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
configRequest_1_4_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -738,6 +743,39 @@
hidl_status_cb, cmd_id, msg1, msg2);
}
+Return<void> WifiNanIface::registerEventCallback_1_5(
+ const sp<IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_5Internal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_5(
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ enableRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_5Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_5(
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ configRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_5Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest_1_5(
+ uint16_t cmd_id, getCapabilitiesRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getCapabilitiesRequest_1_5Internal,
+ hidl_status_cb, cmd_id);
+}
+
std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
}
@@ -754,10 +792,8 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t /* cmd_id */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
WifiStatus WifiNanIface::enableRequestInternal(
@@ -890,7 +926,7 @@
WifiStatus WifiNanIface::enableRequest_1_2Internal(
uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
- const V1_2::NanConfigRequestSupplemental& /*msg2 */) {
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
@@ -901,10 +937,44 @@
}
WifiStatus WifiNanIface::enableRequest_1_4Internal(
- uint16_t cmd_id, const NanEnableRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2) {
+ uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_4Internal(
+ uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_5Internal(
+ const sp<IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+ if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_5_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequest_1_5Internal(uint16_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_5Internal(
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2) {
legacy_hal::NanEnableRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy(
+ if (!hidl_struct_util::convertHidlNanEnableRequest_1_5ToLegacy(
msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
@@ -913,11 +983,11 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-WifiStatus WifiNanIface::configRequest_1_4Internal(
- uint16_t cmd_id, const NanConfigRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2) {
+WifiStatus WifiNanIface::configRequest_1_5Internal(
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2) {
legacy_hal::NanConfigRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy(
+ if (!hidl_struct_util::convertHidlNanConfigRequest_1_5ToLegacy(
msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
@@ -927,7 +997,7 @@
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.5/default/wifi_nan_iface.h
similarity index 80%
rename from wifi/1.4/default/wifi_nan_iface.h
rename to wifi/1.5/default/wifi_nan_iface.h
index 06edbf2..fb9c047 100644
--- a/wifi/1.4/default/wifi_nan_iface.h
+++ b/wifi/1.5/default/wifi_nan_iface.h
@@ -18,8 +18,8 @@
#define WIFI_NAN_IFACE_H_
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+#include <android/hardware/wifi/1.5/IWifiNanIface.h>
+#include <android/hardware/wifi/1.5/IWifiNanIfaceEventCallback.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -28,7 +28,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
using namespace android::hardware::wifi::V1_2;
@@ -36,7 +36,7 @@
/**
* HIDL interface object used to control a NAN Iface instance.
*/
-class WifiNanIface : public V1_4::IWifiNanIface {
+class WifiNanIface : public V1_5::IWifiNanIface {
public:
WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -105,13 +105,26 @@
const V1_2::NanConfigRequestSupplemental& msg2,
configRequest_1_2_cb hidl_status_cb) override;
Return<void> enableRequest_1_4(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
- enableRequest_1_2_cb hidl_status_cb) override;
+ enableRequest_1_4_cb hidl_status_cb) override;
Return<void> configRequest_1_4(
- uint16_t cmd_id, const NanConfigRequest& msg1,
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
- configRequest_1_2_cb hidl_status_cb) override;
+ configRequest_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_5(
+ const sp<IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_5_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_5(
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ enableRequest_1_4_cb hidl_status_cb) override;
+ Return<void> configRequest_1_5(
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ configRequest_1_4_cb hidl_status_cb) override;
+ Return<void> getCapabilitiesRequest_1_5(
+ uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -153,16 +166,27 @@
uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
const V1_2::NanConfigRequestSupplemental& msg2);
WifiStatus enableRequest_1_4Internal(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2);
WifiStatus configRequest_1_4Internal(
- uint16_t cmd_id, const NanConfigRequest& msg,
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus registerEventCallback_1_5Internal(
+ const sp<IWifiNanIfaceEventCallback>& callback);
+ WifiStatus enableRequest_1_5Internal(
+ uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_5Internal(
+ uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+ const NanConfigRequestSupplemental& msg2);
+ WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
// all 1_0 and descendant callbacks
std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
// all 1_2 and descendant callbacks
std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
+ // all 1_5 and descendant callbacks
+ std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
std::string ifname_;
bool is_dedicated_iface_;
@@ -173,12 +197,14 @@
event_cb_handler_;
hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
event_cb_handler_1_2_;
+ hidl_callback_util::HidlCallbackHandler<IWifiNanIfaceEventCallback>
+ event_cb_handler_1_5_;
DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.cpp b/wifi/1.5/default/wifi_p2p_iface.cpp
similarity index 97%
rename from wifi/1.4/default/wifi_p2p_iface.cpp
rename to wifi/1.5/default/wifi_p2p_iface.cpp
index 9e7341f..b8893da 100644
--- a/wifi/1.4/default/wifi_p2p_iface.cpp
+++ b/wifi/1.5/default/wifi_p2p_iface.cpp
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -60,7 +60,7 @@
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.h b/wifi/1.5/default/wifi_p2p_iface.h
similarity index 97%
rename from wifi/1.4/default/wifi_p2p_iface.h
rename to wifi/1.5/default/wifi_p2p_iface.h
index a6fc59d..c1adc50 100644
--- a/wifi/1.4/default/wifi_p2p_iface.h
+++ b/wifi/1.5/default/wifi_p2p_iface.h
@@ -25,7 +25,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
@@ -58,7 +58,7 @@
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.cpp b/wifi/1.5/default/wifi_rtt_controller.cpp
similarity index 94%
rename from wifi/1.4/default/wifi_rtt_controller.cpp
rename to wifi/1.5/default/wifi_rtt_controller.cpp
index 594a116..a0f9969 100644
--- a/wifi/1.4/default/wifi_rtt_controller.cpp
+++ b/wifi/1.5/default/wifi_rtt_controller.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -44,7 +44,7 @@
bool WifiRttController::isValid() { return is_valid_; }
-std::vector<sp<IWifiRttControllerEventCallback>>
+std::vector<sp<V1_4::IWifiRttControllerEventCallback>>
WifiRttController::getEventCallbacks() {
return event_callbacks_;
}
@@ -131,7 +131,7 @@
}
Return<void> WifiRttController::registerEventCallback_1_4(
- const sp<IWifiRttControllerEventCallback>& callback,
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback,
registerEventCallback_1_4_cb hidl_status_cb) {
return validateAndCall(
this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -140,7 +140,7 @@
}
Return<void> WifiRttController::rangeRequest_1_4(
- uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+ uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
rangeRequest_1_4_cb hidl_status_cb) {
return validateAndCall(this,
WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -164,7 +164,7 @@
Return<void> WifiRttController::enableResponder_1_4(
uint32_t cmd_id, const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds, const RttResponder& info,
+ uint32_t max_duration_seconds, const V1_4::RttResponder& info,
enableResponder_1_4_cb hidl_status_cb) {
return validateAndCall(
this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -252,14 +252,14 @@
}
WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
- const sp<IWifiRttControllerEventCallback>& callback) {
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback) {
// TODO(b/31632518): remove the callback when the client is destroyed
event_callbacks_.emplace_back(callback);
return createWifiStatus(WifiStatusCode::SUCCESS);
}
WifiStatus WifiRttController::rangeRequestInternal_1_4(
- uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+ uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs) {
std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
rtt_configs, &legacy_configs)) {
@@ -275,7 +275,7 @@
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
- std::vector<RttResult> hidl_results;
+ std::vector<V1_4::RttResult> hidl_results;
if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
results, &hidl_results)) {
LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
@@ -291,7 +291,7 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-std::pair<WifiStatus, RttCapabilities>
+std::pair<WifiStatus, V1_4::RttCapabilities>
WifiRttController::getCapabilitiesInternal_1_4() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_capabilities legacy_caps;
@@ -300,7 +300,7 @@
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- RttCapabilities hidl_caps;
+ V1_4::RttCapabilities hidl_caps;
if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
&hidl_caps)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -308,7 +308,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
}
-std::pair<WifiStatus, RttResponder>
+std::pair<WifiStatus, V1_4::RttResponder>
WifiRttController::getResponderInfoInternal_1_4() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_responder legacy_responder;
@@ -317,7 +317,7 @@
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- RttResponder hidl_responder;
+ V1_4::RttResponder hidl_responder;
if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
&hidl_responder)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -327,7 +327,7 @@
WifiStatus WifiRttController::enableResponderInternal_1_4(
uint32_t cmd_id, const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds, const RttResponder& info) {
+ uint32_t max_duration_seconds, const V1_4::RttResponder& info) {
legacy_hal::wifi_channel_info legacy_channel_info;
if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
channel_hint, &legacy_channel_info)) {
@@ -345,7 +345,7 @@
return createWifiStatusFromLegacyError(legacy_status);
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.h b/wifi/1.5/default/wifi_rtt_controller.h
similarity index 86%
rename from wifi/1.4/default/wifi_rtt_controller.h
rename to wifi/1.5/default/wifi_rtt_controller.h
index 1f12555..9ac3e06 100644
--- a/wifi/1.4/default/wifi_rtt_controller.h
+++ b/wifi/1.5/default/wifi_rtt_controller.h
@@ -27,7 +27,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
/**
@@ -41,7 +41,7 @@
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
- std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
+ std::vector<sp<V1_4::IWifiRttControllerEventCallback>> getEventCallbacks();
std::string getIfaceName();
// HIDL methods exposed.
@@ -69,10 +69,10 @@
Return<void> disableResponder(uint32_t cmd_id,
disableResponder_cb hidl_status_cb) override;
Return<void> registerEventCallback_1_4(
- const sp<IWifiRttControllerEventCallback>& callback,
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback,
registerEventCallback_1_4_cb hidl_status_cb) override;
Return<void> rangeRequest_1_4(uint32_t cmd_id,
- const hidl_vec<RttConfig>& rtt_configs,
+ const hidl_vec<V1_4::RttConfig>& rtt_configs,
rangeRequest_1_4_cb hidl_status_cb) override;
Return<void> getCapabilities_1_4(
getCapabilities_1_4_cb hidl_status_cb) override;
@@ -80,7 +80,7 @@
getResponderInfo_1_4_cb hidl_status_cb) override;
Return<void> enableResponder_1_4(
uint32_t cmd_id, const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds, const RttResponder& info,
+ uint32_t max_duration_seconds, const V1_4::RttResponder& info,
enableResponder_1_4_cb hidl_status_cb) override;
private:
@@ -102,27 +102,27 @@
const V1_0::RttResponder& info);
WifiStatus disableResponderInternal(uint32_t cmd_id);
WifiStatus registerEventCallbackInternal_1_4(
- const sp<IWifiRttControllerEventCallback>& callback);
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback);
WifiStatus rangeRequestInternal_1_4(
- uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs);
- std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal_1_4();
- std::pair<WifiStatus, RttResponder> getResponderInfoInternal_1_4();
+ uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs);
+ std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
+ std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
const WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
- const RttResponder& info);
+ const V1_4::RttResponder& info);
std::string ifname_;
sp<IWifiIface> bound_iface_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
+ std::vector<sp<V1_4::IWifiRttControllerEventCallback>> event_callbacks_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiRttController);
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp
similarity index 99%
rename from wifi/1.4/default/wifi_sta_iface.cpp
rename to wifi/1.5/default/wifi_sta_iface.cpp
index 49f383a..04087fd 100644
--- a/wifi/1.4/default/wifi_sta_iface.cpp
+++ b/wifi/1.5/default/wifi_sta_iface.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -640,7 +640,7 @@
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.5/default/wifi_sta_iface.h
similarity index 99%
rename from wifi/1.4/default/wifi_sta_iface.h
rename to wifi/1.5/default/wifi_sta_iface.h
index dee04f2..7695f3c 100644
--- a/wifi/1.4/default/wifi_sta_iface.h
+++ b/wifi/1.5/default/wifi_sta_iface.h
@@ -28,7 +28,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
@@ -172,7 +172,7 @@
};
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.5/default/wifi_status_util.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_status_util.cpp
rename to wifi/1.5/default/wifi_status_util.cpp
index 8ceb926..eb8c869 100644
--- a/wifi/1.4/default/wifi_status_util.cpp
+++ b/wifi/1.5/default/wifi_status_util.cpp
@@ -19,7 +19,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
std::string legacyErrorToString(legacy_hal::wifi_error error) {
@@ -106,7 +106,7 @@
}
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.h b/wifi/1.5/default/wifi_status_util.h
similarity index 97%
rename from wifi/1.4/default/wifi_status_util.h
rename to wifi/1.5/default/wifi_status_util.h
index 3ff58f0..68f2168 100644
--- a/wifi/1.4/default/wifi_status_util.h
+++ b/wifi/1.5/default/wifi_status_util.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
@@ -37,7 +37,7 @@
WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
} // namespace implementation
-} // namespace V1_4
+} // namespace V1_5
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
new file mode 100644
index 0000000..5873f79
--- /dev/null
+++ b/wifi/1.5/types.hal
@@ -0,0 +1,69 @@
+/*
+ * 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.0::WifiBand;
+import @1.0::NanCipherSuiteType;
+import @1.0::NanCapabilities;
+import @1.2::NanConfigRequestSupplemental;
+
+/**
+ * Wifi bands defined in 80211 spec.
+ */
+enum WifiBand : @1.0::WifiBand {
+ /**
+ * 60 GHz.
+ */
+ BAND_60GHZ = 16,
+ /**
+ * 2.4 GHz + 5 GHz no DFS + 6 GHz + 60 GHz.
+ */
+ BAND_24GHZ_5GHZ_6GHZ_60GHZ = 27,
+ /**
+ * 2.4 GHz + 5 GHz with DFS + 6 GHz + 60 GHz.
+ */
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ = 31,
+};
+
+/**
+ * NAN configuration request parameters added in the 1.2 HAL. These are supplemental to previous
+ * versions.
+ */
+struct NanConfigRequestSupplemental {
+ /**
+ * Baseline information as defined in HAL 1.2.
+ */
+ @1.2::NanConfigRequestSupplemental V1_2;
+ /**
+ * Controls whether NAN instant communication mode is enabled.
+ */
+ bool enableInstantCommunicationMode;
+};
+
+/**
+ * NDP Capabilities response.
+ */
+struct NanCapabilities {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::NanCapabilities V1_0;
+ /**
+ * Flag to indicate id instant communication mode is supported.
+ */
+ bool instantCommunicationModeSupportFlag;
+};
\ No newline at end of file
diff --git a/wifi/1.4/default/OWNERS b/wifi/1.5/vts/OWNERS
similarity index 100%
copy from wifi/1.4/default/OWNERS
copy to wifi/1.5/vts/OWNERS
diff --git a/wifi/1.5/vts/functional/Android.bp b/wifi/1.5/vts/functional/Android.bp
new file mode 100644
index 0000000..a7ba498
--- /dev/null
+++ b/wifi/1.5/vts/functional/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.
+//
+
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
+cc_test {
+ name: "VtsHalWifiNanV1_5TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "wifi_nan_iface_hidl_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_nan_iface_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp
new file mode 100644
index 0000000..803d39d
--- /dev/null
+++ b/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Nanache 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.5/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifiNanIface.h>
+#include <android/hardware/wifi/1.5/IWifiNanIfaceEventCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using namespace ::android::hardware::wifi::V1_0;
+using namespace ::android::hardware::wifi::V1_2;
+using namespace ::android::hardware::wifi::V1_4;
+using namespace ::android::hardware::wifi::V1_5;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 10
+
+android::sp<android::hardware::wifi::V1_5::IWifiNanIface> getWifiNanIface_1_5(
+ const std::string& instance_name) {
+ return android::hardware::wifi::V1_5::IWifiNanIface::castFrom(
+ getWifiNanIface(instance_name));
+}
+
+/**
+ * Fixture to use for all NAN Iface HIDL interface tests.
+ */
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+ GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ iwifiNanIface = getWifiNanIface_1_5(GetInstanceName());
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_5,
+ new WifiNanIfaceEventCallback(*this))
+ .code);
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count_++;
+ cv_.notify_one();
+ }
+
+ enum CallbackType {
+ INVALID = -2,
+ ANY_CALLBACK = -1,
+
+ NOTIFY_CAPABILITIES_RESPONSE = 0,
+ NOTIFY_ENABLE_RESPONSE,
+ NOTIFY_CONFIG_RESPONSE,
+ NOTIFY_DISABLE_RESPONSE,
+ NOTIFY_START_PUBLISH_RESPONSE,
+ NOTIFY_STOP_PUBLISH_RESPONSE,
+ NOTIFY_START_SUBSCRIBE_RESPONSE,
+ NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+ NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+ NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+ NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+ NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+ NOTIFY_CAPABILITIES_RESPONSE_1_5,
+
+ EVENT_CLUSTER_EVENT,
+ EVENT_DISABLED,
+ EVENT_PUBLISH_TERMINATED,
+ EVENT_SUBSCRIBE_TERMINATED,
+ EVENT_MATCH,
+ EVENT_MATCH_EXPIRED,
+ EVENT_FOLLOWUP_RECEIVED,
+ EVENT_TRANSMIT_FOLLOWUP,
+ EVENT_DATA_PATH_REQUEST,
+ EVENT_DATA_PATH_CONFIRM,
+ EVENT_DATA_PATH_TERMINATED,
+ EVENT_DATA_PATH_CONFIRM_1_2,
+ EVENT_DATA_PATH_SCHEDULE_UPDATE
+ };
+
+ /* Test code calls this function to wait for data/event callback */
+ /* Must set callbackType = INVALID before call this function */
+ inline std::cv_status wait(CallbackType waitForCallbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a
+ // non-void-returning method
+
+ 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;
+ if (waitForCallbackType != ANY_CALLBACK &&
+ callbackType != INVALID &&
+ callbackType != waitForCallbackType) {
+ count_--;
+ }
+ }
+ count_--;
+ return status;
+ }
+
+ class WifiNanIfaceEventCallback
+ : public ::android::hardware::wifi::V1_5::IWifiNanIfaceEventCallback {
+ WifiNanIfaceHidlTest& parent_;
+
+ public:
+ WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent)
+ : parent_(parent){};
+
+ virtual ~WifiNanIfaceEventCallback() = default;
+
+ Return<void> notifyCapabilitiesResponse(
+ uint16_t id, const WifiNanStatus& status,
+ const ::android::hardware::wifi::V1_0::NanCapabilities&
+ capabilities) override {
+ parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.capabilities = capabilities;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyCapabilitiesResponse_1_5(
+ uint16_t id, const WifiNanStatus& status,
+ const ::android::hardware::wifi::V1_5::NanCapabilities&
+ capabilities) override {
+ parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE_1_5;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.capabilities_1_5 = capabilities;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyEnableResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyConfigResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDisableResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartPublishResponse(uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopPublishResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartSubscribeResponse(uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopSubscribeResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTransmitFollowupResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyCreateDataInterfaceResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDeleteDataInterfaceResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyInitiateDataPathResponse(
+ uint16_t id, const WifiNanStatus& status,
+ uint32_t ndpInstanceId) override {
+ parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyRespondToDataPathIndicationResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType =
+ NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTerminateDataPathResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventClusterEvent(
+ const NanClusterEventInd& event) override {
+ parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+ parent_.nanClusterEventInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDisabled(const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_DISABLED;
+
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventPublishTerminated(
+ uint8_t sessionId, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventSubscribeTerminated(
+ uint8_t sessionId, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatch(const NanMatchInd& event) override {
+ parent_.callbackType = EVENT_MATCH;
+
+ parent_.nanMatchInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatchExpired(uint8_t discoverySessionId,
+ uint32_t peerId) override {
+ parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+ parent_.sessionId = discoverySessionId;
+ parent_.peerId = peerId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventFollowupReceived(
+ const NanFollowupReceivedInd& event) override {
+ parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+ parent_.nanFollowupReceivedInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventTransmitFollowup(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathRequest(
+ const NanDataPathRequestInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+ parent_.nanDataPathRequestInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathConfirm(
+ const ::android::hardware::wifi::V1_0::NanDataPathConfirmInd& event)
+ override {
+ parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+ parent_.nanDataPathConfirmInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathTerminated(uint32_t ndpInstanceId) override {
+ parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathConfirm_1_2(
+ const ::android::hardware::wifi::V1_2::NanDataPathConfirmInd& event)
+ override {
+ parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_2;
+
+ parent_.nanDataPathConfirmInd_1_2 = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathScheduleUpdate(
+ const NanDataPathScheduleUpdateInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE;
+
+ parent_.nanDataPathScheduleUpdateInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+ };
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_ = 0;
+
+ protected:
+ android::sp<::android::hardware::wifi::V1_5::IWifiNanIface> iwifiNanIface;
+
+ // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of
+ // all arguments to all callbacks. They are set by the callback
+ // (notifications or events) and can be retrieved by tests.
+ CallbackType callbackType;
+ uint16_t id;
+ WifiNanStatus status;
+ uint8_t sessionId;
+ uint32_t ndpInstanceId;
+ NanClusterEventInd nanClusterEventInd;
+ NanMatchInd nanMatchInd;
+ uint32_t peerId;
+ NanFollowupReceivedInd nanFollowupReceivedInd;
+ NanDataPathRequestInd nanDataPathRequestInd;
+ ::android::hardware::wifi::V1_0::NanCapabilities capabilities;
+ ::android::hardware::wifi::V1_5::NanCapabilities capabilities_1_5;
+ ::android::hardware::wifi::V1_0::NanDataPathConfirmInd
+ nanDataPathConfirmInd;
+ ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
+ nanDataPathConfirmInd_1_2;
+ NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * Create:
+ * Ensures that an instance of the IWifiNanIface proxy object is
+ * successfully created.
+ */
+TEST_P(WifiNanIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
+}
+
+/*
+ * enableRequest_1_5InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_5InvalidArgs) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+ ::android::hardware::wifi::V1_5::NanConfigRequestSupplemental
+ nanConfigRequestSupp = {};
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_5, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+ ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
+}
+
+/*
+ * enableRequest_1_5ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_5ShimInvalidArgs) {
+ uint16_t inputCmdId = 10;
+ ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+ nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
+ 128; // must be <= 127
+ ::android::hardware::wifi::V1_5::NanConfigRequestSupplemental
+ nanConfigRequestSupp = {};
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_5, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
+}
+
+/*
+ * configRequest_1_5InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_5InvalidArgs) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+ ::android::hardware::wifi::V1_5::NanConfigRequestSupplemental
+ nanConfigRequestSupp = {};
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_5, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+ ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
+}
+
+/*
+ * configRequest_1_5ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_5ShimInvalidArgs) {
+ uint16_t inputCmdId = 10;
+ ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+ nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127
+ ::android::hardware::wifi::V1_5::NanConfigRequestSupplemental
+ nanConfigRequestSupp = {};
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_5, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
+}
+
+/*
+ * getCapabilitiesRequest: validate that returns capabilities.
+ */
+TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest_1_5) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest_1_5, inputCmdId).code;
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus);
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout,
+ wait(NOTIFY_CAPABILITIES_RESPONSE_1_5));
+ ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE_1_5, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+
+ // check for reasonable capability values
+ EXPECT_GT(capabilities_1_5.V1_0.maxConcurrentClusters, (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxPublishes, (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxSubscribes, (unsigned int)0);
+ EXPECT_EQ(capabilities_1_5.V1_0.maxServiceNameLen, (unsigned int)255);
+ EXPECT_EQ(capabilities_1_5.V1_0.maxMatchFilterLen, (unsigned int)255);
+ EXPECT_GT(capabilities_1_5.V1_0.maxTotalMatchFilterLen, (unsigned int)255);
+ EXPECT_EQ(capabilities_1_5.V1_0.maxServiceSpecificInfoLen,
+ (unsigned int)255);
+ EXPECT_GE(capabilities_1_5.V1_0.maxExtendedServiceSpecificInfoLen,
+ (unsigned int)255);
+ EXPECT_GT(capabilities_1_5.V1_0.maxNdiInterfaces, (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxNdpSessions, (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxAppInfoLen, (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxQueuedTransmitFollowupMsgs,
+ (unsigned int)0);
+ EXPECT_GT(capabilities_1_5.V1_0.maxSubscribeInterfaceAddresses,
+ (unsigned int)0);
+ EXPECT_NE(capabilities_1_5.V1_0.supportedCipherSuites, (unsigned int)0);
+ EXPECT_TRUE(capabilities_1_5.instantCommunicationModeSupportFlag ||
+ !capabilities_1_5.instantCommunicationModeSupportFlag);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiNanIfaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_5::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp
index 291eceb..61a8dfd 100644
--- a/wifi/hostapd/1.1/vts/functional/Android.bp
+++ b/wifi/hostapd/1.1/vts/functional/Android.bp
@@ -25,11 +25,15 @@
"VtsHalWifiHostapdV1_0TargetTestUtil",
"android.hardware.wifi.hostapd@1.0",
"android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.hostapd@1.3",
"android.hardware.wifi@1.0",
"libgmock",
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
-
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index d823685..32bbe72 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -23,6 +23,7 @@
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
#include "hostapd_hidl_call_util.h"
#include "hostapd_hidl_test_utils.h"
@@ -43,6 +44,7 @@
constexpr char kNwPassphrase[] = "test12345";
constexpr int kIfaceChannel = 6;
constexpr int kIfaceInvalidChannel = 567;
+
} // namespace
class HostapdHidlTest
@@ -173,10 +175,17 @@
}
};
+bool is_1_3(const sp<IHostapd>& hostapd) {
+ sp<::android::hardware::wifi::hostapd::V1_3::IHostapd> hostapd_1_3 =
+ ::android::hardware::wifi::hostapd::V1_3::IHostapd::castFrom(hostapd);
+ return hostapd_1_3.get() != nullptr;
+}
+
/*
* RegisterCallback
*/
TEST_P(HostapdHidlTest, registerCallback) {
+ if (is_1_3(hostapd_)) GTEST_SKIP() << "Ignore since current HIDL over 1.3";
hostapd_->registerCallback(
new IfaceCallback(), [](const HostapdStatus& status) {
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp
index cec1782..577174b 100644
--- a/wifi/hostapd/1.2/vts/functional/Android.bp
+++ b/wifi/hostapd/1.2/vts/functional/Android.bp
@@ -25,12 +25,15 @@
"VtsHalWifiHostapdV1_0TargetTestUtil",
"android.hardware.wifi.hostapd@1.0",
"android.hardware.wifi.hostapd@1.1",
- "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.hostapd@1.3",
"android.hardware.wifi@1.0",
"libgmock",
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
-
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index 99784a4..c40c582 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
#include "hostapd_hidl_call_util.h"
#include "hostapd_hidl_test_utils.h"
@@ -216,12 +217,20 @@
std::string hostapd_instance_name_;
};
+bool is_1_3(const sp<IHostapd>& hostapd) {
+ sp<::android::hardware::wifi::hostapd::V1_3::IHostapd> hostapd_1_3 =
+ ::android::hardware::wifi::hostapd::V1_3::IHostapd::castFrom(hostapd);
+ return hostapd_1_3.get() != nullptr;
+}
+
/**
* Adds an access point with PSK network config & ACS enabled.
* Access point creation should pass.
*/
TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithAcs(), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -233,6 +242,8 @@
*/
TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
@@ -245,6 +256,8 @@
*/
TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) {
if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithAcsAndInvalidFreqRange(),
getPskNwParams());
@@ -257,6 +270,8 @@
*/
TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithAcs(), getOpenNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -267,6 +282,8 @@
* Access point creation should pass.
*/
TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithoutAcs(), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -277,6 +294,8 @@
* Access point creation should pass.
*/
TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithoutAcs(), getOpenNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -288,6 +307,8 @@
*/
TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) {
if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
getSaeTransitionNwParams());
@@ -300,6 +321,8 @@
*/
TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) {
if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithoutAcs(), getSaeNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -311,6 +334,8 @@
*/
TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithAcs(), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
@@ -326,6 +351,8 @@
* Access point creation & removal should pass.
*/
TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithoutAcs(), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
@@ -341,6 +368,8 @@
* Access point creation should fail.
*/
TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
getIfaceParamsWithInvalidChannel(), getPskNwParams());
@@ -352,6 +381,8 @@
* Access point creation should fail.
*/
TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
getInvalidPskNwParams());
@@ -364,6 +395,8 @@
*/
TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) {
if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
getInvalidSaeTransitionNwParams());
@@ -376,6 +409,8 @@
*/
TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) {
if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
getInvalidSaeNwParams());
@@ -398,6 +433,8 @@
* when hotspot interface available.
*/
TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
+ if (is_1_3(hostapd_))
+ GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
auto status_1_2 =
HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
getOpenNwParams());
diff --git a/wifi/hostapd/1.3/Android.bp b/wifi/hostapd/1.3/Android.bp
new file mode 100644
index 0000000..31faa6a
--- /dev/null
+++ b/wifi/hostapd/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.hostapd@1.3",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "IHostapd.hal",
+ "IHostapdCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.hostapd@1.0",
+ "android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+}
diff --git a/wifi/hostapd/1.3/IHostapd.hal b/wifi/hostapd/1.3/IHostapd.hal
new file mode 100644
index 0000000..0309f3b
--- /dev/null
+++ b/wifi/hostapd/1.3/IHostapd.hal
@@ -0,0 +1,79 @@
+/*
+ * 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.hostapd@1.3;
+
+import @1.2::HostapdStatus;
+import @1.2::IHostapd.IfaceParams;
+import @1.2::IHostapd.NetworkParams;
+import @1.2::IHostapd;
+import IHostapdCallback;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.2::IHostapd {
+ /**
+ * Parameters to use for setting up the access point network.
+ */
+ struct NetworkParams {
+ /**
+ * Baseline information as defined in HAL 1.2.
+ */
+ @1.2::IHostapd.NetworkParams V1_2;
+
+ /**
+ * Enable the interworking service and set access network type to
+ * CHARGEABLE_PUBLIC_NETWORK when set to true.
+ */
+ bool isMetered;
+ };
+
+ /**
+ * Adds a new access point for hostapd to control.
+ *
+ * This should trigger the setup of an access point with the specified
+ * interface and network params.
+ *
+ * @param ifaceParams AccessPoint Params for the access point.
+ * @param nwParams Network Params for the access point.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|,
+ * |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+ */
+ addAccessPoint_1_3(@1.2::IHostapd.IfaceParams ifaceParams, NetworkParams nwParams)
+ generates (HostapdStatus status);
+
+ /**
+ * Register for callbacks from the hostapd service.
+ *
+ * These callbacks are invoked for global events that are not specific
+ * to any interface or network. Registration of multiple callback
+ * objects is supported. These objects must be deleted when the corresponding
+ * client process is dead.
+ *
+ * @param callback An instance of the |IHostapdCallback| HIDL interface
+ * object.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|
+ */
+ registerCallback_1_3(IHostapdCallback callback) generates (HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.3/IHostapdCallback.hal b/wifi/hostapd/1.3/IHostapdCallback.hal
new file mode 100644
index 0000000..a098d87
--- /dev/null
+++ b/wifi/hostapd/1.3/IHostapdCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.hostapd@1.3;
+
+import @1.1::IHostapdCallback;
+import @1.2::MacAddress;
+import Bandwidth;
+import Generation;
+
+/**
+ * Top-level callback object for managing SoftAPs.
+ */
+interface IHostapdCallback extends @1.1::IHostapdCallback {
+ /**
+ * Invoked when information changes for one of the AP instances.
+ *
+ * @param ifaceName Name of the interface which was added via
+ * |IHostapd.addAccessPoint|.
+ * @param apIfaceInstance The identity of the AP instance. The interface
+ * will have two instances (e.q. 2.4 Ghz AP and 5 GHz AP) in dual AP mode.
+ * The apIfaceInstance can be used to identify which instance the callback
+ * is from.
+ * Note: The apIfaceInstance must be same as ifaceName in single AP mode.
+ * @param freq The operational frequency of the AP.
+ * @param bandwidth The operational bandwidth of the AP.
+ * @param generation The operational mode of the AP (e.g. 11ac, 11ax).
+ * @param apIfaceInstanceMacAddress MAC Address of the apIfaceInstance.
+ */
+ oneway onApInstanceInfoChanged(string ifaceName, string apIfaceInstance, uint32_t freq,
+ Bandwidth bandwidth, Generation generation, MacAddress apIfaceInstanceMacAddress);
+
+ /**
+ * Invoked when a client connects/disconnects from the hotspot.
+ *
+ * @param ifaceName Name of the interface which was added via
+ * |IHostapd.addAccessPoint|.
+ * @param apIfaceInstance The identity of the AP instance. The interface
+ * will have two instances in dual AP mode. The apIfaceInstance can be used
+ * to identify which instance the callback is from.
+ * Note: The apIfaceInstance must be same as ifaceName in single AP mode.
+ * @param clientAddress MAC Address of hotspot client.
+ * @param isConnected true when client connected, false when client
+ * disconnected.
+ */
+ oneway onConnectedClientsChanged(string ifaceName, string apIfaceInstance,
+ MacAddress clientAddress, bool isConnected);
+};
diff --git a/wifi/hostapd/1.3/types.hal b/wifi/hostapd/1.3/types.hal
new file mode 100644
index 0000000..de85043
--- /dev/null
+++ b/wifi/hostapd/1.3/types.hal
@@ -0,0 +1,49 @@
+/*
+ * 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.hostapd@1.3;
+
+/**
+ * The wifi operational mode of the AP.
+ * It depends on hw mode and HT/VHT capabilities in hostapd.
+ *
+ * WIFI_STANDARD_LEGACY = (hw_mode is HOSTAPD_MODE_IEEE80211B) or
+ * (hw_mode is HOSTAPD_MODE_IEEE80211G and HT is 0).
+ * WIFI_STANDARD_11N = [hw_mode is HOSTAPD_MODE_IEEE80211G and (HT is 1 or HT40 is 1)] or
+ * [hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 0].
+ * WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
+ * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211AX.
+ */
+enum Generation : uint32_t {
+ WIFI_STANDARD_UNKNOWN = -1,
+ WIFI_STANDARD_LEGACY = 0,
+ WIFI_STANDARD_11N = 1,
+ WIFI_STANDARD_11AC = 2,
+ WIFI_STANDARD_11AX = 3,
+};
+
+/**
+ * The channel bandwidth of the AP.
+ */
+enum Bandwidth : uint32_t {
+ WIFI_BANDWIDTH_INVALID = 0,
+ WIFI_BANDWIDTH_20_NOHT = 1,
+ WIFI_BANDWIDTH_20 = 2,
+ WIFI_BANDWIDTH_40 = 3,
+ WIFI_BANDWIDTH_80 = 4,
+ WIFI_BANDWIDTH_80P80 = 5,
+ WIFI_BANDWIDTH_160 = 6,
+};
diff --git a/wifi/1.4/default/OWNERS b/wifi/hostapd/1.3/vts/OWNERS
similarity index 100%
copy from wifi/1.4/default/OWNERS
copy to wifi/hostapd/1.3/vts/OWNERS
diff --git a/wifi/hostapd/1.3/vts/functional/Android.bp b/wifi/hostapd/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..07cebb0
--- /dev/null
+++ b/wifi/hostapd/1.3/vts/functional/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_test {
+ name: "VtsHalWifiHostapdV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "hostapd_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiHostapdV1_0TargetTestUtil",
+ "android.hardware.wifi.hostapd@1.0",
+ "android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.hostapd@1.3",
+ "android.hardware.wifi@1.0",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/wifi/hostapd/1.3/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.3/vts/functional/hostapd_hidl_test.cpp
new file mode 100644
index 0000000..d6c750f
--- /dev/null
+++ b/wifi/hostapd/1.3/vts/functional/hostapd_hidl_test.cpp
@@ -0,0 +1,433 @@
+/*
+ * 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 <VtsCoreUtil.h>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
+
+#include "hostapd_hidl_call_util.h"
+#include "hostapd_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::hostapd::V1_2::DebugLevel;
+using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode;
+using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
+using ::android::hardware::wifi::hostapd::V1_3::IHostapd;
+using ::android::hardware::wifi::V1_0::IWifi;
+
+namespace {
+constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
+ '2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
+constexpr char kInvalidMaxPskNwPassphrase[] =
+ "0123456789012345678901234567890123456789012345678901234567890123456789";
+constexpr char kInvalidMinPskNwPassphrase[] = "test";
+constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
+constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
+constexpr Ieee80211ReasonCode kTestDisconnectReasonCode =
+ Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
+} // namespace
+
+class HostapdHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_instance_name_ = std::get<0>(GetParam());
+ hostapd_instance_name_ = std::get<1>(GetParam());
+ stopSupplicantIfNeeded(wifi_instance_name_);
+ startHostapdAndWaitForHidlService(wifi_instance_name_,
+ hostapd_instance_name_);
+ hostapd_ = IHostapd::getService(hostapd_instance_name_);
+ ASSERT_NE(hostapd_.get(), nullptr);
+ HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE);
+ isAcsSupport_ = testing::checkSubstringInCommandOutput(
+ "/system/bin/cmd wifi get-softap-supported-features",
+ "wifi_softap_acs_supported");
+ isWpa3SaeSupport_ = testing::checkSubstringInCommandOutput(
+ "/system/bin/cmd wifi get-softap-supported-features",
+ "wifi_softap_wpa3_sae_supported");
+ }
+
+ virtual void TearDown() override {
+ HIDL_INVOKE_VOID_WITHOUT_ARGUMENTS(hostapd_, terminate);
+ stopHostapd(wifi_instance_name_);
+ }
+
+ protected:
+ bool isWpa3SaeSupport_ = false;
+ bool isAcsSupport_ = false;
+ std::string getPrimaryWlanIfaceName() {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(),
+ nullptr);
+ if (res > 0) return buffer.data();
+ property_get("wifi.interface", buffer.data(), "wlan0");
+ return buffer.data();
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
+ ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
+ iface_params;
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
+ iface_params_1_1;
+ IHostapd::IfaceParams iface_params_1_2;
+
+ iface_params.ifaceName = getPrimaryWlanIfaceName();
+ iface_params.hwModeParams.enable80211N = true;
+ iface_params.hwModeParams.enable80211AC = false;
+ iface_params.channelParams.enableAcs = false;
+ iface_params.channelParams.acsShouldExcludeDfs = false;
+ iface_params.channelParams.channel = kIfaceChannel;
+ iface_params_1_1.V1_0 = iface_params;
+ iface_params_1_2.V1_1 = iface_params_1_1;
+ // Newly added attributes in V1_2
+ iface_params_1_2.hwModeParams.enable80211AX = false;
+ iface_params_1_2.hwModeParams.enable6GhzBand = false;
+ iface_params_1_2.channelParams.bandMask = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_2_GHZ;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcs() {
+ // First get the settings for WithoutAcs and then make changes
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_5_GHZ;
+
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+ ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
+ acsFrequencyRange;
+ acsFrequencyRange.start = 2412;
+ acsFrequencyRange.end = 2462;
+ std::vector<::android::hardware::wifi::hostapd::V1_2::IHostapd::
+ AcsFrequencyRange>
+ vec_acsFrequencyRange;
+ vec_acsFrequencyRange.push_back(acsFrequencyRange);
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz =
+ vec_acsFrequencyRange;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcsAndFreqRange();
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
+ return iface_params_1_2;
+ }
+
+ IHostapd::NetworkParams getOpenNwParams() {
+ IHostapd::NetworkParams nw_params_1_3;
+ ::android::hardware::wifi::hostapd::V1_2::IHostapd::NetworkParams
+ nw_params_1_2;
+ ::android::hardware::wifi::hostapd::V1_0::IHostapd::NetworkParams
+ nw_params_1_0;
+ nw_params_1_0.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params_1_0.isHidden = false;
+ nw_params_1_2.V1_0 = nw_params_1_0;
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::NONE;
+ nw_params_1_3.V1_2 = nw_params_1_2;
+ nw_params_1_3.isMetered = true;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getPskNwParamsWithNonMetered() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_3.V1_2.passphrase = kNwPassphrase;
+ nw_params_1_3.isMetered = false;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getPskNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_3.V1_2.passphrase = kNwPassphrase;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getInvalidPskNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_3.V1_2.passphrase = kInvalidMaxPskNwPassphrase;
+
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getSaeTransitionNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType =
+ IHostapd::EncryptionType::WPA3_SAE_TRANSITION;
+ nw_params_1_3.V1_2.passphrase = kNwPassphrase;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getInvalidSaeTransitionNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_3.V1_2.passphrase = kInvalidMinPskNwPassphrase;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getSaeNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+ nw_params_1_3.V1_2.passphrase = kNwPassphrase;
+ return nw_params_1_3;
+ }
+
+ IHostapd::NetworkParams getInvalidSaeNwParams() {
+ IHostapd::NetworkParams nw_params_1_3 = getOpenNwParams();
+ nw_params_1_3.V1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+ nw_params_1_3.V1_2.passphrase = "";
+ return nw_params_1_3;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
+ return iface_params_1_2;
+ }
+
+ // IHostapd object used for all tests in this fixture.
+ sp<IHostapd> hostapd_;
+ std::string wifi_instance_name_;
+ std::string hostapd_instance_name_;
+};
+
+/**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+ if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS enabled & frequency Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
+ if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel range.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) {
+ if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithAcsAndInvalidFreqRange(),
+ getPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+ if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithAcs(), getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS disabled & Non metered.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcsAndNonMetered) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getPskNwParamsWithNonMetered());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithoutAcs(), getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with SAE Transition network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) {
+ if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getSaeTransitionNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with SAE network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) {
+ if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithoutAcs(), getSaeNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+ if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+ auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+ auto status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(
+ android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+ status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+ auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+ auto status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(
+ android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+ status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3,
+ getIfaceParamsWithInvalidChannel(), getPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getInvalidPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid SAE transition network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) {
+ if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getInvalidSaeTransitionNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid SAE network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) {
+ if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getInvalidSaeNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * forceClientDisconnect should return FAILURE_CLIENT_UNKNOWN
+ * when hotspot interface available.
+ */
+TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
+ auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_3, getIfaceParamsWithoutAcs(),
+ getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+
+ status_1_2 =
+ HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+ kTestZeroMacAddr, kTestDisconnectReasonCode);
+ EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HostapdHidlTest);
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, HostapdHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::hostapd::V1_2::IHostapd::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 5e7a371..be6aad9 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -283,3 +283,17 @@
});
return !operation_failed;
}
+
+bool waitForFrameworkReady() {
+ int waitCount = 10;
+ do {
+ // Check whether package service is ready or not.
+ if (!testing::checkSubstringInCommandOutput(
+ "/system/bin/service check package", ": not found")) {
+ return true;
+ }
+ LOG(INFO) << "Framework is not ready";
+ sleep(1);
+ } while (waitCount-- > 0);
+ return false;
+}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 1ccf091..33945cc 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -17,6 +17,8 @@
#ifndef SUPPLICANT_HIDL_TEST_UTILS_H
#define SUPPLICANT_HIDL_TEST_UTILS_H
+#include <VtsCoreUtil.h>
+#include <android-base/logging.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
@@ -62,4 +64,51 @@
bool turnOnExcessiveLogging();
+bool waitForFrameworkReady();
+
+class SupplicantHidlTestBase
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ // should always be v1.0 wifi
+ wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ supplicant_instance_name_ = std::get<1>(GetParam());
+ std::system("/system/bin/start");
+ ASSERT_TRUE(waitForFrameworkReady());
+
+ isP2pOn_ =
+ testing::deviceSupportsFeature("android.hardware.wifi.direct");
+ // Stop Framework
+ std::system("/system/bin/stop");
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_instance_name_);
+ LOG(INFO) << "SupplicantHidlTestBase isP2pOn_: " << isP2pOn_;
+ }
+
+ virtual void TearDown() override {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ // Start Framework
+ std::system("/system/bin/start");
+ }
+
+ protected:
+ bool isP2pOn_ = false;
+ std::string wifi_v1_0_instance_name_;
+ std::string supplicant_instance_name_;
+};
+
+class SupplicantHidlTestBaseV1_0 : public SupplicantHidlTestBase {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBase::SetUp();
+ supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+ ASSERT_NE(supplicant_.get(), nullptr);
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ }
+
+ protected:
+ android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
+ supplicant_;
+};
#endif /* SUPPLICANT_HIDL_TEST_UTILS_H */
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 616869b..325f355 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -71,21 +71,13 @@
constexpr SupplicantNetworkId kTestNetworkId = 5;
} // namespace
-class SupplicantP2pIfaceHidlTest
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBaseV1_0 {
public:
virtual void SetUp() override {
- wifi_instance_name_ = std::get<0>(GetParam());
- supplicant_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
- supplicant_instance_name_);
- supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_0::SetUp();
+ if (!isP2pOn_) {
+ GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
+ }
p2p_iface_ = getSupplicantP2pIface(supplicant_);
ASSERT_NE(p2p_iface_.get(), nullptr);
@@ -93,22 +85,11 @@
memcpy(peer_mac_addr_.data(), kTestPeerMacAddr, peer_mac_addr_.size());
}
- virtual void TearDown() override {
- stopSupplicant(wifi_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
- bool isP2pOn_ = false;
- sp<ISupplicant> supplicant_;
- // ISupplicantP2pIface object used for all tests in this fixture.
sp<ISupplicantP2pIface> p2p_iface_;
// MAC address to use for various tests.
std::array<uint8_t, 6> mac_addr_;
std::array<uint8_t, 6> peer_mac_addr_;
- std::string wifi_instance_name_;
- std::string supplicant_instance_name_;
};
class IfaceCallback : public ISupplicantP2pIfaceCallback {
@@ -201,8 +182,8 @@
* successfully created.
*/
TEST_P(SupplicantP2pIfaceHidlTest, Create) {
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
supplicant_instance_name_);
sp<ISupplicantP2pIface> p2p_iface = getSupplicantP2pIface(
getSupplicant(supplicant_instance_name_, isP2pOn_));
@@ -301,8 +282,17 @@
mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
kTestConnectPin, false, false, kTestConnectGoIntent,
[](const SupplicantStatus& status, const hidl_string& /* pin */) {
- // This is not going to work with fake values.
- EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ /*
+ * Before R, auto-join is not enabled and it is not going to work
+ * with fake values. After enabling auto-join, it will succeed
+ * always.
+ */
+ LOG(INFO) << "ISupplicantP2pIface::connect() ret: "
+ << toString(status);
+ if (SupplicantStatusCode::FAILURE_UNKNOWN != status.code &&
+ SupplicantStatusCode::SUCCESS != status.code) {
+ FAIL();
+ }
});
}
@@ -314,12 +304,26 @@
mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
kTestConnectPin, false, false, kTestConnectGoIntent,
[](const SupplicantStatus& status, const hidl_string& /* pin */) {
- // This is not going to work with fake values.
- EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ /*
+ * Before R, auto-join is not enabled and it is not going to work
+ * with fake values. After enabling auto-join, it will succeed
+ * always.
+ */
+ LOG(INFO) << "ISupplicantP2pIface::connect() ret: "
+ << toString(status);
+ if (SupplicantStatusCode::FAILURE_UNKNOWN != status.code &&
+ SupplicantStatusCode::SUCCESS != status.code) {
+ FAIL();
+ }
});
p2p_iface_->cancelConnect([](const SupplicantStatus& status) {
- EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ LOG(INFO) << "ISupplicantP2pIface::cancelConnect() ret: "
+ << toString(status);
+ if (SupplicantStatusCode::FAILURE_UNKNOWN != status.code &&
+ SupplicantStatusCode::SUCCESS != status.code) {
+ FAIL();
+ }
});
}
@@ -655,4 +659,4 @@
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
ISupplicant::descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+ android::hardware::PrintInstanceTupleNameToString<>);
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 e4fe52c..6b85e00 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
@@ -66,42 +66,22 @@
constexpr uint16_t kTestWpsConfigMethods = 0xffff;
} // namespace
-class SupplicantStaIfaceHidlTest
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBaseV1_0 {
public:
virtual void SetUp() override {
- wifi_instance_name_ = std::get<0>(GetParam());
- supplicant_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
- supplicant_instance_name_);
- supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_0::SetUp();
sta_iface_ = getSupplicantStaIface(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
}
- virtual void TearDown() override {
- stopSupplicant(wifi_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
bool isP2pOn_ = false;
- sp<ISupplicant> supplicant_;
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
// MAC address to use for various tests.
std::array<uint8_t, 6> mac_addr_;
- std::string wifi_instance_name_;
- std::string supplicant_instance_name_;
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -183,8 +163,8 @@
* successfully created.
*/
TEST_P(SupplicantStaIfaceHidlTest, Create) {
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
supplicant_instance_name_);
EXPECT_NE(nullptr, getSupplicantStaIface(
getSupplicant(supplicant_instance_name_, isP2pOn_))
@@ -566,4 +546,4 @@
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
ISupplicant::descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
index 7e93c5f..2b4d681 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -79,21 +79,10 @@
ISupplicantStaNetwork::PairwiseCipherMask::TKIP);
} // namespace
-class SupplicantStaNetworkHidlTest
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_0 {
public:
virtual void SetUp() override {
- wifi_instance_name_ = std::get<0>(GetParam());
- supplicant_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
- supplicant_instance_name_);
- supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_0::SetUp();
sta_network_ = createSupplicantStaNetwork(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
/* variable used to check if the underlying HAL version is 1.3 or
@@ -105,12 +94,6 @@
ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr));
}
- virtual void TearDown() override {
- stopSupplicant(wifi_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
void removeNetwork() {
sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant_);
@@ -128,14 +111,10 @@
sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
v1_3 = nullptr;
- bool isP2pOn_ = false;
- sp<ISupplicant> supplicant_;
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
// SSID to use for various tests.
std::vector<uint8_t> ssid_;
- std::string wifi_instance_name_;
- std::string supplicant_instance_name_;
};
class NetworkCallback : public ISupplicantStaNetworkCallback {
@@ -158,8 +137,8 @@
* successfully created.
*/
TEST_P(SupplicantStaNetworkHidlTest, Create) {
- stopSupplicant(wifi_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_instance_name_,
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
supplicant_instance_name_);
sp<ISupplicant> supplicant =
getSupplicant(supplicant_instance_name_, isP2pOn_);
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 76d12d7..8d7ea54 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -36,9 +36,9 @@
using ::android::hardware::wifi::V1_0::IWifi;
using ::android::sp;
-class SupplicantHidlTest : public SupplicantHidlTestBase {
+class SupplicantHidlTest : public SupplicantHidlTestBaseV1_1 {
public:
- virtual void SetUp() override { SupplicantHidlTestBase::SetUp(); }
+ virtual void SetUp() override { SupplicantHidlTestBaseV1_1::SetUp(); }
protected:
std::string getWlan0IfaceName() {
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
index 2104794..b6feb41 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
@@ -36,34 +36,15 @@
const android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>&
supplicant);
-class SupplicantHidlTestBase
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantHidlTestBaseV1_1 : public SupplicantHidlTestBase {
public:
virtual void SetUp() override {
- wifi_v1_0_instance_name_ = std::get<0>(GetParam());
- supplicant_v1_1_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
- stopSupplicant(wifi_v1_0_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
- supplicant_v1_1_instance_name_);
- supplicant_ =
- getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+ SupplicantHidlTestBase::SetUp();
+ supplicant_ = getSupplicant_1_1(supplicant_instance_name_, isP2pOn_);
ASSERT_NE(supplicant_.get(), nullptr);
}
- virtual void TearDown() override {
- stopSupplicant(wifi_v1_0_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
supplicant_;
- bool isP2pOn_ = false;
- std::string wifi_v1_0_instance_name_;
- std::string supplicant_v1_1_instance_name_;
};
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 2fade44..db6323c 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
@@ -39,11 +39,10 @@
using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
-class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBaseV1_1 {
public:
virtual void SetUp() override {
- SupplicantHidlTestBase::SetUp();
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_1::SetUp();
sta_iface_ = getSupplicantStaIface_1_1(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
}
@@ -149,4 +148,4 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
android::hardware::wifi::supplicant::V1_1::ISupplicant::
descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
index bd8a2ab..37641a4 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -37,11 +37,10 @@
constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
} // namespace
-class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_1 {
public:
virtual void SetUp() override {
- SupplicantHidlTestBase::SetUp();
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_1::SetUp();
sta_network_ = createSupplicantStaNetwork_1_1(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
}
@@ -59,9 +58,9 @@
TEST_P(SupplicantStaNetworkHidlTest, Create) {
stopSupplicant(wifi_v1_0_instance_name_);
startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
- supplicant_v1_1_instance_name_);
+ supplicant_instance_name_);
sp<ISupplicant> supplicant =
- getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+ getSupplicant_1_1(supplicant_instance_name_, isP2pOn_);
EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1(supplicant).get());
}
@@ -102,4 +101,4 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
android::hardware::wifi::supplicant::V1_1::ISupplicant::
descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
index 2a432d0..b9c5ade 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
@@ -42,35 +42,16 @@
const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
supplicant);
-class SupplicantHidlTestBase
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantHidlTestBaseV1_2 : public SupplicantHidlTestBase {
public:
virtual void SetUp() override {
- wifi_v1_0_instance_name_ = std::get<0>(GetParam());
- supplicant_v1_2_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
- stopSupplicant(wifi_v1_0_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
- supplicant_v1_2_instance_name_);
- supplicant_ =
- getSupplicant_1_2(supplicant_v1_2_instance_name_, isP2pOn_);
+ SupplicantHidlTestBase::SetUp();
+ supplicant_ = getSupplicant_1_2(supplicant_instance_name_, isP2pOn_);
ASSERT_NE(supplicant_.get(), nullptr);
EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
}
- virtual void TearDown() override {
- stopSupplicant(wifi_v1_0_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>
supplicant_;
- bool isP2pOn_ = false;
- std::string wifi_v1_0_instance_name_;
- std::string supplicant_v1_2_instance_name_;
};
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 75512d7..7884cc6 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -38,11 +38,10 @@
constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
} // namespace
-class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBase {
+class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBaseV1_2 {
public:
virtual void SetUp() override {
- SupplicantHidlTestBase::SetUp();
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_2::SetUp();
if (!isP2pOn_) {
GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
}
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 184543b..cd08468 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
@@ -53,11 +53,10 @@
#define TIMEOUT_PERIOD 60
class IfaceDppCallback;
-class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBaseV1_2 {
public:
virtual void SetUp() override {
- SupplicantHidlTestBase::SetUp();
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_2::SetUp();
sta_iface_ = getSupplicantStaIface_1_2(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
count_ = 0;
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
index 5a2f808..ee5de69 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -37,10 +37,10 @@
// constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
//} // namespace
-class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_2 {
public:
virtual void SetUp() override {
- SupplicantHidlTestBase::SetUp();
+ SupplicantHidlTestBaseV1_2::SetUp();
sta_network_ = createSupplicantStaNetwork_1_2(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
index 69fc598..b28c5a4 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
@@ -34,4 +34,17 @@
bool isFilsSupported(
android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface>
sta_iface);
+
+class SupplicantHidlTestBaseV1_3 : public SupplicantHidlTestBase {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBase::SetUp();
+ supplicant_ = getSupplicant_1_3(supplicant_instance_name_, isP2pOn_);
+ ASSERT_NE(supplicant_.get(), nullptr);
+ }
+
+ protected:
+ android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>
+ supplicant_;
+};
#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 504ccc4..6dc267c 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -55,33 +55,14 @@
#define TIMEOUT_PERIOD 60
class IfaceDppCallback;
-class SupplicantStaIfaceHidlTest
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBaseV1_3 {
public:
virtual void SetUp() override {
- wifi_v1_0_instance_name_ = std::get<0>(GetParam());
- supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
-
- stopSupplicant(wifi_v1_0_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
- supplicant_v1_3_instance_name_);
- supplicant_ =
- getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_3::SetUp();
sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
}
- virtual void TearDown() override {
- stopSupplicant(wifi_v1_0_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
int64_t pmkCacheExpirationTimeInSec;
std::vector<uint8_t> serializedPmkCacheEntry;
@@ -127,10 +108,6 @@
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
- sp<ISupplicant> supplicant_;
- bool isP2pOn_ = false;
- std::string wifi_v1_0_instance_name_;
- std::string supplicant_v1_3_instance_name_;
bool isDppSupported() {
uint32_t keyMgmtMask = 0;
@@ -353,7 +330,11 @@
sta_iface_->getConnectionCapabilities(
[&](const SupplicantStatus& status,
ConnectionCapabilities /* capabilities */) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ // Since getConnectionCapabilities() is overridden by an
+ // upgraded API in newer HAL versions, allow for FAILURE_UNKNOWN
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ }
});
}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 11c55a6..12d8d0d 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -43,43 +43,20 @@
constexpr OcspType kTestInvalidOcspType = (OcspType)-1;
} // namespace
-class SupplicantStaNetworkHidlTest
- : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_3 {
public:
virtual void SetUp() override {
- wifi_v1_0_instance_name_ = std::get<0>(GetParam());
- supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
- isP2pOn_ =
- testing::deviceSupportsFeature("android.hardware.wifi.direct");
- // Stop Framework
- std::system("/system/bin/stop");
-
- stopSupplicant(wifi_v1_0_instance_name_);
- startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
- supplicant_v1_3_instance_name_);
- supplicant_ =
- getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
- EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ SupplicantHidlTestBaseV1_3::SetUp();
sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
ASSERT_NE(nullptr, sta_iface_.get());
sta_network_ = createSupplicantStaNetwork_1_3(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
}
- virtual void TearDown() override {
- stopSupplicant(wifi_v1_0_instance_name_);
- // Start Framework
- std::system("/system/bin/start");
- }
-
protected:
sp<ISupplicantStaIface> sta_iface_;
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
- sp<ISupplicant> supplicant_;
- bool isP2pOn_ = false;
- std::string wifi_v1_0_instance_name_;
- std::string supplicant_v1_3_instance_name_;
bool isWapiSupported() {
uint32_t keyMgmtMask = 0;
diff --git a/wifi/supplicant/1.4/Android.bp b/wifi/supplicant/1.4/Android.bp
new file mode 100644
index 0000000..0a039de
--- /dev/null
+++ b/wifi/supplicant/1.4/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.supplicant@1.4",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ "ISupplicant.hal",
+ "ISupplicantP2pIface.hal",
+ "ISupplicantStaIface.hal",
+ "ISupplicantStaNetwork.hal",
+ "ISupplicantStaNetworkCallback.hal",
+ ],
+ interfaces: [
+ "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@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+}
diff --git a/wifi/supplicant/1.4/ISupplicant.hal b/wifi/supplicant/1.4/ISupplicant.hal
new file mode 100644
index 0000000..9cb88ba
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicant.hal
@@ -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.wifi.supplicant@1.4;
+
+import @1.3::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.4 features you must cast specific interfaces returned from the
+ * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_0::ISupplicantIface,
+ * which can be cast to V1_4::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.3::ISupplicant {};
diff --git a/wifi/supplicant/1.4/ISupplicantP2pIface.hal b/wifi/supplicant/1.4/ISupplicantP2pIface.hal
new file mode 100644
index 0000000..7c41d1c
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantP2pIface.hal
@@ -0,0 +1,52 @@
+/*
+ * 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.supplicant@1.4;
+
+import @1.2::ISupplicantP2pIface;
+import @1.0::SupplicantStatus;
+
+/**
+ * Interface exposed by the supplicant for each P2P mode network
+ * interface (e.g p2p0) it controls.
+ * To use 1.4 features you must cast specific interfaces returned from the
+ * 1.4 HAL. For example V1_4::ISupplicant::addIface() adds V1_4::ISupplicantIface,
+ * which can be cast to V1_4::ISupplicantP2pIface.
+ */
+interface ISupplicantP2pIface extends @1.2::ISupplicantP2pIface {
+ /**
+ * Set whether to enable EDMG(802.11ay). Only allowed if hw mode is |HOSTAPD_MODE_IEEE80211AD|
+ *
+ * @param enable true to set, false otherwise.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setEdmg(bool enable) generates (SupplicantStatus status);
+
+ /**
+ * Get whether EDMG(802.11ay) is enabled for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return enabled true if set, false otherwise.
+ */
+ getEdmg() generates (SupplicantStatus status, bool enabled);
+};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIface.hal b/wifi/supplicant/1.4/ISupplicantStaIface.hal
new file mode 100644
index 0000000..28ef912
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantStaIface.hal
@@ -0,0 +1,39 @@
+/*
+ * 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.supplicant@1.4;
+
+import @1.0::SupplicantStatus;
+import @1.3::ISupplicantStaIface;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.3::ISupplicantStaIface {
+
+ /**
+ * Get Connection capabilities
+ *
+ * @return status Status of the operation, and connection capabilities.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ */
+ getConnectionCapabilities_1_4()
+ generates (SupplicantStatus status, ConnectionCapabilities capabilities);
+
+};
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..f12ace4
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
@@ -0,0 +1,146 @@
+/*
+ * 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.supplicant@1.4;
+
+import @1.3::ISupplicantStaNetwork;
+import @1.4::ISupplicantStaNetworkCallback;
+import @1.0::SupplicantStatus;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.3::ISupplicantStaNetwork {
+ /**
+ * Possible mask of values for PairwiseCipher param.
+ */
+ enum PairwiseCipherMask : @1.3::ISupplicantStaNetwork.PairwiseCipherMask {
+ /**
+ * GCMP-128 Pairwise Cipher
+ */
+ GCMP_128 = 1 << 9,
+ };
+
+ /**
+ * Possible mask of values for GroupCipher param.
+ */
+ enum GroupCipherMask : @1.3::ISupplicantStaNetwork.GroupCipherMask {
+ /**
+ * GCMP-128 Group Cipher
+ */
+ GCMP_128 = 1 << 9,
+ };
+
+ /**
+ * Set group cipher mask for the network.
+ *
+ * @param groupCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setGroupCipher_1_4(bitfield<GroupCipherMask> groupCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the group cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return groupCipherMask Combination of |GroupCipherMask| values.
+ */
+ getGroupCipher_1_4()
+ generates (SupplicantStatus status, bitfield<GroupCipherMask> groupCipherMask);
+
+ /**
+ * Set pairwise cipher mask for the network.
+ *
+ * @param pairwiseCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setPairwiseCipher_1_4(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the pairwise cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+ */
+ getPairwiseCipher_1_4()
+ generates (SupplicantStatus status, bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+ /**
+ * Set whether to enable enhanced directional multi-gigabit (802.11ay EDMG).
+ * Only allowed if hw mode is |HOSTAPD_MODE_IEEE80211AD|
+ *
+ * @param enable true to set, false otherwise.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setEdmg(bool enable) generates (SupplicantStatus status);
+
+ /**
+ * Get whether enhanced directional multi-gigabit (802.11ay EDMG) is enabled for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return enabled true if set, false otherwise.
+ */
+ getEdmg() generates (SupplicantStatus status, bool enabled);
+
+ /**
+ * Register for callbacks from this network.
+ *
+ * These callbacks are invoked for events that are specific to this network.
+ * Registration of multiple callback objects is supported. These objects must
+ * be automatically deleted when the corresponding client process is dead or
+ * if this network is removed.
+ *
+ * @param callback An instance of the |ISupplicantStaNetworkCallback| HIDL
+ * interface object.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ registerCallback_1_4(ISupplicantStaNetworkCallback callback)
+ generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetworkCallback.hal b/wifi/supplicant/1.4/ISupplicantStaNetworkCallback.hal
new file mode 100644
index 0000000..38cdcf9
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantStaNetworkCallback.hal
@@ -0,0 +1,46 @@
+/*
+ * 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.supplicant@1.4;
+
+import @1.0::ISupplicantStaNetworkCallback;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each network (ISupplicantStaNetwork).
+ *
+ * Clients need to host an instance of this HIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaNetwork.registerCallback_1_4| method.
+ */
+interface ISupplicantStaNetworkCallback extends @1.0::ISupplicantStaNetworkCallback {
+ /**
+ * WPA3™ Specification Addendum for WPA3 R3 - Table 3.
+ * Transition Disable Indication filled in the third
+ * 4-way handshake message.
+ */
+ enum TransitionDisableIndication : uint32_t {
+ USE_WPA3_PERSONAL = 1 << 0,
+ USE_SAE_PK = 1 << 1,
+ USE_WPA3_ENTERPRISE = 1 << 2,
+ USE_ENHANCED_OPEN = 1 << 3,
+ };
+
+ /**
+ * Used to notify WPA3 transition disable.
+ */
+ oneway onTransitionDisable(bitfield<TransitionDisableIndication> ind);
+};
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
new file mode 100644
index 0000000..79e367a
--- /dev/null
+++ b/wifi/supplicant/1.4/types.hal
@@ -0,0 +1,52 @@
+/*
+ * 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.supplicant@1.4;
+
+import @1.3::ConnectionCapabilities;
+
+/**
+ * Detailed network mode for legacy network
+ */
+enum LegacyMode : uint32_t {
+ UNKNOWN = 0,
+ /**
+ * For 802.11a
+ */
+ A_MODE = 1,
+ /**
+ * For 802.11b
+ */
+ B_MODE = 2,
+ /**
+ * For 802.11g
+ */
+ G_MODE = 3,
+};
+
+/**
+ * Connection Capabilities supported by current network and device
+ */
+struct ConnectionCapabilities {
+ /**
+ * Baseline information as defined in HAL 1.3.
+ */
+ @1.3::ConnectionCapabilities V1_3;
+ /**
+ * detailed network mode for legacy network
+ */
+ LegacyMode legacyMode;
+};
diff --git a/wifi/1.4/default/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
similarity index 100%
copy from wifi/1.4/default/OWNERS
copy to wifi/supplicant/1.4/vts/OWNERS
diff --git a/wifi/supplicant/1.4/vts/functional/Android.bp b/wifi/supplicant/1.4/vts/functional/Android.bp
new file mode 100644
index 0000000..d6af0a0
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/Android.bp
@@ -0,0 +1,103 @@
+//
+// 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: "VtsHalWifiSupplicantV1_4TargetTestUtil",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["supplicant_hidl_test_utils_1_4.cpp"],
+ export_include_dirs: [
+ ".",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ "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",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+}
+
+cc_test {
+ name: "VtsHalWifiSupplicantV1_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "supplicant_sta_iface_hidl_test.cpp",
+ "supplicant_sta_network_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ "VtsHalWifiSupplicantV1_4TargetTestUtil",
+ "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",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
+
+cc_test {
+ name: "VtsHalWifiSupplicantP2pV1_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "supplicant_p2p_iface_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ "VtsHalWifiSupplicantV1_4TargetTestUtil",
+ "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",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp
new file mode 100644
index 0000000..7e7a465
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp
@@ -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.
+ */
+
+#include <android-base/logging.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantP2pIface;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+
+sp<ISupplicantStaIface> getSupplicantStaIface_1_4(
+ const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+ supplicant) {
+ return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
+}
+
+sp<ISupplicantP2pIface> getSupplicantP2pIface_1_4(
+ const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+ supplicant) {
+ return ISupplicantP2pIface::castFrom(getSupplicantP2pIface(supplicant));
+}
+
+sp<ISupplicant> getSupplicant_1_4(const std::string& supplicant_instance_name,
+ bool isP2pOn) {
+ return ISupplicant::castFrom(
+ getSupplicant(supplicant_instance_name, isP2pOn));
+}
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.h b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.h
new file mode 100644
index 0000000..b3b6990
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.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 SUPPLICANT_HIDL_TEST_UTILS_1_4_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_4_H
+
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface>
+getSupplicantStaIface_1_4(
+ const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+ supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicantP2pIface>
+getSupplicantP2pIface_1_4(
+ const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+ supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>
+getSupplicant_1_4(const std::string& supplicant_instance_name, bool isP2pOn);
+
+class SupplicantHidlTestBaseV1_4 : public SupplicantHidlTestBase {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBase::SetUp();
+ supplicant_ = getSupplicant_1_4(supplicant_instance_name_, isP2pOn_);
+ ASSERT_NE(supplicant_.get(), nullptr);
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ }
+
+ protected:
+ android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>
+ supplicant_;
+};
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_4_H */
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp
new file mode 100644
index 0000000..17e1b9f
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.4/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantP2pIface;
+
+class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBaseV1_4 {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBaseV1_4::SetUp();
+ p2p_iface_ = getSupplicantP2pIface_1_4(supplicant_);
+ ASSERT_NE(p2p_iface_.get(), nullptr);
+ }
+
+ protected:
+ // ISupplicantP2pIface object used for all tests in this fixture.
+ sp<ISupplicantP2pIface> p2p_iface_;
+};
+
+/*
+ * SetGetEdmg
+ */
+TEST_P(SupplicantP2pIfaceHidlTest, SetGetEdmg) {
+ p2p_iface_->setEdmg(true, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ p2p_iface_->getEdmg([&](const SupplicantStatus& status, bool enable) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(true, enable);
+ });
+ p2p_iface_->setEdmg(false, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ p2p_iface_->getEdmg([&](const SupplicantStatus& status, bool enable) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(false, enable);
+ });
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceHidlTest);
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantP2pIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_4::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
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
new file mode 100644
index 0000000..5b9c750
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -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.
+ */
+
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#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/types.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+using ::android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBaseV1_4 {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBaseV1_4::SetUp();
+ sta_iface_ = getSupplicantStaIface_1_4(supplicant_);
+ ASSERT_NE(sta_iface_.get(), nullptr);
+ }
+
+ protected:
+ // ISupplicantStaIface object used for all tests in this fixture.
+ sp<ISupplicantStaIface> sta_iface_;
+};
+
+/*
+ * getConnectionCapabilities_1_4
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+ sta_iface_->getConnectionCapabilities_1_4(
+ [&](const SupplicantStatus& status,
+ ConnectionCapabilities /* capabilities */) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceHidlTest);
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_4::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
new file mode 100644
index 0000000..32e4f17
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_4::
+ ISupplicantStaNetworkCallback;
+using ::android::hardware::wifi::V1_0::IWifi;
+
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_4 {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBaseV1_4::SetUp();
+ sta_network_ = createSupplicantStaNetwork(supplicant_);
+ ASSERT_NE(sta_network_.get(), nullptr);
+ /* variable used to check if the underlying HAL version is 1.4 or
+ * higher. This is to skip tests which are using deprecated methods.
+ */
+ v1_4 = ::android::hardware::wifi::supplicant::V1_4::
+ ISupplicantStaNetwork::castFrom(sta_network_);
+ }
+
+ protected:
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaNetwork>
+ v1_4 = nullptr;
+ // ISupplicantStaNetwork object used for all tests in this fixture.
+ sp<ISupplicantStaNetwork> sta_network_;
+};
+
+class NetworkCallback : public ISupplicantStaNetworkCallback {
+ Return<void> onNetworkEapSimGsmAuthRequest(
+ const ISupplicantStaNetworkCallback::NetworkRequestEapSimGsmAuthParams&
+ /* params */) override {
+ return Void();
+ }
+ Return<void> onNetworkEapSimUmtsAuthRequest(
+ const ISupplicantStaNetworkCallback::NetworkRequestEapSimUmtsAuthParams&
+ /* params */) override {
+ return Void();
+ }
+ Return<void> onNetworkEapIdentityRequest() override { return Void(); }
+ Return<void> onTransitionDisable(uint32_t /* params */) override {
+ return Void();
+ }
+};
+
+/*
+ * RegisterCallback
+ */
+TEST_P(SupplicantStaNetworkHidlTest, RegisterCallback_1_4) {
+ v1_4->registerCallback_1_4(
+ new NetworkCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkHidlTest);
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaNetworkHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ISupplicant::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);