Merge "composer 2.4: add api to control vsync period"
diff --git a/Android.bp b/Android.bp
index dd84737..70e0574 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,4 +45,5 @@
"-g",
],
+ require_root: true,
}
diff --git a/CleanSpec.mk b/CleanSpec.mk
index edde1cb..76594fb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,3 +80,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..98e125b
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "presubmit": [
+ {
+ "name": "hidl_implementation_test"
+ }
+ ]
+}
+
diff --git a/audio/4.0/config/api/current.txt b/audio/4.0/config/api/current.txt
index d59cade..3462568 100644
--- a/audio/4.0/config/api/current.txt
+++ b/audio/4.0/config/api/current.txt
@@ -114,11 +114,15 @@
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCNW;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCWB;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_FLAC;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_IEC61937;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP2;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP3;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_OPUS;
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index 58bab22..f26e41b 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -357,6 +357,10 @@
<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_1_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="extendableAudioFormat">
diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp
new file mode 100644
index 0000000..dc6bb98
--- /dev/null
+++ b/audio/6.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IDevice.hal",
+ "IDevicesFactory.hal",
+ "IPrimaryDevice.hal",
+ "IStream.hal",
+ "IStreamIn.hal",
+ "IStreamOut.hal",
+ "IStreamOutCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@6.0",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
new file mode 100644
index 0000000..42a545b
--- /dev/null
+++ b/audio/6.0/IDevice.hal
@@ -0,0 +1,282 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+ /**
+ * Returns whether the audio hardware interface has been initialized.
+ *
+ * @return retval OK on success, NOT_INITIALIZED on failure.
+ */
+ initCheck() generates (Result retval);
+
+ /**
+ * Sets the audio volume for all audio activities other than voice call. If
+ * NOT_SUPPORTED is returned, the software mixer will emulate this
+ * capability.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setMasterVolume(float volume) generates (Result retval);
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. For example, AudioFlinger will query this value
+ * from the primary audio HAL when the service starts and use the value for
+ * setting the initial master volume across all HALs. HALs which do not
+ * support this method must return NOT_SUPPORTED in 'retval'.
+ *
+ * @return retval operation completion status.
+ * @return volume 1.0f means unity, 0.0f is zero.
+ */
+ getMasterVolume() generates (Result retval, float volume);
+
+ /**
+ * Sets microphone muting state.
+ *
+ * @param mute whether microphone is muted.
+ * @return retval operation completion status.
+ */
+ setMicMute(bool mute) generates (Result retval);
+
+ /**
+ * Gets whether microphone is muted.
+ *
+ * @return retval operation completion status.
+ * @return mute whether microphone is muted.
+ */
+ getMicMute() generates (Result retval, bool mute);
+
+ /**
+ * Set the audio mute status for all audio activities. If the return value
+ * is NOT_SUPPORTED, the software mixer will emulate this capability.
+ *
+ * @param mute whether audio is muted.
+ * @return retval operation completion status.
+ */
+ setMasterMute(bool mute) generates (Result retval);
+
+ /**
+ * Get the current master mute status for the HAL, if the HAL supports
+ * master mute control. AudioFlinger will query this value from the primary
+ * audio HAL when the service starts and use the value for setting the
+ * initial master mute across all HALs. HAL must indicate that the feature
+ * is not supported by returning NOT_SUPPORTED status.
+ *
+ * @return retval operation completion status.
+ * @return mute whether audio is muted.
+ */
+ getMasterMute() generates (Result retval, bool mute);
+
+ /**
+ * Returns audio input buffer size according to parameters passed or
+ * INVALID_ARGUMENTS if one of the parameters is not supported.
+ *
+ * @param config audio configuration.
+ * @return retval operation completion status.
+ * @return bufferSize input buffer size in bytes.
+ */
+ getInputBufferSize(AudioConfig config)
+ generates (Result retval, uint64_t bufferSize);
+
+ /**
+ * This method creates and opens the audio hardware output stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @param sourceMetadata Description of the audio that will be played.
+ May be used by implementations to configure hardware effects.
+ * @return retval operation completion status.
+ * @return outStream created output stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openOutputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ bitfield<AudioOutputFlag> flags,
+ SourceMetadata sourceMetadata) generates (
+ Result retval,
+ IStreamOut outStream,
+ AudioConfig suggestedConfig);
+
+ /**
+ * This method creates and opens the audio hardware input stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @param sinkMetadata Description of the audio that is suggested by the client.
+ * May be used by implementations to configure processing effects.
+ * @return retval operation completion status.
+ * @return inStream in case of success, created input stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openInputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ bitfield<AudioInputFlag> flags,
+ SinkMetadata sinkMetadata) generates (
+ Result retval,
+ IStreamIn inStream,
+ AudioConfig suggestedConfig);
+
+ /**
+ * Returns whether HAL supports audio patches.
+ *
+ * @return supports true if audio patches are supported.
+ */
+ supportsAudioPatches() generates (bool supports);
+
+ /**
+ * Creates an audio patch between several source and sink ports. The handle
+ * is allocated by the HAL and must be unique for this audio HAL module.
+ *
+ * @param sources patch sources.
+ * @param sinks patch sinks.
+ * @return retval operation completion status.
+ * @return patch created patch handle.
+ */
+ createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+ generates (Result retval, AudioPatchHandle patch);
+
+ /**
+ * Release an audio patch.
+ *
+ * @param patch patch handle.
+ * @return retval operation completion status.
+ */
+ releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+ /**
+ * Returns the list of supported attributes for a given audio port.
+ *
+ * As input, 'port' contains the information (type, role, address etc...)
+ * needed by the HAL to identify the port.
+ *
+ * As output, 'resultPort' contains possible attributes (sampling rates,
+ * formats, channel masks, gain controllers...) for this port.
+ *
+ * @param port port identifier.
+ * @return retval operation completion status.
+ * @return resultPort port descriptor with all parameters filled up.
+ */
+ getAudioPort(AudioPort port)
+ generates (Result retval, AudioPort resultPort);
+
+ /**
+ * Set audio port configuration.
+ *
+ * @param config audio port configuration.
+ * @return retval operation completion status.
+ */
+ setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+ /**
+ * Gets the HW synchronization source of the device. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+ * Optional method
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ * @return hwAvSync HW synchronization source
+ */
+ getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+ /**
+ * Sets whether the screen is on. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+ * Optional method
+ *
+ * @param turnedOn whether the screen is turned on.
+ * @return retval operation completion status.
+ */
+ setScreenState(bool turnedOn) generates (Result retval);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be retrieved at the same time.
+ * The implementation should return as many requested parameters
+ * as possible, even if one or more is not supported
+ *
+ * @param context provides more information about the request
+ * @param keys keys of the requested parameters
+ * @return retval operation completion status.
+ * OK must be returned if keys is empty.
+ * NOT_SUPPORTED must be returned if at least one key is unknown.
+ * @return parameters parameter key value pairs.
+ * Must contain the value of all requested keys if retval == OK
+ */
+ getParameters(vec<ParameterValue> context, vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be set at the same time though this is
+ * discouraged as it make failure analysis harder.
+ *
+ * If possible, a failed setParameters should not impact the platform state.
+ *
+ * @param context provides more information about the request
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ * All parameters must be successfully set for OK to be returned
+ */
+ setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+ generates (Result retval);
+
+ /**
+ * Returns an array with available microphones in device.
+ *
+ * @return retval INVALID_STATE if the call is not successful,
+ * OK otherwise.
+ *
+ * @return microphones array with microphones info
+ */
+ getMicrophones()
+ generates(Result retval, vec<MicrophoneInfo> microphones);
+
+ /**
+ * Notifies the device module about the connection state of an input/output
+ * device attached to it. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+ *
+ * @param address audio device specification.
+ * @param connected whether the device is connected.
+ * @return retval operation completion status.
+ */
+ setConnectedState(DeviceAddress address, bool connected)
+ generates (Result retval);
+};
diff --git a/audio/6.0/IDevicesFactory.hal b/audio/6.0/IDevicesFactory.hal
new file mode 100644
index 0000000..0483473
--- /dev/null
+++ b/audio/6.0/IDevicesFactory.hal
@@ -0,0 +1,70 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+import IPrimaryDevice;
+
+/** This factory allows a HAL implementation to be split in multiple independent
+ * devices (called module in the pre-treble API).
+ * Note that this division is arbitrary and implementation are free
+ * to only have a Primary.
+ * The framework will query the devices according to audio_policy_configuration.xml
+ *
+ * Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml
+ * and only used to identify a device in this factory.
+ * The framework must not interpret the name, treating it as a vendor opaque data
+ * with the following exception:
+ * - the "r_submix" device that must be present to support policyMixes (Eg: Android projected).
+ * Note that this Device is included by default in a build derived from AOSP.
+ *
+ * Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API
+ * but is loaded directly from the system partition using the legacy API
+ * due to limitations with the Bluetooth framework.
+ */
+interface IDevicesFactory {
+
+ /**
+ * Opens an audio device. To close the device, it is necessary to release
+ * references to the returned device object.
+ *
+ * @param device device name.
+ * @return retval operation completion status. Returns INVALID_ARGUMENTS
+ * if there is no corresponding hardware module found,
+ * NOT_INITIALIZED if an error occurred while opening the hardware
+ * module.
+ * @return result the interface for the created device.
+ */
+ openDevice(string device) generates (Result retval, IDevice result);
+
+ /**
+ * Opens the Primary audio device that must be present.
+ * This function is not optional and must return successfully the primary device.
+ *
+ * This device must have the name "primary".
+ *
+ * The telephony stack uses this device to control the audio during a voice call.
+ *
+ * @return retval operation completion status. Must be SUCCESS.
+ * For debugging, return INVALID_ARGUMENTS if there is no corresponding
+ * hardware module found, NOT_INITIALIZED if an error occurred
+ * while opening the hardware module.
+ * @return result the interface for the created device.
+ */
+ openPrimaryDevice() generates (Result retval, IPrimaryDevice result);
+};
diff --git a/audio/6.0/IPrimaryDevice.hal b/audio/6.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..78cfc65
--- /dev/null
+++ b/audio/6.0/IPrimaryDevice.hal
@@ -0,0 +1,195 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+ /**
+ * Sets the audio volume of a voice call.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setVoiceVolume(float volume) generates (Result retval);
+
+ /**
+ * This method is used to notify the HAL about audio mode changes.
+ *
+ * @param mode new mode.
+ * @return retval operation completion status.
+ */
+ setMode(AudioMode mode) generates (Result retval);
+
+ /**
+ * Sets the name of the current BT SCO headset. Calling this method
+ * is equivalent to setting legacy "bt_headset_name" parameter.
+ * The BT SCO headset name must only be used for debugging purposes.
+ * Optional method
+ *
+ * @param name the name of the current BT SCO headset (can be empty).
+ * @return retval operation completion status.
+ */
+ setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+ /**
+ * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT SCO NR + EC are enabled.
+ */
+ getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT SCO NR + EC are enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT Wideband is enabled.
+ */
+ getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT Wideband is enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT HFP is enabled.
+ */
+ getBtHfpEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT HFP is enabled.
+ * @return retval operation completion status.
+ */
+ setBtHfpEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+ * method is equivalent to setting "hfp_set_sampling_rate" parameter
+ * on the legacy HAL.
+ * Optional method
+ *
+ * @param sampleRateHz sample rate in Hz.
+ * @return retval operation completion status.
+ */
+ setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+ /**
+ * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+ * Calling this method is equivalent to setting "hfp_volume" parameter value
+ * on the legacy HAL (except that legacy HAL implementations expect
+ * an integer value in the range from 0 to 15.)
+ * Optional method
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setBtHfpVolume(float volume) generates (Result retval);
+
+ enum TtyMode : int32_t {
+ OFF,
+ VCO,
+ HCO,
+ FULL
+ };
+
+ /**
+ * Gets current TTY mode selection. Calling this method is equivalent to
+ * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return mode TTY mode.
+ */
+ getTtyMode() generates (Result retval, TtyMode mode);
+
+ /**
+ * Sets current TTY mode. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @param mode TTY mode.
+ * @return retval operation completion status.
+ */
+ setTtyMode(TtyMode mode) generates (Result retval);
+
+ /**
+ * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to getting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether HAC mode is enabled.
+ */
+ getHacEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether HAC mode is enabled.
+ * @return retval operation completion status.
+ */
+ setHacEnabled(bool enabled) generates (Result retval);
+
+ enum Rotation : int32_t {
+ DEG_0,
+ DEG_90,
+ DEG_180,
+ DEG_270
+ };
+
+ /**
+ * Updates HAL on the current rotation of the device relative to natural
+ * orientation. Calling this method is equivalent to setting legacy
+ * parameter "rotation".
+ *
+ * @param rotation rotation in degrees relative to natural device
+ * orientation.
+ * @return retval operation completion status.
+ */
+ updateRotation(Rotation rotation) generates (Result retval);
+};
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
new file mode 100644
index 0000000..f4c91f8
--- /dev/null
+++ b/audio/6.0/IStream.hal
@@ -0,0 +1,310 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import android.hardware.audio.effect@6.0::IEffect;
+
+interface IStream {
+ /**
+ * Return the frame size (number of bytes per sample).
+ *
+ * @return frameSize frame size in bytes.
+ */
+ getFrameSize() generates (uint64_t frameSize);
+
+ /**
+ * Return the frame count of the buffer. Calling this method is equivalent
+ * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+ *
+ * @return count frame count.
+ */
+ getFrameCount() generates (uint64_t count);
+
+ /**
+ * Return the size of input/output buffer in bytes for this stream.
+ * It must be a multiple of the frame size.
+ *
+ * @return buffer buffer size in bytes.
+ */
+ getBufferSize() generates (uint64_t bufferSize);
+
+ /**
+ * Return the sampling rate in Hz.
+ *
+ * @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.
+ *
+ * @return formats supported audio formats.
+ */
+ getSupportedFormats() generates (vec<AudioFormat> formats);
+
+ /**
+ * Sets the audio format of the stream. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+ * Optional method
+ *
+ * @param format audio format.
+ * @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);
+
+ /**
+ * Applies audio effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to apply.
+ * @return retval operation completion status.
+ */
+ addEffect(uint64_t effectId) generates (Result retval);
+
+ /**
+ * Stops application of the effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to remove.
+ * @return retval operation completion status.
+ */
+ removeEffect(uint64_t effectId) generates (Result retval);
+
+ /**
+ * Put the audio hardware input/output into standby mode.
+ * Driver must exit from standby mode at the next I/O operation.
+ *
+ * @return retval operation completion status.
+ */
+ standby() generates (Result retval);
+
+ /**
+ * Return the set of devices which this stream is connected to.
+ * Optional method
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ * @return device set of devices which this stream is connected to.
+ */
+ getDevices() generates (Result retval, vec<DeviceAddress> devices);
+
+ /**
+ * Connects the stream to one or multiple devices.
+ *
+ * This method must only be used for HALs that do not support
+ * 'IDevice.createAudioPatch' method. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded
+ * with a device address in the legacy HAL interface.
+ *
+ * @param address device to connect the stream to.
+ * @return retval operation completion status.
+ */
+ setDevices(vec<DeviceAddress> devices) generates (Result retval);
+
+ /**
+ * Sets the HW synchronization source. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+ * Optional method
+ *
+ * @param hwAvSync HW synchronization source
+ * @return retval operation completion status.
+ */
+ setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be retrieved at the same time.
+ * The implementation should return as many requested parameters
+ * as possible, even if one or more is not supported
+ *
+ * @param context provides more information about the request
+ * @param keys keys of the requested parameters
+ * @return retval operation completion status.
+ * OK must be returned if keys is empty.
+ * NOT_SUPPORTED must be returned if at least one key is unknown.
+ * @return parameters parameter key value pairs.
+ * Must contain the value of all requested keys if retval == OK
+ */
+ getParameters(vec<ParameterValue> context, vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be set at the same time though this is
+ * discouraged as it make failure analysis harder.
+ *
+ * If possible, a failed setParameters should not impact the platform state.
+ *
+ * @param context provides more information about the request
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ * All parameters must be successfully set for OK to be returned
+ */
+ setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+ generates (Result retval);
+
+ /**
+ * Called by the framework to start a stream operating in mmap mode.
+ * createMmapBuffer() must be called before calling start().
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ start() generates (Result retval);
+
+ /**
+ * Called by the framework to stop a stream operating in mmap mode.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ stop() generates (Result retval) ;
+
+ /**
+ * Called by the framework to retrieve information on the mmap buffer used for audio
+ * samples transfer.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @param minSizeFrames minimum buffer size requested. The actual buffer
+ * size returned in struct MmapBufferInfo can be larger.
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * NOT_INITIALIZED in case of memory allocation error
+ * INVALID_ARGUMENTS if the requested buffer size is too large
+ * INVALID_STATE if called out of sequence
+ * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created.
+ */
+ createMmapBuffer(int32_t minSizeFrames)
+ generates (Result retval, MmapBufferInfo info);
+
+ /**
+ * Called by the framework to read current read/write position in the mmap buffer
+ * with associated time stamp.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ * @return position a MmapPosition struct containing current HW read/write position in frames
+ * with associated time stamp.
+ */
+ getMmapPosition()
+ generates (Result retval, MmapPosition position);
+
+ /**
+ * Called by the framework to deinitialize the stream and free up
+ * all the currently allocated resources. It is recommended to close
+ * the stream on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED if called on IStream instead of input or
+ * output stream interface.
+ * INVALID_STATE if the stream was already closed.
+ */
+ close() generates (Result retval);
+};
diff --git a/audio/6.0/IStreamIn.hal b/audio/6.0/IStreamIn.hal
new file mode 100644
index 0000000..aadc370
--- /dev/null
+++ b/audio/6.0/IStreamIn.hal
@@ -0,0 +1,199 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+ /**
+ * Returns the source descriptor of the input stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+ * HAL.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return source audio source.
+ */
+ getAudioSource() generates (Result retval, AudioSource source);
+
+ /**
+ * Set the input gain for the audio driver.
+ * Optional method
+ *
+ * @param gain 1.0f is unity, 0.0f is zero.
+ * @result retval operation completion status.
+ */
+ setGain(float gain) generates (Result retval);
+
+ /**
+ * Commands that can be executed on the driver reader thread.
+ */
+ enum ReadCommand : int32_t {
+ READ,
+ GET_CAPTURE_POSITION
+ };
+
+ /**
+ * Data structure passed to the driver for executing commands
+ * on the driver reader thread.
+ */
+ struct ReadParameters {
+ ReadCommand command; // discriminator
+ union Params {
+ uint64_t read; // READ command, amount of bytes to read, >= 0.
+ // No parameters for GET_CAPTURE_POSITION.
+ } params;
+ };
+
+ /**
+ * Data structure passed back to the client via status message queue
+ * of 'read' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, read operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow reads.
+ */
+ struct ReadStatus {
+ Result retval;
+ ReadCommand replyTo; // discriminator
+ union Reply {
+ uint64_t read; // READ command, amount of bytes read, >= 0.
+ struct CapturePosition { // same as generated by getCapturePosition.
+ uint64_t frames;
+ uint64_t time;
+ } capturePosition;
+ } reply;
+ };
+
+ /**
+ * Called when the metadata of the stream's sink has been changed.
+ * @param sinkMetadata Description of the audio that is suggested by the clients.
+ */
+ updateSinkMetadata(SinkMetadata sinkMetadata);
+
+ /**
+ * Set up required transports for receiving audio buffers from the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the reader thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the driver
+ * to the client;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually read or error code).
+ *
+ * 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
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @param threadPriority priority of the driver thread.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * 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.
+ */
+ prepareForReading(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<ReadParameters> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<ReadStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /**
+ * Return the amount of input frames lost in the audio driver since the last
+ * call of this function.
+ *
+ * Audio driver is expected to reset the value to 0 and restart counting
+ * upon returning the current value by this function call. Such loss
+ * typically occurs when the user space process is blocked longer than the
+ * capacity of audio driver buffers.
+ *
+ * @return framesLost the number of input audio frames lost.
+ */
+ getInputFramesLost() generates (uint32_t framesLost);
+
+ /**
+ * Return a recent count of the number of audio frames received and the
+ * clock time associated with that frame count.
+ *
+ * @return retval INVALID_STATE if the device is not ready/available,
+ * NOT_SUPPORTED if the command is not supported,
+ * OK otherwise.
+ * @return frames the total frame count received. This must be as early in
+ * the capture pipeline as possible. In general, frames
+ * must be non-negative and must not go "backwards".
+ * @return time is the clock monotonic time when frames was measured. In
+ * general, time must be a positive quantity and must not
+ * go "backwards".
+ */
+ getCapturePosition()
+ generates (Result retval, uint64_t frames, uint64_t time);
+
+ /**
+ * Returns an array with active microphones in the stream.
+ *
+ * @return retval INVALID_STATE if the call is not successful,
+ * OK otherwise.
+ *
+ * @return microphones array with microphones info
+ */
+ getActiveMicrophones()
+ generates(Result retval, vec<MicrophoneInfo> microphones);
+
+ /**
+ * Specifies the logical microphone (for processing).
+ *
+ * If the feature is not supported an error should be returned
+ * If multiple microphones are present, this should be treated as a preference
+ * for their combined direction.
+ *
+ * Optional method
+ *
+ * @param Direction constant
+ * @return retval OK if the call is successful, an error code otherwise.
+ */
+ setMicrophoneDirection(MicrophoneDirection direction)
+ generates(Result retval);
+
+ /**
+ * Specifies the zoom factor for the selected microphone (for processing).
+ *
+ * If the feature is not supported an error should be returned
+ * If multiple microphones are present, this should be treated as a preference
+ * for their combined field dimension.
+ *
+ * Optional method
+ *
+ * @param the desired field dimension of microphone capture. Range is from -1 (wide angle),
+ * though 0 (no zoom) to 1 (maximum zoom).
+ *
+ * @return retval OK if the call is not successful, an error code otherwise.
+ */
+ setMicrophoneFieldDimension(float zoom) generates(Result retval);
+};
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
new file mode 100644
index 0000000..941ba61
--- /dev/null
+++ b/audio/6.0/IStreamOut.hal
@@ -0,0 +1,279 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+ /**
+ * Return the audio hardware driver estimated latency in milliseconds.
+ *
+ * @return latencyMs latency in milliseconds.
+ */
+ getLatency() generates (uint32_t latencyMs);
+
+ /**
+ * This method is used in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ * Optional method
+ *
+ * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @return retval operation completion status.
+ * If a volume is outside [0,1], return INVALID_ARGUMENTS
+ */
+ setVolume(float left, float right) generates (Result retval);
+
+ /**
+ * Commands that can be executed on the driver writer thread.
+ */
+ enum WriteCommand : int32_t {
+ WRITE,
+ GET_PRESENTATION_POSITION,
+ GET_LATENCY
+ };
+
+ /**
+ * Data structure passed back to the client via status message queue
+ * of 'write' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, write operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow writes;
+ * - INVALID_OPERATION, retrieving presentation position isn't supported.
+ */
+ struct WriteStatus {
+ Result retval;
+ WriteCommand replyTo; // discriminator
+ union Reply {
+ uint64_t written; // WRITE command, amount of bytes written, >= 0.
+ struct PresentationPosition { // same as generated by
+ uint64_t frames; // getPresentationPosition.
+ TimeSpec timeStamp;
+ } presentationPosition;
+ uint32_t latencyMs; // Same as generated by getLatency.
+ } reply;
+ };
+
+ /**
+ * Called when the metadata of the stream's source has been changed.
+ * @param sourceMetadata Description of the audio that is played by the clients.
+ */
+ updateSourceMetadata(SourceMetadata sourceMetadata);
+
+ /**
+ * Set up required transports for passing audio buffers to the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the writer thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the client
+ * to the driver;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually written or error code).
+ *
+ * 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
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * 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.
+ */
+ prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<WriteCommand> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<WriteStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /**
+ * Return the number of audio frames written by the audio DSP to DAC since
+ * the output has exited standby.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return dspFrames number of audio frames written.
+ */
+ getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+ /**
+ * Get the local time at which the next write to the audio driver will be
+ * presented. The units are microseconds, where the epoch is decided by the
+ * local audio HAL.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return timestampUs time of the next write.
+ */
+ getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+ /**
+ * Set the callback interface for notifying completion of non-blocking
+ * write and drain.
+ *
+ * Calling this function implies that all future 'write' and 'drain'
+ * must be non-blocking and use the callback to signal completion.
+ *
+ * 'clearCallback' method needs to be called in order to release the local
+ * callback proxy on the server side and thus dereference the callback
+ * implementation on the client side.
+ *
+ * @return retval operation completion status.
+ */
+ setCallback(IStreamOutCallback callback) generates (Result retval);
+
+ /**
+ * Clears the callback previously set via 'setCallback' method.
+ *
+ * Warning: failure to call this method results in callback implementation
+ * on the client side being held until the HAL server termination.
+ *
+ * If no callback was previously set, the method should be a no-op
+ * and return OK.
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ */
+ clearCallback() generates (Result retval);
+
+ /**
+ * Returns whether HAL supports pausing and resuming of streams.
+ *
+ * @return supportsPause true if pausing is supported.
+ * @return supportsResume true if resume is supported.
+ */
+ supportsPauseAndResume()
+ generates (bool supportsPause, bool supportsResume);
+
+ /**
+ * Notifies to the audio driver to stop playback however the queued buffers
+ * are retained by the hardware. Useful for implementing pause/resume. Empty
+ * implementation if not supported however must be implemented for hardware
+ * with non-trivial latency. In the pause state, some audio hardware may
+ * still be using power. Client code may consider calling 'suspend' after a
+ * timeout to prevent that excess power usage.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ pause() generates (Result retval);
+
+ /**
+ * Notifies to the audio driver to resume playback following a pause.
+ * Returns error INVALID_STATE if called without matching pause.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ resume() generates (Result retval);
+
+ /**
+ * Returns whether HAL supports draining of streams.
+ *
+ * @return supports true if draining is supported.
+ */
+ supportsDrain() generates (bool supports);
+
+ /**
+ * Requests notification when data buffered by the driver/hardware has been
+ * played. If 'setCallback' has previously been called to enable
+ * non-blocking mode, then 'drain' must not block, instead it must return
+ * quickly and completion of the drain is notified through the callback. If
+ * 'setCallback' has not been called, then 'drain' must block until
+ * completion.
+ *
+ * If 'type' is 'ALL', the drain completes when all previously written data
+ * has been played.
+ *
+ * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+ * for the current track has played to allow time for the framework to
+ * perform a gapless track switch.
+ *
+ * Drain must return immediately on 'stop' and 'flush' calls.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @param type type of drain.
+ * @return retval operation completion status.
+ */
+ drain(AudioDrain type) generates (Result retval);
+
+ /**
+ * Notifies to the audio driver to flush the queued data. Stream must
+ * already be paused before calling 'flush'.
+ * Optional method
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ flush() generates (Result retval);
+
+ /**
+ * Return a recent count of the number of audio frames presented to an
+ * external observer. This excludes frames which have been written but are
+ * still in the pipeline. The count is not reset to zero when output enters
+ * standby. Also returns the value of CLOCK_MONOTONIC as of this
+ * presentation count. The returned count is expected to be 'recent', but
+ * does not need to be the most recent possible value. However, the
+ * associated time must correspond to whatever count is returned.
+ *
+ * Example: assume that N+M frames have been presented, where M is a 'small'
+ * number. Then it is permissible to return N instead of N+M, and the
+ * 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.
+ */
+ getPresentationPosition()
+ generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+ /**
+ * Selects a presentation for decoding from a next generation media stream
+ * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+ * Optional method
+ *
+ * @param presentationId selected audio presentation.
+ * @param programId refinement for the presentation.
+ * @return retval operation completion status.
+ */
+ selectPresentation(int32_t presentationId, int32_t programId)
+ generates (Result retval);
+};
diff --git a/audio/6.0/IStreamOutCallback.hal b/audio/6.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..e393d9a
--- /dev/null
+++ b/audio/6.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.audio@6.0;
+
+/**
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+ /**
+ * Non blocking write completed.
+ */
+ oneway onWriteReady();
+
+ /**
+ * Drain completed.
+ */
+ oneway onDrainReady();
+
+ /**
+ * Stream hit an error.
+ */
+ oneway onError();
+};
diff --git a/audio/6.0/config/Android.bp b/audio/6.0/config/Android.bp
new file mode 100644
index 0000000..182dfcc
--- /dev/null
+++ b/audio/6.0/config/Android.bp
@@ -0,0 +1,7 @@
+
+xsd_config {
+ name: "audio_policy_configuration_V6_0",
+ srcs: ["audio_policy_configuration.xsd"],
+ package_name: "audio.policy.configuration.V6_0",
+}
+
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
new file mode 100644
index 0000000..7aa147c
--- /dev/null
+++ b/audio/6.0/config/api/current.txt
@@ -0,0 +1,422 @@
+// Signature format: 2.0
+package audio.policy.configuration.V6_0 {
+
+ public class AttachedDevices {
+ ctor public AttachedDevices();
+ method public java.util.List<java.lang.String> getItem();
+ }
+
+ public enum AudioDevice {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_IP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_NONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+
+ public enum AudioFormat {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_ALAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_FLAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_IEC61937;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_OPUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_QCELP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_SBC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_VORBIS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+ }
+
+ public class AudioPolicyConfiguration {
+ ctor public AudioPolicyConfiguration();
+ method public audio.policy.configuration.V6_0.GlobalConfiguration getGlobalConfiguration();
+ method public java.util.List<audio.policy.configuration.V6_0.Modules> getModules();
+ method public audio.policy.configuration.V6_0.SurroundSound getSurroundSound();
+ method public audio.policy.configuration.V6_0.Version getVersion();
+ method public java.util.List<audio.policy.configuration.V6_0.Volumes> getVolumes();
+ method public void setGlobalConfiguration(audio.policy.configuration.V6_0.GlobalConfiguration);
+ method public void setSurroundSound(audio.policy.configuration.V6_0.SurroundSound);
+ method public void setVersion(audio.policy.configuration.V6_0.Version);
+ }
+
+ public enum AudioUsage {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_GAME;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_MEDIA;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public enum DeviceCategory {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public class DevicePorts {
+ ctor public DevicePorts();
+ method public java.util.List<audio.policy.configuration.V6_0.DevicePorts.DevicePort> getDevicePort();
+ }
+
+ public static class DevicePorts.DevicePort {
+ ctor public DevicePorts.DevicePort();
+ method public String getAddress();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getEncodedFormats();
+ method public audio.policy.configuration.V6_0.Gains getGains();
+ method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+ method public audio.policy.configuration.V6_0.Role getRole();
+ method public String getTagName();
+ method public String getType();
+ method public boolean get_default();
+ method public void setAddress(String);
+ method public void setEncodedFormats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+ method public void setGains(audio.policy.configuration.V6_0.Gains);
+ method public void setRole(audio.policy.configuration.V6_0.Role);
+ method public void setTagName(String);
+ method public void setType(String);
+ method public void set_default(boolean);
+ }
+
+ public enum GainMode {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_JOINT;
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_RAMP;
+ }
+
+ public class Gains {
+ ctor public Gains();
+ method public java.util.List<audio.policy.configuration.V6_0.Gains.Gain> getGain();
+ }
+
+ public static class Gains.Gain {
+ ctor public Gains.Gain();
+ method public String 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.V6_0.GainMode getMode();
+ method public String getName();
+ method public int getStepValueMB();
+ method public void setChannel_mask(String);
+ 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.V6_0.GainMode);
+ method public void setName(String);
+ method public void setStepValueMB(int);
+ }
+
+ public class GlobalConfiguration {
+ ctor public GlobalConfiguration();
+ method public boolean getSpeaker_drc_enabled();
+ method public void setSpeaker_drc_enabled(boolean);
+ }
+
+ public enum HalVersion {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.HalVersion _2_0;
+ enum_constant public static final audio.policy.configuration.V6_0.HalVersion _3_0;
+ }
+
+ public class MixPorts {
+ ctor public MixPorts();
+ method public java.util.List<audio.policy.configuration.V6_0.MixPorts.MixPort> getMixPort();
+ }
+
+ public static class MixPorts.MixPort {
+ ctor public MixPorts.MixPort();
+ method public String getFlags();
+ method public audio.policy.configuration.V6_0.Gains getGains();
+ method public long getMaxActiveCount();
+ method public long getMaxOpenCount();
+ method public String getName();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioUsage> getPreferredUsage();
+ method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+ method public audio.policy.configuration.V6_0.Role getRole();
+ method public void setFlags(String);
+ method public void setGains(audio.policy.configuration.V6_0.Gains);
+ method public void setMaxActiveCount(long);
+ method public void setMaxOpenCount(long);
+ method public void setName(String);
+ method public void setPreferredUsage(java.util.List<audio.policy.configuration.V6_0.AudioUsage>);
+ method public void setRole(audio.policy.configuration.V6_0.Role);
+ }
+
+ public enum MixType {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.MixType mix;
+ enum_constant public static final audio.policy.configuration.V6_0.MixType mux;
+ }
+
+ public class Modules {
+ ctor public Modules();
+ method public java.util.List<audio.policy.configuration.V6_0.Modules.Module> getModule();
+ }
+
+ public static class Modules.Module {
+ ctor public Modules.Module();
+ method public audio.policy.configuration.V6_0.AttachedDevices getAttachedDevices();
+ method public String getDefaultOutputDevice();
+ method public audio.policy.configuration.V6_0.DevicePorts getDevicePorts();
+ method public audio.policy.configuration.V6_0.HalVersion getHalVersion();
+ method public audio.policy.configuration.V6_0.MixPorts getMixPorts();
+ method public String getName();
+ method public audio.policy.configuration.V6_0.Routes getRoutes();
+ method public void setAttachedDevices(audio.policy.configuration.V6_0.AttachedDevices);
+ method public void setDefaultOutputDevice(String);
+ method public void setDevicePorts(audio.policy.configuration.V6_0.DevicePorts);
+ method public void setHalVersion(audio.policy.configuration.V6_0.HalVersion);
+ method public void setMixPorts(audio.policy.configuration.V6_0.MixPorts);
+ method public void setName(String);
+ method public void setRoutes(audio.policy.configuration.V6_0.Routes);
+ }
+
+ public class Profile {
+ ctor public Profile();
+ method public String getChannelMasks();
+ method public String getFormat();
+ method public String getName();
+ method public String getSamplingRates();
+ method public void setChannelMasks(String);
+ method public void setFormat(String);
+ method public void setName(String);
+ method public void setSamplingRates(String);
+ }
+
+ public class Reference {
+ ctor public Reference();
+ method public String getName();
+ method public java.util.List<java.lang.String> getPoint();
+ method public void setName(String);
+ }
+
+ public enum Role {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Role sink;
+ enum_constant public static final audio.policy.configuration.V6_0.Role source;
+ }
+
+ public class Routes {
+ ctor public Routes();
+ method public java.util.List<audio.policy.configuration.V6_0.Routes.Route> getRoute();
+ }
+
+ public static class Routes.Route {
+ ctor public Routes.Route();
+ method public String getSink();
+ method public String getSources();
+ method public audio.policy.configuration.V6_0.MixType getType();
+ method public void setSink(String);
+ method public void setSources(String);
+ method public void setType(audio.policy.configuration.V6_0.MixType);
+ }
+
+ public enum Stream {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_MUSIC;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_PATCH;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_REROUTING;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_RING;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_SYSTEM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_TTS;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public class SurroundFormats {
+ ctor public SurroundFormats();
+ method public java.util.List<audio.policy.configuration.V6_0.SurroundFormats.Format> getFormat();
+ }
+
+ public static class SurroundFormats.Format {
+ ctor public SurroundFormats.Format();
+ method public audio.policy.configuration.V6_0.AudioFormat getName();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getSubformats();
+ method public void setName(audio.policy.configuration.V6_0.AudioFormat);
+ method public void setSubformats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+ }
+
+ public class SurroundSound {
+ ctor public SurroundSound();
+ method public audio.policy.configuration.V6_0.SurroundFormats getFormats();
+ method public void setFormats(audio.policy.configuration.V6_0.SurroundFormats);
+ }
+
+ public enum Version {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Version _1_0;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method public audio.policy.configuration.V6_0.DeviceCategory getDeviceCategory();
+ method public java.util.List<java.lang.String> getPoint();
+ method public String getRef();
+ method public audio.policy.configuration.V6_0.Stream getStream();
+ method public void setDeviceCategory(audio.policy.configuration.V6_0.DeviceCategory);
+ method public void setRef(String);
+ method public void setStream(audio.policy.configuration.V6_0.Stream);
+ }
+
+ public class Volumes {
+ ctor public Volumes();
+ method public java.util.List<audio.policy.configuration.V6_0.Reference> getReference();
+ method public java.util.List<audio.policy.configuration.V6_0.Volume> getVolume();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static audio.policy.configuration.V6_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/6.0/config/api/last_current.txt b/audio/6.0/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_current.txt
diff --git a/audio/6.0/config/api/last_removed.txt b/audio/6.0/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_removed.txt
diff --git a/audio/6.0/config/api/removed.txt b/audio/6.0/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/6.0/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..0dc89bb
--- /dev/null
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,624 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="halVersion">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Version of the interface the hal implements.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:decimal">
+ <!-- List of HAL versions supported by the framework. -->
+ <xs:enumeration value="2.0"/>
+ <xs:enumeration value="3.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="audioPolicyConfiguration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="globalConfiguration" type="globalConfiguration"/>
+ <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+ <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:key name="moduleNameKey">
+ <xs:selector xpath="modules/module"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@stream"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+ </xs:element>
+ <xs:complexType name="globalConfiguration">
+ <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="modules">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ There should be one section per audio HW module present on the platform.
+ Each <module/> contains two mandatory tags: “halVersion” and “name”.
+ The module "name" is the same as in previous .conf file.
+ Each module must contain the following sections:
+ - <devicePorts/>: a list of device descriptors for all
+ input and output devices accessible via this module.
+ This contains both permanently attached devices and removable devices.
+ - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+ - <routes/>: list of possible connections between input
+ and output devices or between stream and devices.
+ A <route/> is defined by a set of 3 attributes:
+ -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+ -"sink": the sink involved in this route
+ -"sources": all the sources than can be connected to the sink via this route
+ - <attachedDevices/>: permanently attached devices.
+ The attachedDevices section is a list of devices names.
+ Their names correspond to device names defined in "devicePorts" section.
+ - <defaultOutputDevice/> is the device to be used when no policy rule applies
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="module" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+ <xs:unique name="attachedDevicesUniqueness">
+ <xs:selector xpath="item"/>
+ <xs:field xpath="."/>
+ </xs:unique>
+ </xs:element>
+ <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+ <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+ <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+ <xs:element name="routes" type="routes" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="halVersion" type="halVersion" use="required"/>
+ </xs:complexType>
+ <xs:unique name="mixPortNameUniqueness">
+ <xs:selector xpath="mixPorts/mixPort"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ <xs:key name="devicePortNameKey">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@tagName"/>
+ </xs:key>
+ <xs:unique name="devicePortUniqueness">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@type"/>
+ <xs:field xpath="@address"/>
+ </xs:unique>
+ <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="defaultOutputDevice"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="attachedDevices/item"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <!-- The following 3 constraints try to make sure each sink port
+ is reference in one an only one route. -->
+ <xs:key name="routeSinkKey">
+ <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+ <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+ <xs:field xpath="@tagName|@name"/>
+ </xs:key>
+ <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:keyref>
+ <xs:unique name="routeUniqueness">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="attachedDevices">
+ <xs:sequence>
+ <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:annotation>
+ <xs:documentation xml:lang="en">
+ "|" separated list of audio_output_flags_t or audio_input_flags_t.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="role">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="sink"/>
+ <xs:enumeration value="source"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="mixPorts">
+ <xs:sequence>
+ <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="flags" type="audioInOutFlags"/>
+ <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+ <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+ <xs:attribute name="preferredUsage" type="audioUsageList">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ When choosing the mixPort of an audio track, the audioPolicy
+ first considers the mixPorts with a preferredUsage including
+ the track AudioUsage preferred .
+ If non support the track format, the other mixPorts are considered.
+ Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+ the audio of all apps playing with a MEDIA usage.
+ It may receive audio from ALARM if there are no audio compatible
+ <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:unique name="mixPortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="mixPortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </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"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+ <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_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+ <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_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_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+ <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_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="vendorExtension">
+ <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values.
+ Vendor are encouraged to namespace their module names to avoid conflicts.
+ Example for an hypothetical Google virtual reality device:
+ <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink">
+ -->
+ <xs:restriction base="xs:string">
+ <xs:pattern value="VX_[_a-zA-Z0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <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" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+ <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_HE_AAC_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+ <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+ <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+ <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+ <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_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"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+ </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:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+ <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+ <xs:enumeration value="AUDIO_USAGE_ALARM" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_GAME" />
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+ </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:annotation>
+ <xs:documentation xml:lang="en">
+ Comma (",") separated list of channel flags
+ from audio_channel_mask_t.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+ </xs:restriction>
+ </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:complexType>
+ <xs:simpleType name="gainMode">
+ <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: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="minValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="devicePorts">
+ <xs:sequence>
+ <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="tagName" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+ <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+ <xs:attribute name="default" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The default device will be used if multiple have the same type
+ and no explicit route request exists for a specific device of
+ that type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+ default="" />
+ </xs:complexType>
+ <xs:unique name="devicePortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="devicePortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="mixType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mix"/>
+ <xs:enumeration value="mux"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="routes">
+ <xs:sequence>
+ <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List all available sources for a given sink.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="mixType" use="required"/>
+ <xs:attribute name="sink" type="xs:string" use="required"/>
+ <xs:attribute name="sources" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="volumes">
+ <xs:sequence>
+ <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- TODO: Always require a ref for better xsd validations.
+ Currently a volume could have no points nor ref
+ as it can not be forbidden by xsd 1.0.-->
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <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:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+ <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of device_category from Volume.h.
+ TODO: generate from hidl to avoid manual sync. -->
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="stream" type="stream"/>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="reference">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="surroundSound">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Surround Sound section provides configuration related to handling of
+ multi-channel formats.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="formats" type="surroundFormats"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioFormatsList">
+ <xs:list itemType="audioFormat" />
+ </xs:simpleType>
+ <xs:complexType name="surroundFormats">
+ <xs:sequence>
+ <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="audioFormat" use="required"/>
+ <xs:attribute name="subformats" type="audioFormatsList" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
new file mode 100644
index 0000000..1a704f8
--- /dev/null
+++ b/audio/6.0/types.hal
@@ -0,0 +1,249 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ /**
+ * Methods marked as "Optional method" must return this result value
+ * if the operation is not supported by HAL.
+ */
+ NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+ /** drain() returns when all data has been played. */
+ ALL,
+ /**
+ * drain() returns a short time before all data from the current track has
+ * been played to give time for gapless track switch.
+ */
+ EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+ uint64_t tvSec; // seconds
+ uint64_t tvNSec; // nanoseconds
+};
+
+struct ParameterValue {
+ string key;
+ string value;
+};
+
+enum MmapBufferFlag : uint32_t {
+ NONE = 0x0,
+ /**
+ * If the buffer can be securely shared to untrusted applications
+ * through the AAudio exclusive mode.
+ * Only set this flag if applications are restricted from accessing the
+ * memory surrounding the audio data buffer by a kernel mechanism.
+ * See Linux kernel's dma_buf.
+ */
+ APPLICATION_SHAREABLE = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+ /** Mmap memory buffer */
+ memory sharedMemory;
+ /** Total buffer size in frames */
+ uint32_t bufferSizeFrames;
+ /** Transfer size granularity in frames */
+ uint32_t burstSizeFrames;
+ /** Attributes describing the buffer. */
+ bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+ int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+ int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ NOT_EMPTY = 1 << 0,
+ NOT_FULL = 1 << 1
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+ float x;
+ float y;
+ float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+ UNUSED = 0, /* Channel not used */
+ DIRECT = 1, /* Channel used and signal not processed */
+ PROCESSED = 2, /* Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+ UNKNOWN = 0,
+ MAINBODY = 1,
+ MAINBODY_MOVABLE = 2,
+ PERIPHERAL = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+ /** In Hz */
+ float frequency;
+ /** In dB */
+ float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+ /** Unique alphanumeric id for microphone. Guaranteed to be the same
+ * even after rebooting.
+ */
+ string deviceId;
+ /**
+ * Device specific information
+ */
+ DeviceAddress deviceAddress;
+ /** Each element of the vector must describe the channel with the same
+ * index.
+ */
+ vec<AudioMicrophoneChannelMapping> channelMapping;
+ /** Location of the microphone in regard to the body of the device */
+ AudioMicrophoneLocation location;
+ /** Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+ AudioMicrophoneGroup group;
+ /** Index of this microphone within the group.
+ * (group, index) must be unique within the same device.
+ */
+ uint32_t indexInTheGroup;
+ /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+ float sensitivity;
+ /** Level in dB of the max SPL supported at 1000 Hz */
+ float maxSpl;
+ /** Level in dB of the min SPL supported at 1000 Hz */
+ float minSpl;
+ /** Standard polar pattern of the microphone */
+ AudioMicrophoneDirectionality directionality;
+ /** Vector with ordered frequency responses (from low to high frequencies)
+ * with the frequency response of the microphone.
+ * Levels are in dB, relative to level at 1000 Hz
+ */
+ vec<AudioFrequencyResponsePoint> frequencyResponse;
+ /** Position of the microphone's capsule in meters, from the
+ * bottom-left-back corner of the bounding box of device.
+ */
+ AudioMicrophoneCoordinate position;
+ /** Normalized point to signal the main orientation of the microphone's
+ * capsule. sqrt(x^2 + y^2 + z^2) = 1
+ */
+ AudioMicrophoneCoordinate orientation;
+};
+
+/**
+ * Constants used by the HAL to determine how to select microphones and process those inputs in
+ * order to optimize for capture in the specified direction.
+ *
+ * MicrophoneDirection Constants are defined in MicrophoneDirection.java.
+ */
+@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_")
+enum MicrophoneDirection : int32_t {
+ /**
+ * Don't do any directionality processing of the activated microphone(s).
+ */
+ UNSPECIFIED = 0,
+ /**
+ * Optimize capture for audio coming from the screen-side of the device.
+ */
+ FRONT = 1,
+ /**
+ * Optimize capture for audio coming from the side of the device opposite the screen.
+ */
+ BACK = 2,
+ /**
+ * Optimize capture for audio coming from an off-device microphone.
+ */
+ EXTERNAL = 3,
+};
diff --git a/audio/common/6.0/Android.bp b/audio/common/6.0/Android.bp
new file mode 100644
index 0000000..1a4e054
--- /dev/null
+++ b/audio/common/6.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio.common@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
new file mode 100644
index 0000000..132f86d
--- /dev/null
+++ b/audio/common/6.0/types.hal
@@ -0,0 +1,1032 @@
+/*
+ * 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.audio.common@6.0;
+
+import android.hidl.safe_union@1.0;
+
+/*
+ *
+ * IDs and Handles
+ *
+ */
+
+/**
+ * Handle type for identifying audio sources and sinks.
+ */
+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.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+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.
+ */
+struct Uuid {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t versionAndTimeHigh;
+ uint16_t variantAndClockSeqHigh;
+ uint8_t[6] node;
+};
+
+
+/*
+ *
+ * Audio streams
+ *
+ */
+
+/**
+ * Audio stream type describing the intended use case of a stream.
+ */
+@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
+ DEFAULT = -1,
+ MIN = 0,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be
+ // routed to speaker
+ DTMF = 8,
+ TTS = 9, // Transmitted Through Speaker. Plays over speaker
+ // only, silent on other devices
+ ACCESSIBILITY = 10, // For accessibility talk back prompts
+};
+
+@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,
+ // frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ // system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+ DEFAULT = 0,
+ MIC = 1,
+ VOICE_UPLINK = 2,
+ VOICE_DOWNLINK = 3,
+ VOICE_CALL = 4,
+ CAMCORDER = 5,
+ VOICE_RECOGNITION = 6,
+ 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,
+ FM_TUNER = 1998,
+ HOTWORD = 1999,
+};
+
+typedef int32_t AudioSession;
+/**
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+ /**
+ * Session for effects attached to a particular output stream
+ * (value must be less than 0)
+ */
+ OUTPUT_STAGE = -1,
+ /**
+ * Session for effects applied to output mix. These effects can
+ * be moved by audio policy manager to another output stream
+ * (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).
+ */
+@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,
+
+ /** Deprecated */
+ MAIN_MASK = 0xFF000000UL,
+ SUB_MASK = 0x00FFFFFFUL,
+
+ /* 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),
+};
+
+/**
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@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),
+};
+
+/**
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+ NORMAL = 0,
+ RINGTONE = 1,
+ /** Calls handled by the telephony stack (Eg: PSTN). */
+ IN_CALL = 2,
+ /** Calls handled by apps (Eg: Hangout). */
+ IN_COMMUNICATION = 3,
+};
+
+@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.
+ */
+typedef uint8_t[6] MacAddress;
+
+/**
+ * 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
+ struct Alsa {
+ int32_t card;
+ int32_t device;
+ } alsa; // used for USB_*
+ } 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.
+ */
+@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,
+};
+
+/**
+ * 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.
+ */
+@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
+};
+
+@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
+ UNKNOWN = 0,
+ MEDIA = 1,
+ VOICE_COMMUNICATION = 2,
+ VOICE_COMMUNICATION_SIGNALLING = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ NOTIFICATION_TELEPHONY_RINGTONE = 6,
+ ASSISTANCE_ACCESSIBILITY = 11,
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ ASSISTANCE_SONIFICATION = 13,
+ GAME = 14,
+ VIRTUAL_SOURCE = 15,
+ ASSISTANT = 16,
+};
+
+/** 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
+ UNKNOWN = 0,
+ SPEECH = 1,
+ MUSIC = 2,
+ MOVIE = 3,
+ SONIFICATION = 4,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+ uint32_t sampleRateHz;
+ bitfield<AudioChannelMask> channelMask;
+ AudioFormat format;
+ AudioStreamType streamType;
+ uint32_t bitRatePerSecond;
+ int64_t durationMicroseconds; // -1 if unknown
+ bool hasVideo;
+ bool isStreaming;
+ uint32_t bitWidth;
+ uint32_t bufferSize;
+ AudioUsage usage;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+ uint32_t sampleRateHz;
+ bitfield<AudioChannelMask> channelMask;
+ AudioFormat format;
+ AudioOffloadInfo offloadInfo;
+ uint64_t frameCount;
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+ AudioUsage usage;
+ AudioContentType contentType;
+ /**
+ * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+ * 2 means double amplification...
+ * Must not be negative.
+ */
+ float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+ vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+ AudioSource source;
+ /**
+ * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+ * 2 means double amplification...
+ * Must not be negative.
+ */
+ float gain;
+ /**
+ * Indicates the destination of an input stream, can be left unspecified.
+ */
+ safe_union Destination {
+ Monostate unspecified;
+ DeviceAddress device;
+ };
+ Destination destination;
+};
+
+/** Metadatas of the sink of a StreamIn. */
+struct SinkMetadata {
+ vec<RecordTrackMetadata> tracks;
+};
+
+
+/*
+ *
+ * Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@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
+};
+
+/**
+ * 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
+ int32_t minValue; // minimum gain value in millibels
+ int32_t maxValue; // maximum gain value in millibels
+ int32_t defaultValue; // default gain value in millibels
+ uint32_t stepValue; // gain step in millibels
+ uint32_t minRampMs; // minimum ramp duration in ms
+ uint32_t maxRampMs; // maximum ramp duration in ms
+};
+
+/**
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+ int32_t index; // index of the corresponding AudioGain in AudioPort.gains
+ AudioGainMode mode;
+ 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).
+ */
+ int32_t[4 * 8] values;
+ uint32_t rampDurationMs; // ramp duration in ms
+};
+
+
+/*
+ *
+ * Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * 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)
+ */
+@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 {
+ 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 {
+ 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;
+};
+
+/**
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+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 {
+ AudioPortHandle id;
+ AudioPortRole role;
+ string name;
+ vec<uint32_t> sampleRates;
+ vec<bitfield<AudioChannelMask>> channelMasks;
+ vec<AudioFormat> formats;
+ 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;
+};
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
new file mode 100755
index 0000000..d07012f
--- /dev/null
+++ b/audio/common/all-versions/copyHAL.sh
@@ -0,0 +1,204 @@
+#/usr/bin/env bash
+
+set -euo pipefail
+
+if (echo "$@" |grep -qe -h); then
+ echo "This script will generate a new HAL version identical to an other one."
+ echo "This helps creating the boilerplate for a new version."
+ echo
+ echo "USAGE: $0 [BASE_VERSION] [NEW_VERSION]"
+ echo " BASE_VERSION default value is the highest version currently existing"
+ echo " NEW_VERSION default value is BASE_VERSION + 1"
+ echo
+ echo "Example: to generate a V6.0 by copying V5, do: $0 5.0 6.0"
+ exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional
+readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp
+readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/
+readonly HAL_SERVICE_CPP=service.cpp
+
+readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal
+readonly IMPL_DIRECTORY=impl
+readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
+
+readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
+readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
+readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
+
+readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
+ sort -n |tail -n1)}
+readonly BASE_MAJOR_VERSION=${BASE_VERSION%.*}
+readonly BASE_MINOR_VERSION=${BASE_VERSION##*.}
+
+readonly NEW_VERSION="${2:-$((${BASE_MAJOR_VERSION} + 1)).0}"
+readonly NEW_MAJOR_VERSION=${NEW_VERSION%.*}
+readonly NEW_MINOR_VERSION=${NEW_VERSION##*.}
+
+
+readonly BASE_VERSION_REGEX="${BASE_MAJOR_VERSION}[._]${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_REGEX="${NEW_MAJOR_VERSION}[._]${NEW_MINOR_VERSION}"
+
+readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}"
+readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}"
+updateVersion() {
+ if [ $1 == "-e" ]; then
+ local -r REGEX="$2"; shift 2
+ else
+ local -r REGEX="$BASE_VERSION_REGEX"
+ fi
+ awk -i inplace -e "{if (!/$REGEX/) print; else {
+ if (original_before) print
+ if (original_after) original_line=\$0;
+
+ gsub(/$BASE_VERSION_ESCAPE/,\"$NEW_VERSION\");
+ gsub(/$BASE_VERSION_UNDERSCORE/,\"$NEW_VERSION_UNDERSCORE\");
+ gsub(/MAJOR_VERSION=$BASE_MAJOR_VERSION/,
+ \"MAJOR_VERSION=$NEW_MAJOR_VERSION\");
+ gsub(/MINOR_VERSION=$BASE_MINOR_VERSION/,
+ \"MINOR_VERSION=$NEW_MINOR_VERSION\");
+
+ print
+ if (original_after) print original_line
+ }}" "$@"
+}
+
+updateAudioVersion() {
+ updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@"
+}
+
+updateLicenceDates() {
+ # Update date on the 2 first lines
+ sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@"
+}
+
+echo "Creating new audio HAL V$NEW_VERSION based on V$BASE_VERSION"
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+MODIFIED=
+runIfNeeded() {
+ local -r TARGET=$1; shift
+ cd $ANDROID_BUILD_TOP/$TARGET
+ if grep -q -r "audio.*$NEW_VERSION_REGEX"; then
+ echo " Skipping $TARGET as already up to date"
+ else
+ echo " Updating $PWD"
+ MODIFIED+=$'\n - '$TARGET
+ "$@"
+ fi
+}
+
+createHALVersion() {
+ local -r DIRS=". common effect"
+ local COPY=
+ echo "Copy $BASE_VERSION to $NEW_VERSION in $DIRS"
+ for DIR in $DIRS; do
+ cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION
+ COPY+=" $DIR/$NEW_VERSION"
+ done
+
+ echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files"
+ updateVersion $(find $COPY -type f)
+ updateLicenceDates $(find $COPY -type f)
+
+ echo "Update implementation and VTS generic code"
+ local -r FILES="*/all-versions/default/Android.bp */all-versions/vts/functional/Android.bp"
+ updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $FILES
+ sed -i '${/^$/d}' $FILES # Remove \n at the end of the files
+
+ updateVersion -v original_before=1 $HAL_SERVICE_DIRECTORY/Android.bp
+
+ updateVersion -e "audio::.*$BASE_VERSION_REGEX" -v original_after=1 \
+ $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+ updateVersion -e "audio\/.*$BASE_VERSION_REGEX" -v original_before=1 \
+ $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+
+ local -r HAL_VTS_PATH=$HAL_VTS_DIRECTORY/$NEW_VERSION/$HAL_VTS_FILE
+ mkdir -p $(dirname $HAL_VTS_PATH)
+ cat > $HAL_VTS_PATH <<EOF
+/*
+ * Copyright (C) $(date +"%Y") The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pull in all the <= $BASE_VERSION tests
+#include "$BASE_VERSION/$(basename AudioPrimaryHidlHalTest.cpp)"
+EOF
+
+ echo "New HAL version $NEW_VERSION successfully created"
+}
+
+echo "Creating new audio HAL definition, default impl and VTS"
+runIfNeeded $HAL_DIRECTORY createHALVersion
+
+
+createFrameworkAdapter() {
+ updateVersion -v original_before=1 Android.bp
+ updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_FACTORYHAL/Android.bp
+ updateVersion -v original_after=1 $IMPL_FACTORYHAL
+}
+echo "Now creating the framework adapter version"
+runIfNeeded $FWK_DIRECTORY createFrameworkAdapter
+
+createVTSXML() {
+ cp -Tar V$BASE_VERSION_UNDERSCORE V$NEW_VERSION_UNDERSCORE
+ cp -Tar effect/{V$BASE_VERSION_UNDERSCORE,V$NEW_VERSION_UNDERSCORE}
+ local -r FILES=$(find {.,effect}/V$NEW_VERSION_UNDERSCORE -type f)
+ updateVersion $FILES
+ updateLicenceDates $FILES
+}
+echo "Now update VTS XML"
+runIfNeeded $VTS_DIRECTORY createVTSXML
+
+echo "Now register new VTS"
+runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basename $VTS_LIST)
+
+echo "Now update watchdog"
+runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
+
+echo "Now update GSI current.txt"
+runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
+
+if ! [ "$MODIFIED" ]; then
+ echo
+ echo "$NEW_VERSION already exist, nothing to do"
+ exit
+fi
+
+cat << EOF
+
+All File generated successfully. Please submit a patch in all those directories: $MODIFIED
+
+-----------------------------------------------------------
+WHAT WAS *NOT* DONE, and you need to do now:
+ 1) You need to choose if the new HAL is optional or not for new devices.
+ Either add or replace $BASE_VERSION by $NEW_VERSION in
+ compatibility_matrices/compatibility_matrix.current.xml
+ Do not forget to update both the "audio" and "audio.effects" HAL'
+
+ 2) Then you need to choose a device to update its audio HAL implementation:
+ a) Update the HAL manifest of your device: open your device manifest.xml
+ and replace $BASE_VERSION by $NEW_VERSION for both
+ - android.hardware.audio
+ - android.hardware.audio.effect
+ b) Go to your device device.mk (usually next to the manifest) and replace:
+ - android.hardware.audio@$BASE_VERSION-impl by
+ android.hardware.audio@$NEW_VERSION-impl
+ - android.hardware.audio.effect@$BASE_VERSION-impl by
+ android.hardware.audio.effect@$NEW_VERSION-impl
+EOF
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index c0bd34c..0eb4a71 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -69,7 +69,6 @@
cc_library_shared {
name: "android.hardware.audio.common@2.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@2.0",
],
@@ -83,7 +82,6 @@
cc_library_shared {
name: "android.hardware.audio.common@4.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@4.0",
],
@@ -97,7 +95,6 @@
cc_library_shared {
name: "android.hardware.audio.common@5.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@5.0",
],
@@ -107,3 +104,16 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio.common@6.0-util",
+ defaults: ["android.hardware.audio.common-util_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
new file mode 100644
index 0000000..4565730
--- /dev/null
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -0,0 +1,51 @@
+cc_binary {
+ name: "android.hardware.audio.service",
+
+ init_rc: ["android.hardware.audio.service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ // Only support 32 bit as the binary must always be installed at the same
+ // location for init to start it and the build system does not support
+ // having two binaries installable to the same location even if they are
+ // not installed in the same build.
+ compile_multilib: "32",
+ srcs: ["service.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.audio@2.0",
+ "android.hardware.audio@4.0",
+ "android.hardware.audio@5.0",
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.audio.common@4.0",
+ "android.hardware.audio.common@5.0",
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@2.0",
+ "android.hardware.audio.effect@4.0",
+ "android.hardware.audio.effect@5.0",
+ "android.hardware.audio.effect@6.0",
+ "android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ ],
+}
+
+// Legacy service name, use android.hardware.audio.service instead
+phony {
+ name: "android.hardware.audio@2.0-service",
+ required: ["android.hardware.audio.service"],
+}
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
deleted file mode 100644
index 236f1fd..0000000
--- a/audio/common/all-versions/default/service/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Service
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.audio@2.0-service
-LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_SRC_FILES := \
- service.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libbinder \
- libhidlbase \
- liblog \
- libutils \
- libhardware \
- android.hardware.audio@2.0 \
- android.hardware.audio@4.0 \
- android.hardware.audio@5.0 \
- android.hardware.audio.common@2.0 \
- android.hardware.audio.common@4.0 \
- android.hardware.audio.common@5.0 \
- android.hardware.audio.effect@2.0 \
- android.hardware.audio.effect@4.0 \
- android.hardware.audio.effect@5.0 \
- android.hardware.bluetooth.a2dp@1.0 \
- android.hardware.bluetooth.audio@2.0 \
- android.hardware.soundtrigger@2.0 \
- android.hardware.soundtrigger@2.1 \
- android.hardware.soundtrigger@2.2
-
-# Can not switch to Android.bp until AUDIOSERVER_MULTILIB
-# is deprecated as build config variable are not supported
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
-
-include $(BUILD_EXECUTABLE)
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
similarity index 81%
rename from audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
rename to audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 72b4d19..63d2542 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -1,4 +1,4 @@
-service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
+service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service
class hal
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 2a6571b..2730f3b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -19,9 +19,11 @@
#include <android/hardware/audio/2.0/IDevicesFactory.h>
#include <android/hardware/audio/4.0/IDevicesFactory.h>
#include <android/hardware/audio/5.0/IDevicesFactory.h>
+#include <android/hardware/audio/6.0/IDevicesFactory.h>
#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
@@ -59,16 +61,22 @@
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<audio::V5_0::IDevicesFactory,
- audio::V4_0::IDevicesFactory,
- audio::V2_0::IDevicesFactory>()),
+ // Keep versions on a separate line for easier parsing
+ // clang-format off
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+ audio::V6_0::IDevicesFactory,
+ audio::V5_0::IDevicesFactory,
+ audio::V4_0::IDevicesFactory,
+ audio::V2_0::IDevicesFactory>()),
"Could not register audio core API");
- LOG_ALWAYS_FATAL_IF(
- (registerPassthroughServiceImplementations<audio::effect::V5_0::IEffectsFactory,
- audio::effect::V4_0::IEffectsFactory,
- audio::effect::V2_0::IEffectsFactory>()),
- "Could not register audio effect API");
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+ audio::effect::V6_0::IEffectsFactory,
+ audio::effect::V5_0::IEffectsFactory,
+ audio::effect::V4_0::IEffectsFactory,
+ audio::effect::V2_0::IEffectsFactory>()),
+ "Could not register audio effect API");
+ // clang-format on
ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
soundtrigger::V2_1::ISoundTriggerHw,
diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
index 5ac2fdc..03a6305 100644
--- a/audio/common/all-versions/test/utility/include/utility/AssertOk.h
+++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
@@ -114,6 +114,27 @@
#define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
#define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return the default initializer value. */
+template <class R>
+static R extract(const Return<R>& ret) {
+ if (!ret.isOk()) {
+ EXPECT_IS_OK(ret);
+ return R{};
+ }
+ return ret;
+}
+
+template <class Result, class Value>
+static void expectValueOrFailure(Result res, Value expectedValue, Value actualValue,
+ Result expectedFailure) {
+ if (res == Result::OK) {
+ ASSERT_EQ(expectedValue, actualValue);
+ } else {
+ ASSERT_EQ(expectedFailure, res) << "Unexpected result " << toString(res);
+ }
+}
+
} // namespace utility
} // namespace test
} // namespace common
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
index 0e416f3..2b240ce 100644
--- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -20,9 +20,6 @@
#include <functional>
#include <list>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <gtest/gtest.h>
-
namespace android {
namespace hardware {
namespace audio {
@@ -34,18 +31,20 @@
* Avoid destroying static objects after main return.
* Post main return destruction leads to incorrect gtest timing measurements as
* well as harder debuging if anything goes wrong during destruction. */
-class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
+class EnvironmentTearDown {
+ public:
using TearDownFunc = std::function<void()>;
void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
- private:
- void HidlTearDown() override {
+ protected:
+ void executeAllTearDowns() {
// Call the tear downs in reverse order of insertion
for (auto& tearDown : tearDowns) {
tearDown();
}
}
+
+ private:
std::list<TearDownFunc> tearDowns;
};
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index c4548c3..b8b7fee 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -43,13 +43,11 @@
cc_library_shared {
name: "android.hardware.audio@2.0-impl",
defaults: ["android.hardware.audio-impl_default"],
-
shared_libs: [
"android.hardware.audio@2.0",
"android.hardware.audio.common@2.0",
"android.hardware.audio.common@2.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=2",
"-DMINOR_VERSION=0",
@@ -66,7 +64,6 @@
"android.hardware.audio.common@4.0",
"android.hardware.audio.common@4.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=4",
"-DMINOR_VERSION=0",
@@ -77,16 +74,29 @@
cc_library_shared {
name: "android.hardware.audio@5.0-impl",
defaults: ["android.hardware.audio-impl_default"],
-
shared_libs: [
"android.hardware.audio@5.0",
"android.hardware.audio.common@5.0",
"android.hardware.audio.common@5.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio@6.0-impl",
+ defaults: ["android.hardware.audio-impl_default"],
+ shared_libs: [
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
index 7906bf1..c189464 100644
--- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
@@ -60,19 +60,20 @@
"deconnection",
testConnectedState(stream.get()))
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
+ ASSERT_IS_OK(getDevice()->getHwAvSync()));
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
// Test Invalid values
for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
SCOPED_TRACE("mode=" + toString(mode));
- ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode));
}
// Test valid values
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
SCOPED_TRACE("mode=" + toString(mode));
- ASSERT_OK(device->setMode(mode));
+ ASSERT_OK(getDevice()->setMode(mode));
}
}
diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..6373e39
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+ public ::testing::VtsHalHidlTargetTestEnvBase {
+ private:
+ void HidlTearDown() override {
+ executeAllTearDowns();
+ VtsHalHidlTargetTestEnvBase::HidlTearDown();
+ }
+};
+
+#endif // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
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 022f75e..b8defb6 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,41 +16,33 @@
#include "AudioPrimaryHidlHalTest.h"
-static void waitForDeviceDestruction() {
- // FIXME: there is no way to know when the remote IDevice is being destroyed
- // Binder does not support testing if an object is alive, thus
- // wait for 100ms to let the binder destruction propagates and
- // the remote device has the time to be destroyed.
- // flushCommand makes sure all local command are sent, thus should reduce
- // the latency between local and remote destruction.
- IPCThreadState::self()->flushCommands();
- usleep(100);
-}
-
-TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
+TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
doc::test("Calling openDevice(\"primary\") should return the primary device.");
- {
- Result result;
- sp<IDevice> baseDevice;
- ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
- ASSERT_OK(result);
- ASSERT_TRUE(baseDevice != nullptr);
+ struct WaitExecutor {
+ ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); }
+ } waitExecutor; // Make sure we wait for the device destruction on exiting from the test.
+ Result result;
+ sp<IDevice> baseDevice;
+ ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice)));
+ if (result != Result::OK && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory"; // returns
+ }
+ ASSERT_OK(result);
+ ASSERT_TRUE(baseDevice != nullptr);
- Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
- ASSERT_TRUE(primaryDevice.isOk());
- ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
- } // Destroy local IDevice proxy
- waitForDeviceDestruction();
+ Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
+ ASSERT_TRUE(primaryDevice.isOk());
+ ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
}
//////////////////////////////////////////////////////////////////////////////
/////////////////////////// get(Active)Microphones ///////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
+TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) {
doc::test("Make sure getMicrophones always succeeds");
hidl_vec<MicrophoneInfo> microphones;
- ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
+ ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones)));
ASSERT_OK(res);
if (microphones.size() > 0) {
// When there is microphone on the phone, try to open an input stream
@@ -72,15 +64,15 @@
}
sp<IStreamIn> stream;
AudioConfig suggestedConfig{};
- ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
- initMetadata,
- returnIn(res, stream, suggestedConfig)));
+ ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config,
+ flags, initMetadata,
+ returnIn(res, stream, suggestedConfig)));
if (res != Result::OK) {
ASSERT_TRUE(stream == nullptr);
AudioConfig suggestedConfigRetry{};
- ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
- suggestedConfig, flags, initMetadata,
- returnIn(res, stream, suggestedConfigRetry)));
+ ASSERT_OK(getDevice()->openInputStream(
+ ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata,
+ returnIn(res, stream, suggestedConfigRetry)));
}
ASSERT_OK(res);
hidl_vec<MicrophoneInfo> activeMicrophones;
@@ -117,6 +109,10 @@
ASSERT_NE(0U, activeMicrophones.size());
}
stream->close();
+ // Workaround for b/139329877. Ensures the stream gets closed on the audio hal side.
+ stream.clear();
+ IPCThreadState::self()->flushCommands();
+ usleep(1000);
if (efGroup) {
EventFlag::deleteEventFlag(&efGroup);
}
@@ -124,7 +120,7 @@
}
}
-TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
+TEST_P(AudioPrimaryHidlTest, SetConnectedState) {
doc::test("Check that the HAL can be notified of device connection and deconnection");
using AD = AudioDevice;
for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
@@ -133,7 +129,7 @@
SCOPED_TRACE("state=" + ::testing::PrintToString(state));
DeviceAddress address = {};
address.device = deviceType;
- auto ret = device->setConnectedState(address, state);
+ auto ret = getDevice()->setConnectedState(address, state);
ASSERT_TRUE(ret.isOk());
if (ret == Result::NOT_SUPPORTED) {
doc::partialTest("setConnectedState is not supported");
@@ -146,8 +142,7 @@
// Because there is no way of knowing if the devices were connected before
// calling setConnectedState, there is no way to restore the HAL to its
// initial state. To workaround this, destroy the HAL at the end of this test.
- device.clear();
- waitForDeviceDestruction();
+ ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName()));
}
static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
@@ -191,7 +186,7 @@
}
ASSERT_OK(res);
}
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get()));
TEST_P(InputStreamTest, updateSinkMetadata) {
doc::test("The HAL should not crash on metadata change");
@@ -251,58 +246,58 @@
ASSERT_OK(stream->updateSourceMetadata(initMetadata));
}
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
// Test Invalid values
for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
- ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
- << "mode=" << mode;
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
+ << "mode=" << mode;
}
// Test valid values
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
- ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode);
+ ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
}
}
-TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
doc::test(
"Make sure setBtHfpSampleRate either succeeds or "
"indicates that it is not supported at all, or that the provided value is invalid");
for (auto samplingRate : {8000, 16000, 22050, 24000}) {
- ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
+ ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate));
}
}
-TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) {
doc::test(
"Make sure setBtHfpVolume is either not supported or "
"only succeed if volume is in [0,1]");
- auto ret = device->setBtHfpVolume(0.0);
+ auto ret = getDevice()->setBtHfpVolume(0.0);
ASSERT_TRUE(ret.isOk());
if (ret == Result::NOT_SUPPORTED) {
doc::partialTest("setBtHfpVolume is not supported");
return;
}
- testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); });
+ testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); });
}
-TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
+TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
doc::test(
"Make sure setBtScoHeadsetDebugName either succeeds or "
"indicates that it is not supported");
- ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
+ ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test"));
}
-TEST_F(AudioPrimaryHidlTest, updateRotation) {
+TEST_P(AudioPrimaryHidlTest, updateRotation) {
doc::test("Check that the hal can receive the current rotation");
for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
Rotation::DEG_270, Rotation::DEG_0}) {
- ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
+ ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation));
}
}
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
doc::test("Query and set the BT HFP state");
testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
&IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..6314ea7
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// pull in all the <= 5.0 tests
+#include "5.0/AudioPrimaryHidlHalTest.cpp"
diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..593759f
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+ public ::testing::Environment {
+ public:
+ void init(int* /*argc*/, char** /*argv*/) {} // emulate VtsHalHidlTargetTestEnvBase
+ private:
+ void TearDown() override { executeAllTearDowns(); }
+};
+
+// FIXME: Will be removed while making getDeviceParameters to use the config
+static constexpr const char* kDefaultServiceName = "default";
+
+#endif // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 5e17ade..1818e36 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,12 +19,13 @@
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"android.hardware.audio.common.test.utility",
+ "libaudiofoundation",
"libaudiopolicycomponents",
"libmedia_helper",
"libxml2",
],
shared_libs: [
- "libaudiofoundation",
+ "libbinder",
"libfmq",
],
header_libs: [
@@ -83,3 +84,20 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_test {
+ name: "VtsHalAudioV6_0TargetTest",
+ defaults: ["VtsHalAudioTargetTest_defaults"],
+ srcs: [
+ "6.0/AudioPrimaryHidlHalTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 7f8b6a0..e59ab98 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -23,6 +23,7 @@
#include <initializer_list>
#include <limits>
#include <list>
+#include <map>
#include <string>
#include <vector>
@@ -31,7 +32,9 @@
#include <hwbinder/IPCThreadState.h>
+#if MAJOR_VERSION <= 5
#include <VtsHalHidlTargetTestBase.h>
+#endif
#include <android-base/logging.h>
@@ -44,16 +47,25 @@
#include <Serializer.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
+#if MAJOR_VERSION >= 6
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
#include <common/all-versions/VersionUtils.h>
#include "utility/AssertOk.h"
#include "utility/Documentation.h"
-#include "utility/EnvironmentTearDown.h"
#include "utility/PrettyPrintAudioTypes.h"
#include "utility/ReturnIn.h"
#include "utility/ValidateXml.h"
+#if MAJOR_VERSION <= 5
+#include "2.0/EnvironmentTearDown.h"
+#elif MAJOR_VERSION >= 6
+#include "6.0/EnvironmentTearDown.h"
+#endif
+
/** Provide version specific functions that are used in the generic tests */
#if MAJOR_VERSION == 2
#include "2.0/AudioPrimaryHidlHalUtils.h"
@@ -105,14 +117,23 @@
class AudioHidlTestEnvironment : public ::Environment {
public:
- virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#if MAJOR_VERSION <= 5
+ void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#endif
};
// Instance to register global tearDown
static AudioHidlTestEnvironment* environment;
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
+#include "DeviceManager.h"
+
+#if MAJOR_VERSION <= 5
class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
+#elif MAJOR_VERSION >= 6
+class HidlTest : public ::testing::Test {
+#endif
+ protected:
// Convenient member to store results
Result res;
};
@@ -201,6 +222,21 @@
ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
<< policyConfig.getFilePath();
}
+
+ protected:
+ sp<IDevicesFactory> getDevicesFactory(const std::string& factoryName) const {
+ return DevicesFactoryManager::getInstance().get(factoryName);
+ }
+
+ sp<IPrimaryDevice> getPrimaryDevice(const std::string& factoryName) const {
+ return DeviceManager::getInstance().getPrimary(factoryName);
+ }
+
+ bool isPrimaryDeviceOptional(const std::string& factoryName) const {
+ // It's OK not to have "primary" device on non-default audio HAL service.
+ return factoryName != kDefaultServiceName;
+ }
+
sp<const HwModule> mPrimaryConfig = nullptr;
};
@@ -209,34 +245,85 @@
}
//////////////////////////////////////////////////////////////////////////////
+//////////////////// Test parameter types and definitions ////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME };
+using DeviceParameter = std::tuple<std::string, std::string>;
+
+static inline std::string DeviceParameterToString(
+ const ::testing::TestParamInfo<DeviceParameter>& info) {
+#if MAJOR_VERSION <= 5
+ return std::get<PARAM_DEVICE_NAME>(info.param);
+#elif MAJOR_VERSION >= 6
+ const auto factoryName =
+ ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+ std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+ const auto& deviceName = std::get<PARAM_DEVICE_NAME>(info.param);
+ return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName;
+#endif
+}
+
+#if MAJOR_VERSION <= 5
+// For V2..5 the factory is looked up using the instance name passed
+// in the environment, only one factory is returned. This is because the VTS
+// framework will call the test for each instance. Only the primary device of
+// the factory specified in the environment is tested.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+ static std::vector<DeviceParameter> parameters = {
+ {environment->getServiceName<IDevicesFactory>(), DeviceManager::kPrimaryDevice}};
+ return parameters;
+}
+#elif MAJOR_VERSION >= 6
+// FIXME: Will be replaced with code that analyzes the audio policy config file.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+ static std::vector<DeviceParameter> parameters = [] {
+ const auto instances =
+ ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+ std::vector<DeviceParameter> result;
+ result.reserve(instances.size());
+ for (const auto& instance : instances) {
+ result.emplace_back(instance, DeviceManager::kPrimaryDevice);
+ }
+ return result;
+ }();
+ return parameters;
+}
+#endif
+
+class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest,
+ public ::testing::WithParamInterface<DeviceParameter> {
+ protected:
+ const std::string& getFactoryName() const { return std::get<PARAM_FACTORY_NAME>(GetParam()); }
+ bool isPrimaryDeviceOptional() const {
+ return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
+ }
+ sp<IDevicesFactory> getDevicesFactory() const {
+ return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
+ }
+ sp<IPrimaryDevice> getPrimaryDevice() const {
+ return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
////////////////////// getService audio_devices_factory //////////////////////
//////////////////////////////////////////////////////////////////////////////
// Test all audio devices
-class AudioHidlTest : public AudioPolicyConfigTest {
- public:
+class AudioHidlTest : public AudioHidlTestWithDeviceParameter {
+ public:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
-
- if (devicesFactory == nullptr) {
- environment->registerTearDown([] { devicesFactory.clear(); });
- devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
- environment->getServiceName<IDevicesFactory>("default"));
- }
- ASSERT_TRUE(devicesFactory != nullptr);
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp()); // setup base
+ ASSERT_TRUE(getDevicesFactory() != nullptr);
}
-
- protected:
- // Cache the devicesFactory retrieval to speed up each test by ~0.5s
- static sp<IDevicesFactory> devicesFactory;
};
-sp<IDevicesFactory> AudioHidlTest::devicesFactory;
-TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
- doc::test("Test the getService (called in SetUp)");
+TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) {
+ doc::test("Test the getService");
}
-TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) {
doc::test("Test passing an invalid parameter to openDevice");
Result result;
sp<IDevice> device;
@@ -245,11 +332,14 @@
#elif MAJOR_VERSION >= 4
auto invalidDevice = "Non existing device";
#endif
- ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
+ ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device)));
ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
ASSERT_TRUE(device == nullptr);
}
+INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()),
+ &DeviceParameterToString);
+
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// openDevice primary ///////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -257,49 +347,30 @@
// Test the primary device
class AudioPrimaryHidlTest : public AudioHidlTest {
public:
- /** Primary HAL test are NOT thread safe. */
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
-
- if (device == nullptr) {
- initPrimaryDevice();
- ASSERT_TRUE(device != nullptr);
- environment->registerTearDown([] { device.clear(); });
+ if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory";
}
+ ASSERT_TRUE(getDevice() != nullptr);
}
protected:
- // Cache the device opening to speed up each test by ~0.5s
- static sp<IPrimaryDevice> device;
-
- private:
- void initPrimaryDevice() {
- Result result;
-#if MAJOR_VERSION == 2
- sp<IDevice> baseDevice;
- ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
- returnIn(result, baseDevice)));
- ASSERT_OK(result);
- ASSERT_TRUE(baseDevice != nullptr);
-
- device = IPrimaryDevice::castFrom(baseDevice);
-#elif MAJOR_VERSION >= 4
- ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
- ASSERT_OK(result);
-#endif
- }
+ sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
};
-sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
-TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
- doc::test("Test the openDevice (called in SetUp)");
+TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+ doc::test("Test the openDevice (called during setup)");
}
-TEST_F(AudioPrimaryHidlTest, Init) {
+TEST_P(AudioPrimaryHidlTest, Init) {
doc::test("Test that the audio primary hal initialized correctly");
- ASSERT_OK(device->initCheck());
+ ASSERT_OK(getDevice()->initCheck());
}
+INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
+ ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
//////////////////////////////////////////////////////////////////////////////
///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -324,7 +395,7 @@
optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
Property initialValue = expectedInitial.value;
- ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+ ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue)));
ASSERT_RESULT(expectedResults, res);
if (res == Result::OK && expectedInitial.check == REQUIRED) {
EXPECT_EQ(expectedInitial.value, initialValue);
@@ -335,7 +406,7 @@
for (Property setValue : valuesToTest) {
SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
testing::PrintToString(setValue));
- auto ret = (device.get()->*setter)(setValue);
+ auto ret = (getDevice().get()->*setter)(setValue);
ASSERT_RESULT(expectedResults, ret);
if (ret == Result::NOT_SUPPORTED) {
doc::partialTest(propertyName + " setter is not supported");
@@ -343,7 +414,7 @@
}
Property getValue;
// Make sure the getter returns the same value just set
- ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+ ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue)));
ASSERT_RESULT(expectedResults, res);
if (res == Result::NOT_SUPPORTED) {
doc::partialTest(propertyName + " getter is not supported");
@@ -355,31 +426,34 @@
for (Property invalidValue : invalidValues) {
SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
testing::PrintToString(invalidValue));
- EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
+ EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue));
}
// Restore initial value
- EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
+ EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue));
}
};
using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
-TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) {
doc::test("Check that the mic can be muted and unmuted");
testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
// TODO: check that the mic is really muted (all sample are 0)
}
-TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
doc::test("If master mute is supported, try to mute and unmute the master output");
testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
&IDevice::getMasterMute);
// TODO: check that the master volume is really muted
}
+INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
+ ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
-TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
doc::test("Test the master volume if supported");
testAccessors<OPTIONAL>(
"master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
@@ -387,20 +461,19 @@
// TODO: check that the master volume is really changed
}
+INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest,
+ ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// AudioPatches ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
protected:
- bool areAudioPatchesSupported() {
- auto result = device->supportsAudioPatches();
- EXPECT_IS_OK(result);
- return result;
- }
+ bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
};
-TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) {
doc::test("Test if audio patches are supported");
if (!areAudioPatchesSupported()) {
doc::partialTest("Audio patches are not supported");
@@ -409,6 +482,9 @@
// TODO: test audio patches
}
+INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest,
+ ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
//////////////////////////////////////////////////////////////////////////////
//////////////// Required and recommended audio format support ///////////////
// From:
@@ -418,8 +494,7 @@
/////////// TODO: move to the beginning of the file for easier update ////////
//////////////////////////////////////////////////////////////////////////////
-class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
- public:
+struct ConfigHelper {
// for retro compatibility only test the primary device IN_BUILTIN_MIC
// FIXME: in the next audio HAL version, test all available devices
static bool primaryHasMic() {
@@ -491,21 +566,51 @@
}
};
+// 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 };
+using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig>;
+
/** Generate a test name based on an audio config.
*
* As the only parameter changing are channel mask and sample rate,
* only print those ones in the test name.
*/
-static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
- const AudioConfig& config = info.param;
- return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+static 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"
- : ::testing::PrintToString(config.channelMask));
+ ? "MONO"
+ : ::testing::PrintToString(config.channelMask));
}
+class AudioHidlTestWithDeviceConfigParameter
+ : public AudioPolicyConfigTest,
+ public ::testing::WithParamInterface<DeviceConfigParameter> {
+ protected:
+ const std::string& getFactoryName() const {
+ return std::get<PARAM_FACTORY_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+ }
+ bool isPrimaryDeviceOptional() const {
+ return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
+ }
+ sp<IDevicesFactory> getDevicesFactory() const {
+ return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
+ }
+ sp<IPrimaryDevice> getPrimaryDevice() const {
+ return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
+ }
+ const AudioConfig& getConfig() const { return std::get<PARAM_CONFIG>(GetParam()); }
+ // FIXME: Split out tests that don't require primary device
+ sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
+};
+
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// getInputBufferSize /////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -514,12 +619,21 @@
// android.hardware.microphone
// how to get this value ? is it a property ???
-class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
- public ::testing::WithParamInterface<AudioConfig> {
- protected:
+class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base
+ ASSERT_TRUE(getDevicesFactory() != nullptr);
+ if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory";
+ }
+ ASSERT_TRUE(getDevice() != nullptr);
+ }
+
+ protected:
void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
uint64_t bufferSize;
- ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+ ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
switch (res) {
case Result::INVALID_ARGUMENTS:
@@ -543,16 +657,19 @@
doc::test(
"Input buffer size must be retrievable for a format with required "
"support.");
- inputBufferSizeTest(GetParam(), true);
+ inputBufferSizeTest(getConfig(), true);
}
INSTANTIATE_TEST_CASE_P(
- RequiredInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
- &generateTestName);
+ RequiredInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
INSTANTIATE_TEST_CASE_P(
- SupportedInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
- &generateTestName);
+ SupportedInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
// Test that the recommended capture config are supported or lead to a
// INVALID_ARGUMENTS return
@@ -561,21 +678,23 @@
doc::test(
"Input buffer size should be retrievable for a format with recommended "
"support.");
- inputBufferSizeTest(GetParam(), false);
+ inputBufferSizeTest(getConfig(), false);
}
INSTANTIATE_TEST_CASE_P(
- RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
- &generateTestName);
+ RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// setScreenState ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, setScreenState) {
+TEST_P(AudioPrimaryHidlTest, setScreenState) {
doc::test("Check that the hal can receive the screen state");
for (bool turnedOn : {false, true, true, false, false}) {
- ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
+ ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn));
}
}
@@ -583,15 +702,15 @@
//////////////////////////// {get,set}Parameters /////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, getParameters) {
+TEST_P(AudioPrimaryHidlTest, getParameters) {
doc::test("Check that the hal can set and get parameters");
hidl_vec<ParameterValue> context;
hidl_vec<hidl_string> keys;
hidl_vec<ParameterValue> values;
- ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
- ASSERT_OK(Parameters::set(device, values));
+ ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values)));
+ ASSERT_OK(Parameters::set(getDevice(), values));
values.resize(0);
- ASSERT_OK(Parameters::set(device, values));
+ ASSERT_OK(Parameters::set(getDevice(), values));
}
//////////////////////////////////////////////////////////////////////////////
@@ -632,14 +751,14 @@
EXPECT_EQ(0, close(fds[1])) << errno;
}
-TEST_F(AudioPrimaryHidlTest, DebugDump) {
+TEST_P(AudioPrimaryHidlTest, DebugDump) {
doc::test("Check that the hal can dump its state without error");
- testDebugDump([](const auto& handle) { return dump(device, handle); });
+ testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); });
}
-TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
doc::test("Check that the hal dump doesn't crash on invalid arguments");
- ASSERT_OK(dump(device, hidl_handle()));
+ ASSERT_OK(dump(getDevice(), hidl_handle()));
}
//////////////////////////////////////////////////////////////////////////////
@@ -647,9 +766,17 @@
//////////////////////////////////////////////////////////////////////////////
template <class Stream>
-class OpenStreamTest : public AudioConfigPrimaryTest,
- public ::testing::WithParamInterface<AudioConfig> {
- protected:
+class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base
+ ASSERT_TRUE(getDevicesFactory() != nullptr);
+ if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory";
+ }
+ ASSERT_TRUE(getDevice() != nullptr);
+ }
+
template <class Open>
void testOpen(Open openStream, const AudioConfig& config) {
// FIXME: Open a stream without an IOHandle
@@ -684,14 +811,31 @@
Return<Result> closeStream() {
open = false;
- return stream->close();
+ auto res = stream->close();
+ stream.clear();
+ waitForStreamDestruction();
+ return res;
}
- private:
+ static void waitForStreamDestruction() {
+ // FIXME: there is no way to know when the remote IStream is being destroyed
+ // Binder does not support testing if an object is alive, thus
+ // wait for 100ms to let the binder destruction propagates and
+ // the remote device has the time to be destroyed.
+ // flushCommand makes sure all local command are sent, thus should reduce
+ // the latency between local and remote destruction.
+ IPCThreadState::self()->flushCommands();
+ usleep(100 * 1000);
+ }
+
+ bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
+
+ private:
void TearDown() override {
if (open) {
- ASSERT_OK(stream->close());
+ ASSERT_OK(closeStream());
}
+ AudioPolicyConfigTest::TearDown();
}
protected:
@@ -704,21 +848,23 @@
////////////////////////////// openOutputStream //////////////////////////////
class OutputStreamTest : public OpenStreamTest<IStreamOut> {
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ if (IsSkipped()) return; // do not attempt to use 'device'
address.device = AudioDevice::OUT_DEFAULT;
- const AudioConfig& config = GetParam();
+ const AudioConfig& config = getConfig();
// TODO: test all flag combination
auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
testOpen(
- [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+ [&](AudioIoHandle handle, AudioConfig config, auto cb) {
#if MAJOR_VERSION == 2
- return device->openOutputStream(handle, address, config, flags, cb);
+ return getDevice()->openOutputStream(handle, address, config, flags, cb);
#elif MAJOR_VERSION >= 4
- return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
+ return getDevice()->openOutputStream(handle, address, config, flags,
+ initMetadata, cb);
#endif
- },
- config);
+ },
+ config);
}
#if MAJOR_VERSION >= 4
@@ -736,33 +882,40 @@
// Open done in SetUp
}
INSTANTIATE_TEST_CASE_P(
- RequiredOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
- &generateTestName);
+ RequiredOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())),
+ &DeviceConfigParameterToString);
INSTANTIATE_TEST_CASE_P(
- SupportedOutputStreamConfig, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
- &generateTestName);
+ SupportedOutputStreamConfig, OutputStreamTest,
+ ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())),
+ &DeviceConfigParameterToString);
INSTANTIATE_TEST_CASE_P(
- RecommendedOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
- &generateTestName);
+ RecommendedOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())),
+ &DeviceConfigParameterToString);
////////////////////////////// openInputStream //////////////////////////////
class InputStreamTest : public OpenStreamTest<IStreamIn> {
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ if (IsSkipped()) return; // do not attempt to use 'device'
address.device = AudioDevice::IN_DEFAULT;
- const AudioConfig& config = GetParam();
+ const AudioConfig& config = getConfig();
// TODO: test all supported flags and source
auto flags = mkEnumBitfield(AudioInputFlag::NONE);
testOpen(
- [&](AudioIoHandle handle, AudioConfig config, auto cb) {
- return device->openInputStream(handle, address, config, flags, initMetadata, cb);
- },
- config);
+ [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+ return getDevice()->openInputStream(handle, address, config, flags,
+ initMetadata, cb);
+ },
+ config);
}
protected:
@@ -780,34 +933,28 @@
// Open done in setup
}
INSTANTIATE_TEST_CASE_P(
- RequiredInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
- &generateTestName);
+ RequiredInputStreamConfigSupport, InputStreamTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
INSTANTIATE_TEST_CASE_P(
- SupportedInputStreamConfig, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
- &generateTestName);
+ SupportedInputStreamConfig, InputStreamTest,
+ ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
INSTANTIATE_TEST_CASE_P(
- RecommendedInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
- &generateTestName);
+ RecommendedInputStreamConfigSupport, InputStreamTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(getDeviceParameters()),
+ ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+ &DeviceConfigParameterToString);
//////////////////////////////////////////////////////////////////////////////
////////////////////////////// IStream getters ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-/** Unpack the provided result.
- * If the result is not OK, register a failure and return an undefined value. */
-template <class R>
-static R extract(Return<R> ret) {
- if (!ret.isOk()) {
- EXPECT_IS_OK(ret);
- return R{};
- }
- return ret;
-}
-
/* Could not find a way to write a test for two parametrized class fixure
* thus use this macro do duplicate tests for Input and Output stream */
#define TEST_IO_STREAM(test_name, documentation, code) \
@@ -985,8 +1132,14 @@
ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
-TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
- ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+// clang-format off
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
+ auto streamCopy = stream;
+ ASSERT_OK(closeStream());
+ ASSERT_RESULT(Result::INVALID_STATE, streamCopy->close());
+ streamCopy.clear();
+ waitForStreamDestruction())
+// clang-format on
static void testCreateTooBigMmapBuffer(IStream* stream) {
MmapBufferInfo info;
@@ -1151,11 +1304,7 @@
struct Capability {
Capability(IStreamOut* stream) {
EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
- auto ret = stream->supportsDrain();
- EXPECT_IS_OK(ret);
- if (ret.isOk()) {
- drain = ret;
- }
+ drain = extract(stream->supportsDrain());
}
bool pause = false;
bool resume = false;
@@ -1167,19 +1316,6 @@
Capability(stream.get());
}
-template <class Value>
-static void checkInvalidStateOr0(Result res, Value value) {
- switch (res) {
- case Result::INVALID_STATE:
- break;
- case Result::OK:
- ASSERT_EQ(0U, value);
- break;
- default:
- FAIL() << "Unexpected result " << toString(res);
- }
-}
-
TEST_P(OutputStreamTest, GetRenderPosition) {
doc::test("A new stream render position should be 0 or INVALID_STATE");
uint32_t dspFrames;
@@ -1188,7 +1324,7 @@
doc::partialTest("getRenderPosition is not supported");
return;
}
- checkInvalidStateOr0(res, dspFrames);
+ expectValueOrFailure(res, 0U, dspFrames, Result::INVALID_STATE);
}
TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
@@ -1199,7 +1335,7 @@
doc::partialTest("getNextWriteTimestamp is not supported");
return;
}
- checkInvalidStateOr0(res, timestampUs);
+ expectValueOrFailure(res, uint64_t{0}, timestampUs, Result::INVALID_STATE);
}
/** Stub implementation of out stream callback. */
@@ -1326,19 +1462,19 @@
/////////////////////////////// PrimaryDevice ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+TEST_P(AudioPrimaryHidlTest, setVoiceVolume) {
doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
- testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+ testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); });
}
-TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
doc::test("Query and set the BT SCO NR&EC state");
testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
&IPrimaryDevice::setBtScoNrecEnabled,
&IPrimaryDevice::getBtScoNrecEnabled);
}
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
doc::test("Query and set the SCO whideband state");
testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
&IPrimaryDevice::setBtScoWidebandEnabled,
@@ -1346,15 +1482,17 @@
}
using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
-TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
doc::test("Query and set the TTY mode state");
testAccessors<OPTIONAL>(
"TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
{IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
&IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
}
+INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
+ ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
-TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
doc::test("Query and set the HAC state");
testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
&IPrimaryDevice::getHacEnabled);
@@ -1366,9 +1504,13 @@
int main(int argc, char** argv) {
environment = new AudioHidlTestEnvironment;
+ // For V2..5 it's critical to initialize environment before GTest.
+ // The environment parses the service name from the command line,
+ // then it can be used in GTest parameter generators which are
+ // initialized during the call to InitGoogleTest.
+ environment->init(&argc, argv);
::testing::AddGlobalTestEnvironment(environment);
::testing::InitGoogleTest(&argc, argv);
- environment->init(&argc, argv);
int status = RUN_ALL_TESTS();
return status;
}
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
new file mode 100644
index 0000000..b6e2db0
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+// Code in this file uses 'environment'
+#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
+#error Must be included from AudioPrimaryHidlTest.h
+#endif
+
+template <class Derived, class Key, class Interface>
+class InterfaceManager {
+ public:
+ sp<Interface> get(const Key& name) {
+ auto existing = instances.find(name);
+ if (existing != instances.end()) return existing->second;
+ auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
+ if (inserted->second) {
+ environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); });
+ }
+ return inserted->second;
+ }
+
+ // The test must check that reset was successful. Reset failure means that the test code
+ // is holding a strong reference to the device.
+ bool reset(const Key& name) __attribute__((warn_unused_result)) {
+ auto iter = instances.find(name);
+ if (iter == instances.end()) return true;
+ ::android::wp<Interface> weak = iter->second;
+ instances.erase(iter);
+ if (weak.promote() != nullptr) return false;
+ waitForInstanceDestruction();
+ return true;
+ }
+
+ static void waitForInstanceDestruction() {
+ // FIXME: there is no way to know when the remote IDevice is being destroyed
+ // Binder does not support testing if an object is alive, thus
+ // wait for 100ms to let the binder destruction propagates and
+ // the remote device has the time to be destroyed.
+ // flushCommand makes sure all local command are sent, thus should reduce
+ // the latency between local and remote destruction.
+ IPCThreadState::self()->flushCommands();
+ usleep(100 * 1000);
+ }
+
+ protected:
+ std::map<Key, sp<Interface>> instances;
+};
+
+class DevicesFactoryManager
+ : public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
+ public:
+ static DevicesFactoryManager& getInstance() {
+ static DevicesFactoryManager instance;
+ return instance;
+ }
+ static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
+#if MAJOR_VERSION <= 5
+ return ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(name);
+#elif MAJOR_VERSION >= 6
+ return IDevicesFactory::getService(name);
+#endif
+ }
+};
+
+using FactoryAndDevice = std::tuple<std::string, std::string>;
+class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
+ public:
+ static DeviceManager& getInstance() {
+ static DeviceManager instance;
+ return instance;
+ }
+ static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
+ auto [factoryName, name] = factoryAndDevice;
+ sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
+ return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
+ }
+ using InterfaceManager::reset;
+
+ static constexpr const char* kPrimaryDevice = "primary";
+
+ sp<IDevice> get(const std::string& factoryName, const std::string& name) {
+ return InterfaceManager::get(std::make_tuple(factoryName, name));
+ }
+ sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
+ sp<IDevice> device = get(factoryName, kPrimaryDevice);
+ return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
+ }
+ bool reset(const std::string& factoryName, const std::string& name)
+ __attribute__((warn_unused_result)) {
+ return InterfaceManager::reset(std::make_tuple(factoryName, name));
+ }
+ bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
+ return reset(factoryName, kPrimaryDevice);
+ }
+
+ private:
+ static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
+ if (factory == nullptr) return nullptr;
+ sp<IDevice> device;
+#if MAJOR_VERSION >= 4
+ Result result;
+ auto ret = factory->openDevice(name, returnIn(result, device));
+ if (!ret.isOk() || result != Result::OK || device == nullptr) {
+ ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
+ name.c_str(), ret.description().c_str(), result, device.get());
+ return nullptr;
+ }
+#else
+ (void)name;
+#endif
+ return device;
+ }
+
+ static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
+ if (factory == nullptr) return nullptr;
+ Result result;
+ sp<IDevice> device;
+#if MAJOR_VERSION == 2
+ auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
+#elif MAJOR_VERSION >= 4
+ auto ret = factory->openPrimaryDevice(returnIn(result, device));
+#endif
+ if (!ret.isOk() || result != Result::OK || device == nullptr) {
+ ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
+ ret.description().c_str(), result, device.get());
+ return nullptr;
+ }
+ return device;
+ }
+};
diff --git a/audio/effect/6.0/Android.bp b/audio/effect/6.0/Android.bp
new file mode 100644
index 0000000..b6184f3
--- /dev/null
+++ b/audio/effect/6.0/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio.effect@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IAcousticEchoCancelerEffect.hal",
+ "IAutomaticGainControlEffect.hal",
+ "IBassBoostEffect.hal",
+ "IDownmixEffect.hal",
+ "IEffect.hal",
+ "IEffectBufferProviderCallback.hal",
+ "IEffectsFactory.hal",
+ "IEnvironmentalReverbEffect.hal",
+ "IEqualizerEffect.hal",
+ "ILoudnessEnhancerEffect.hal",
+ "INoiseSuppressionEffect.hal",
+ "IPresetReverbEffect.hal",
+ "IVirtualizerEffect.hal",
+ "IVisualizerEffect.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@6.0",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/effect/6.0/IAcousticEchoCancelerEffect.hal b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f7d769f
--- /dev/null
+++ b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+ /**
+ * Sets echo delay value in milliseconds.
+ */
+ setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+ /**
+ * Gets echo delay value in milliseconds.
+ */
+ getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/6.0/IAutomaticGainControlEffect.hal b/audio/effect/6.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d264cd4
--- /dev/null
+++ b/audio/effect/6.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+ /**
+ * Sets target level in millibels.
+ */
+ setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+ /**
+ * Gets target level.
+ */
+ getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+ /**
+ * Sets gain in the compression range in millibels.
+ */
+ setCompGain(int16_t compGainMb) generates (Result retval);
+
+ /**
+ * Gets gain in the compression range.
+ */
+ getCompGain() generates (Result retval, int16_t compGainMb);
+
+ /**
+ * Enables or disables limiter.
+ */
+ setLimiterEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Returns whether limiter is enabled.
+ */
+ isLimiterEnabled() generates (Result retval, bool enabled);
+
+ struct AllProperties {
+ int16_t targetLevelMb;
+ int16_t compGainMb;
+ bool limiterEnabled;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IBassBoostEffect.hal b/audio/effect/6.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..91c4092
--- /dev/null
+++ b/audio/effect/6.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+ /**
+ * Returns whether setting bass boost strength is supported.
+ */
+ isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /**
+ * Sets bass boost strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /**
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/6.0/IDownmixEffect.hal b/audio/effect/6.0/IDownmixEffect.hal
new file mode 100644
index 0000000..e3a38e2
--- /dev/null
+++ b/audio/effect/6.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+ enum Type : int32_t {
+ STRIP, // throw away the extra channels
+ FOLD // mix the extra channels with FL/FR
+ };
+
+ /**
+ * Sets the current downmix preset.
+ */
+ setType(Type preset) generates (Result retval);
+
+ /**
+ * Gets the current downmix preset.
+ */
+ getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal
new file mode 100644
index 0000000..b35afee
--- /dev/null
+++ b/audio/effect/6.0/IEffect.hal
@@ -0,0 +1,418 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+ /**
+ * Initialize effect engine--all configurations return to default.
+ *
+ * @return retval operation completion status.
+ */
+ @entry
+ init() generates (Result retval);
+
+ /**
+ * Apply new audio parameters configurations for input and output buffers.
+ * The provider callbacks may be empty, but in this case the buffer
+ * must be provided in the EffectConfig structure.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ setConfig(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /**
+ * Reset the effect engine. Keep configuration but resets state and buffer
+ * content.
+ *
+ * @return retval operation completion status.
+ */
+ reset() generates (Result retval);
+
+ /**
+ * Enable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"prepareForProcessing"})
+ enable() generates (Result retval);
+
+ /**
+ * Disable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"close"})
+ disable() generates (Result retval);
+
+ /**
+ * Set the rendering device the audio output path is connected to. The
+ * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+ * descriptor to receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the output chain.
+ *
+ * @param device output device specification.
+ * @return retval operation completion status.
+ */
+ setDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+ /**
+ * Set and get volume. Used by audio framework to delegate volume control to
+ * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+ * flag in its descriptor to receive this command. The effect engine must
+ * return the volume that should be applied before the effect is
+ * processed. The overall volume (the volume actually applied by the effect
+ * engine multiplied by the returned value) should match the value indicated
+ * in the command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return result updated volume values.
+ * @return retval operation completion status.
+ */
+ setAndGetVolume(vec<uint32_t> volumes)
+ generates (Result retval, vec<uint32_t> result);
+
+ /**
+ * Notify the effect of the volume change. The effect implementation must
+ * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+ * command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return retval operation completion status.
+ */
+ volumeChangeNotification(vec<uint32_t> volumes)
+ generates (Result retval);
+
+ /**
+ * Set the audio mode. The effect implementation must set
+ * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+ * when the audio mode changes.
+ *
+ * @param mode desired audio mode.
+ * @return retval operation completion status.
+ */
+ setAudioMode(AudioMode mode) generates (Result retval);
+
+ /**
+ * Apply new audio parameters configurations for input and output buffers of
+ * reverse stream. An example of reverse stream is the echo reference
+ * supplied to an Acoustic Echo Canceler.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ setConfigReverse(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /**
+ * Set the capture device the audio input path is connected to. The effect
+ * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+ * receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param device input device specification.
+ * @return retval operation completion status.
+ */
+ setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+ /**
+ * Read audio parameters configurations for input and output buffers.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ getConfig() generates (Result retval, EffectConfig config);
+
+ /**
+ * Read audio parameters configurations for input and output buffers of
+ * reverse stream.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ getConfigReverse() generates (Result retval, EffectConfig config);
+
+ /**
+ * Queries for supported combinations of main and auxiliary channels
+ * (e.g. for a multi-microphone noise suppressor).
+ *
+ * @param maxConfigs maximum number of the combinations to return.
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+ * the number of supported combinations exceeds 'maxConfigs'.
+ * @return result list of configuration descriptors.
+ */
+ getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+ generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+ /**
+ * Retrieves the current configuration of main and auxiliary channels.
+ *
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code.
+ * @return result configuration descriptor.
+ */
+ getAuxChannelsConfig()
+ generates (Result retval, EffectAuxChannelsConfig result);
+
+ /**
+ * Sets the current configuration of main and auxiliary channels.
+ *
+ * @return retval operation completion status; absence of the feature
+ * support is indicated using NOT_SUPPORTED code.
+ */
+ setAuxChannelsConfig(EffectAuxChannelsConfig config)
+ generates (Result retval);
+
+ /**
+ * Set the audio source the capture path is configured for (Camcorder, voice
+ * recognition...).
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param source source descriptor.
+ * @return retval operation completion status.
+ */
+ setAudioSource(AudioSource source) generates (Result retval);
+
+ /**
+ * This command indicates if the playback thread the effect is attached to
+ * is offloaded or not, and updates the I/O handle of the playback thread
+ * the effect is attached to.
+ *
+ * @param param effect offload descriptor.
+ * @return retval operation completion status.
+ */
+ offload(EffectOffloadParameter param) generates (Result retval);
+
+ /**
+ * Returns the effect descriptor.
+ *
+ * @return retval operation completion status.
+ * @return descriptor effect descriptor.
+ */
+ getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+ /**
+ * Set up required transports for passing audio buffers to the effect.
+ *
+ * The transport consists of shared memory and a message queue for reporting
+ * effect processing operation status. The shared memory is set up
+ * separately using 'setProcessBuffers' method.
+ *
+ * Processing is requested by setting 'REQUEST_PROCESS' or
+ * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+ * queue. The result of processing may be one of the following:
+ * OK if there were no errors during processing;
+ * INVALID_ARGUMENTS if audio buffers are invalid;
+ * INVALID_STATE if the engine has finished the disable phase;
+ * NOT_INITIALIZED if the audio buffers were not set;
+ * NOT_SUPPORTED if the requested processing type is not supported by
+ * the effect.
+ *
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * 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);
+
+ /**
+ * Set up input and output buffers for processing audio data. The effect
+ * may modify both the input and the output buffer during the operation.
+ * Buffers may be set multiple times during effect lifetime.
+ *
+ * The input and the output buffer may be reused between different effects,
+ * and the input buffer may be used as an output buffer. Buffers are
+ * distinguished using 'AudioBuffer.id' field.
+ *
+ * @param inBuffer input audio buffer.
+ * @param outBuffer output audio buffer.
+ * @return retval OK if both buffers were mapped successfully.
+ * INVALID_ARGUMENTS if there was a problem with mapping
+ * any of the buffers.
+ */
+ setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer)
+ generates (Result retval);
+
+ /**
+ * Execute a vendor specific command on the effect. The command code
+ * and data, as well as result data are not interpreted by Android
+ * Framework and are passed as-is between the application and the effect.
+ *
+ * The effect must use standard POSIX.1-2001 error codes for the operation
+ * completion status.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param commandId the ID of the command.
+ * @param data command data.
+ * @param resultMaxSize maximum size in bytes of the result; can be 0.
+ * @return status command completion status.
+ * @return result result data.
+ */
+ command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+ generates (int32_t status, vec<uint8_t> result);
+
+ /**
+ * Set a vendor-specific parameter and apply it immediately. The parameter
+ * code and data are not interpreted by Android Framework and are passed
+ * as-is between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown or if provided parameter data is invalid. If the effect does not
+ * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param value the value of the parameter.
+ * @return retval operation completion status.
+ */
+ setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+ generates (Result retval);
+
+ /**
+ * Get a vendor-specific parameter value. The parameter code and returned
+ * data are not interpreted by Android Framework and are passed as-is
+ * between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown. If the effect does not support setting vendor-specific
+ * parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param valueMaxSize maximum size in bytes of the value.
+ * @return retval operation completion status.
+ * @return result the value of the parameter.
+ */
+ getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+ generates (Result retval, vec<uint8_t> value);
+
+ /**
+ * Get supported configs for a vendor-specific feature. The configs returned
+ * are not interpreted by Android Framework and are passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific feature
+ * configs, it must return NOT_SUPPORTED. If the feature is supported but
+ * the total number of supported configurations exceeds the maximum number
+ * indicated by the caller, the method must return RESULT_TOO_BIG.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param maxConfigs maximum number of configs to return.
+ * @param configSize size of each config in bytes.
+ * @return retval operation completion status.
+ * @return configsCount number of configs returned.
+ * @return configsData data for all the configs returned.
+ */
+ getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize) generates (
+ Result retval,
+ uint32_t configsCount,
+ vec<uint8_t> configsData);
+
+ /**
+ * Get the current config for a vendor-specific feature. The config returned
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configSize size of the config in bytes.
+ * @return retval operation completion status.
+ * @return configData config data.
+ */
+ getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+ generates (Result retval, vec<uint8_t> configData);
+
+ /**
+ * Set the current config for a vendor-specific feature. The config data
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configData config data.
+ * @return retval operation completion status.
+ */
+ setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+ generates (Result retval);
+
+ /**
+ * Called by the framework to deinitialize the effect and free up
+ * all the currently allocated resources. It is recommended to close
+ * the effect on the client side as soon as it is becomes unused.
+ *
+ * @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/6.0/IEffectBufferProviderCallback.hal b/audio/effect/6.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..097528d
--- /dev/null
+++ b/audio/effect/6.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * 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.audio.effect@6.0;
+
+/**
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+ /**
+ * Called to retrieve a buffer where data should read from by 'process'
+ * function.
+ *
+ * @return buffer audio buffer for processing
+ */
+ getBuffer() generates (AudioBuffer buffer);
+
+ /**
+ * Called to provide a buffer with the data written by 'process' function.
+ *
+ * @param buffer audio buffer for processing
+ */
+ putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
new file mode 100644
index 0000000..e08b2de
--- /dev/null
+++ b/audio/effect/6.0/IEffectsFactory.hal
@@ -0,0 +1,58 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEffectsFactory {
+ /**
+ * Returns descriptors of different effects in all loaded libraries.
+ *
+ * @return retval operation completion status.
+ * @return result list of effect descriptors.
+ */
+ getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+ /**
+ * Returns a descriptor of a particular effect.
+ *
+ * @return retval operation completion status.
+ * @return result effect descriptor.
+ */
+ getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+ /**
+ * Creates an effect engine of the specified type. To release the effect
+ * engine, it is necessary to release references to the returned effect
+ * object.
+ *
+ * @param uid effect uuid.
+ * @param session audio session to which this effect instance will be
+ * attached. All effects created with the same session ID
+ * are connected in series and process the same signal
+ * stream.
+ * @param ioHandle identifies the output or input stream this effect is
+ * directed to in audio HAL.
+ * @return retval operation completion status.
+ * @return result the interface for the created effect.
+ * @return effectId the unique ID of the effect to be used with
+ * IStream::addEffect and IStream::removeEffect methods.
+ */
+ createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+ generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/6.0/IEnvironmentalReverbEffect.hal b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..8887533
--- /dev/null
+++ b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+ /**
+ * Sets whether the effect should be bypassed.
+ */
+ setBypass(bool bypass) generates (Result retval);
+
+ /**
+ * Gets whether the effect should be bypassed.
+ */
+ getBypass() generates (Result retval, bool bypass);
+
+ enum ParamRange : int16_t {
+ ROOM_LEVEL_MIN = -6000,
+ ROOM_LEVEL_MAX = 0,
+ ROOM_HF_LEVEL_MIN = -4000,
+ ROOM_HF_LEVEL_MAX = 0,
+ DECAY_TIME_MIN = 100,
+ DECAY_TIME_MAX = 20000,
+ DECAY_HF_RATIO_MIN = 100,
+ DECAY_HF_RATIO_MAX = 1000,
+ REFLECTIONS_LEVEL_MIN = -6000,
+ REFLECTIONS_LEVEL_MAX = 0,
+ REFLECTIONS_DELAY_MIN = 0,
+ REFLECTIONS_DELAY_MAX = 65,
+ REVERB_LEVEL_MIN = -6000,
+ REVERB_LEVEL_MAX = 0,
+ REVERB_DELAY_MIN = 0,
+ REVERB_DELAY_MAX = 65,
+ DIFFUSION_MIN = 0,
+ DIFFUSION_MAX = 1000,
+ DENSITY_MIN = 0,
+ DENSITY_MAX = 1000
+ };
+
+ /**
+ * Sets the room level.
+ */
+ setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+ /**
+ * Gets the room level.
+ */
+ getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+ /**
+ * Sets the room high frequencies level.
+ */
+ setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+ /**
+ * Gets the room high frequencies level.
+ */
+ getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+ /**
+ * Sets the room decay time.
+ */
+ setDecayTime(uint32_t decayTime) generates (Result retval);
+
+ /**
+ * Gets the room decay time.
+ */
+ getDecayTime() generates (Result retval, uint32_t decayTime);
+
+ /**
+ * Sets the ratio of high frequencies decay.
+ */
+ setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+ /**
+ * Gets the ratio of high frequencies decay.
+ */
+ getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+ /**
+ * Sets the level of reflections in the room.
+ */
+ setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+ /**
+ * Gets the level of reflections in the room.
+ */
+ getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+ /**
+ * Sets the reflections delay in the room.
+ */
+ setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+ /**
+ * Gets the reflections delay in the room.
+ */
+ getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+ /**
+ * Sets the reverb level of the room.
+ */
+ setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+ /**
+ * Gets the reverb level of the room.
+ */
+ getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+ /**
+ * Sets the reverb delay of the room.
+ */
+ setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+ /**
+ * Gets the reverb delay of the room.
+ */
+ getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+ /**
+ * Sets room diffusion.
+ */
+ setDiffusion(int16_t diffusion) generates (Result retval);
+
+ /**
+ * Gets room diffusion.
+ */
+ getDiffusion() generates (Result retval, int16_t diffusion);
+
+ /**
+ * Sets room wall density.
+ */
+ setDensity(int16_t density) generates (Result retval);
+
+ /**
+ * Gets room wall density.
+ */
+ getDensity() generates (Result retval, int16_t density);
+
+ struct AllProperties {
+ int16_t roomLevel; // in millibels, range -6000 to 0
+ int16_t roomHfLevel; // in millibels, range -4000 to 0
+ uint32_t decayTime; // in milliseconds, range 100 to 20000
+ int16_t decayHfRatio; // in permilles, range 100 to 1000
+ int16_t reflectionsLevel; // in millibels, range -6000 to 0
+ uint32_t reflectionsDelay; // in milliseconds, range 0 to 65
+ int16_t reverbLevel; // in millibels, range -6000 to 0
+ uint32_t reverbDelay; // in milliseconds, range 0 to 65
+ int16_t diffusion; // in permilles, range 0 to 1000
+ int16_t density; // in permilles, range 0 to 1000
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IEqualizerEffect.hal b/audio/effect/6.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..962d518
--- /dev/null
+++ b/audio/effect/6.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+ /**
+ * Gets the number of frequency bands that the equalizer supports.
+ */
+ getNumBands() generates (Result retval, uint16_t numBands);
+
+ /**
+ * Returns the minimum and maximum band levels supported.
+ */
+ getLevelRange()
+ generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+ /**
+ * Sets the gain for the given equalizer band.
+ */
+ setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+ /**
+ * Gets the gain for the given equalizer band.
+ */
+ getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+ /**
+ * Gets the center frequency of the given band, in milliHertz.
+ */
+ getBandCenterFrequency(uint16_t band)
+ generates (Result retval, uint32_t centerFreqmHz);
+
+ /**
+ * Gets the frequency range of the given frequency band, in milliHertz.
+ */
+ getBandFrequencyRange(uint16_t band)
+ generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+ /**
+ * Gets the band that has the most effect on the given frequency
+ * in milliHertz.
+ */
+ getBandForFrequency(uint32_t freqmHz)
+ generates (Result retval, uint16_t band);
+
+ /**
+ * Gets the names of all presets the equalizer supports.
+ */
+ getPresetNames() generates (Result retval, vec<string> names);
+
+ /**
+ * Sets the current preset using the index of the preset in the names
+ * vector returned via 'getPresetNames'.
+ */
+ setCurrentPreset(uint16_t preset) generates (Result retval);
+
+ /**
+ * Gets the current preset.
+ */
+ getCurrentPreset() generates (Result retval, uint16_t preset);
+
+ struct AllProperties {
+ uint16_t curPreset;
+ vec<int16_t> bandLevels;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/ILoudnessEnhancerEffect.hal b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..73dc818
--- /dev/null
+++ b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+ /**
+ * Sets target gain expressed in millibels.
+ */
+ setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+ /**
+ * Gets target gain expressed in millibels.
+ */
+ getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/6.0/INoiseSuppressionEffect.hal b/audio/effect/6.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..16dee57
--- /dev/null
+++ b/audio/effect/6.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+ enum Level : int32_t {
+ LOW,
+ MEDIUM,
+ HIGH
+ };
+
+ /**
+ * Sets suppression level.
+ */
+ setSuppressionLevel(Level level) generates (Result retval);
+
+ /**
+ * Gets suppression level.
+ */
+ getSuppressionLevel() generates (Result retval, Level level);
+
+ enum Type : int32_t {
+ SINGLE_CHANNEL,
+ MULTI_CHANNEL
+ };
+
+ /**
+ * Set suppression type.
+ */
+ setSuppressionType(Type type) generates (Result retval);
+
+ /**
+ * Get suppression type.
+ */
+ getSuppressionType() generates (Result retval, Type type);
+
+ struct AllProperties {
+ Level level;
+ Type type;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IPresetReverbEffect.hal b/audio/effect/6.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..d00c8af
--- /dev/null
+++ b/audio/effect/6.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+ enum Preset : int32_t {
+ NONE, // no reverb or reflections
+ SMALLROOM, // a small room less than five meters in length
+ MEDIUMROOM, // a medium room with a length of ten meters or less
+ LARGEROOM, // a large-sized room suitable for live performances
+ MEDIUMHALL, // a medium-sized hall
+ LARGEHALL, // a large-sized hall suitable for a full orchestra
+ PLATE, // synthesis of the traditional plate reverb
+ LAST = PLATE
+ };
+
+ /**
+ * Sets the current preset.
+ */
+ setPreset(Preset preset) generates (Result retval);
+
+ /**
+ * Gets the current preset.
+ */
+ getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/6.0/IVirtualizerEffect.hal b/audio/effect/6.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..5967b33
--- /dev/null
+++ b/audio/effect/6.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+ /**
+ * Returns whether setting virtualization strength is supported.
+ */
+ isStrengthSupported() generates (bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /**
+ * Sets virtualization strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /**
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+
+ struct SpeakerAngle {
+ /** Speaker channel mask */
+ bitfield<AudioChannelMask> mask;
+ // all angles are expressed in degrees and
+ // are relative to the listener.
+ int16_t azimuth; // 0 is the direction the listener faces
+ // 180 is behind the listener
+ // -90 is to their left
+ int16_t elevation; // 0 is the horizontal plane
+ // +90 is above the listener, -90 is below
+ };
+ /**
+ * Retrieves virtual speaker angles for the given channel mask on the
+ * specified device.
+ */
+ getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+ generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+ /**
+ * Forces the virtualizer effect for the given output device.
+ */
+ forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+ /**
+ * Returns audio device reflecting the current virtualization mode,
+ * AUDIO_DEVICE_NONE when not virtualizing.
+ */
+ getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/6.0/IVisualizerEffect.hal b/audio/effect/6.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..3df3e6f
--- /dev/null
+++ b/audio/effect/6.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+ enum CaptureSizeRange : int32_t {
+ MAX = 1024, // maximum capture size in samples
+ MIN = 128 // minimum capture size in samples
+ };
+
+ /**
+ * Sets the number PCM samples in the capture.
+ */
+ setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+ /**
+ * Gets the number PCM samples in the capture.
+ */
+ getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+ enum ScalingMode : int32_t {
+ // Keep in sync with SCALING_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NORMALIZED = 0,
+ AS_PLAYED = 1
+ };
+
+ /**
+ * Specifies the way the captured data is scaled.
+ */
+ setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+ /**
+ * Retrieves the way the captured data is scaled.
+ */
+ getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+ /**
+ * Informs the visualizer about the downstream latency.
+ */
+ setLatency(uint32_t latencyMs) generates (Result retval);
+
+ /**
+ * Gets the downstream latency.
+ */
+ getLatency() generates (Result retval, uint32_t latencyMs);
+
+ enum MeasurementMode : int32_t {
+ // Keep in sync with MEASUREMENT_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NONE = 0x0,
+ PEAK_RMS = 0x1
+ };
+
+ /**
+ * Specifies which measurements are to be made.
+ */
+ setMeasurementMode(MeasurementMode measurementMode)
+ generates (Result retval);
+
+ /**
+ * Retrieves which measurements are to be made.
+ */
+ getMeasurementMode() generates (
+ Result retval, MeasurementMode measurementMode);
+
+ /**
+ * Retrieves the latest PCM snapshot captured by the visualizer engine. The
+ * number of samples to capture is specified by 'setCaptureSize' parameter.
+ *
+ * @return retval operation completion status.
+ * @return samples samples in 8 bit unsigned format (0 = 0x80)
+ */
+ capture() generates (Result retval, vec<uint8_t> samples);
+
+ struct Measurement {
+ MeasurementMode mode; // discriminator
+ union Values {
+ struct PeakAndRms {
+ int32_t peakMb; // millibels
+ int32_t rmsMb; // millibels
+ } peakAndRms;
+ } value;
+ };
+ /**
+ * Retrieves the latest measurements. The measurements to be made
+ * are specified by 'setMeasurementMode' parameter.
+ *
+ * @return retval operation completion status.
+ * @return result measurement.
+ */
+ measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/6.0/types.hal b/audio/effect/6.0/types.hal
new file mode 100644
index 0000000..dd5a4ad
--- /dev/null
+++ b/audio/effect/6.0/types.hal
@@ -0,0 +1,301 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ NOT_SUPPORTED,
+ RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description | bits | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection | 0..2 | 0 insert: after track process
+ * | mode | | 1 auxiliary: connect to track auxiliary
+ * | | | output and use send level
+ * | | | 2 replace: replaces track process function;
+ * | | | must implement SRC, volume and mono to stereo.
+ * | | | 3 pre processing: applied below audio HAL on in
+ * | | | 4 post processing: applied below audio HAL on out
+ * | | | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion | 3..5 | 0 none
+ * | preference | | 1 first of the chain
+ * | | | 2 last of the chain
+ * | | | 3 exclusive (only effect in the insert chain)
+ * | | | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume | 6..8 | 0 none
+ * | management | | 1 implements volume control
+ * | | | 2 requires volume indication
+ * | | | 3 monitors requested volume
+ * | | | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device | 9..11 | 0 none
+ * | indication | | 1 requires device updates
+ * | | | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input | 12..13 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request input.
+ * | | | buffers.
+ * | | | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output | 14..15 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request output
+ * | | | buffers.
+ * | | | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware | 16..17 | 0 No hardware acceleration
+ * | acceleration | | 1 non tunneled hw acceleration: the process()
+ * | | | function reads the samples, send them to HW
+ * | | | accelerated effect processor, reads back
+ * | | | the processed samples and returns them
+ * | | | to the output buffer.
+ * | | | 2 tunneled hw acceleration: the process()
+ * | | | function is transparent. The effect interface
+ * | | | is only used to control the effect engine.
+ * | | | This mode is relevant for global effects
+ * | | | actually applied by the audio hardware on
+ * | | | the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode | 18..19 | 0 none
+ * | indication | | 1 requires audio mode updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source | 20..21 | 0 none
+ * | indication | | 1 requires audio source updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22 | 0 The effect cannot be offloaded to an audio DSP
+ * | supported | | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process | 23 | 0 The effect implements a process function.
+ * | function | | 1 The effect does not implement a process
+ * | not | | function: enabling the effect has no impact
+ * | implemented | | on latency or CPU load.
+ * | | | Effect implementations setting this flag do not
+ * | | | have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+ // Insert mode
+ TYPE_SHIFT = 0,
+ TYPE_SIZE = 3,
+ TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+ TYPE_INSERT = 0 << TYPE_SHIFT,
+ TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+ TYPE_REPLACE = 2 << TYPE_SHIFT,
+ TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+ TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+ // Insert preference
+ INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+ INSERT_SIZE = 3,
+ INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+ INSERT_ANY = 0 << INSERT_SHIFT,
+ INSERT_FIRST = 1 << INSERT_SHIFT,
+ INSERT_LAST = 2 << INSERT_SHIFT,
+ INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+ // Volume control
+ VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+ VOLUME_SIZE = 3,
+ VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+ VOLUME_CTRL = 1 << VOLUME_SHIFT,
+ VOLUME_IND = 2 << VOLUME_SHIFT,
+ VOLUME_MONITOR = 3 << VOLUME_SHIFT,
+ VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+ // Device indication
+ DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+ DEVICE_SIZE = 3,
+ DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+ DEVICE_IND = 1 << DEVICE_SHIFT,
+ DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+ // Sample input modes
+ INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+ INPUT_SIZE = 2,
+ INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+ INPUT_DIRECT = 1 << INPUT_SHIFT,
+ INPUT_PROVIDER = 2 << INPUT_SHIFT,
+ INPUT_BOTH = 3 << INPUT_SHIFT,
+
+ // Sample output modes
+ OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+ OUTPUT_SIZE = 2,
+ OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+ OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+ OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+ OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+ // Hardware acceleration mode
+ HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+ HW_ACC_SIZE = 2,
+ HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+ HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+ HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+ // Audio mode indication
+ AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+ AUDIO_MODE_SIZE = 2,
+ AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+ // Audio source indication
+ AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+ AUDIO_SOURCE_SIZE = 2,
+ AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+ // Effect offload indication
+ OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+ OFFLOAD_SIZE = 1,
+ OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+ OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+ // Effect has no process indication
+ NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+ NO_PROCESS_SIZE = 1,
+ NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+ NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+ Uuid type; // UUID of to the OpenSL ES interface implemented
+ // by this effect
+ Uuid uuid; // UUID for this particular implementation
+ bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
+ uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units
+ // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+ uint16_t memoryUsage; // data memory usage expressed in KB and includes
+ // only dynamically allocated memory
+ uint8_t[64] name; // human readable effect name
+ uint8_t[64] implementor; // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing. Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+ uint64_t id;
+ uint32_t frameCount;
+ memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+ ACCESS_WRITE,
+ ACCESS_READ,
+ ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+ BUFFER = 0x0001, // buffer field
+ SMP_RATE = 0x0002, // samplingRate
+ CHANNELS = 0x0004, // channels
+ FORMAT = 0x0008, // format
+ ACC_MODE = 0x0010, // accessMode
+ // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+ AudioBuffer buffer;
+ uint32_t samplingRateHz;
+ bitfield<AudioChannelMask> channels;
+ AudioFormat format;
+ EffectBufferAccess accessMode;
+ bitfield<EffectConfigParameters> mask;
+};
+
+struct EffectConfig {
+ EffectBufferConfig inputCfg;
+ EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+ AUX_CHANNELS, // supports auxiliary channels
+ // (e.g. dual mic noise suppressor)
+ CNT
+};
+
+struct EffectAuxChannelsConfig {
+ bitfield<AudioChannelMask> mainChannels; // channel mask for main channels
+ bitfield<AudioChannelMask> auxChannels; // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+ bool isOffload; // true if the playback thread the effect
+ // is attached to is offloaded
+ AudioIoHandle ioHandle; // io handle of the playback thread
+ // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ DONE_PROCESSING = 1 << 0,
+ REQUEST_PROCESS = 1 << 1,
+ REQUEST_PROCESS_REVERSE = 1 << 2,
+ REQUEST_QUIT = 1 << 3,
+ REQUEST_PROCESS_ALL =
+ REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp
new file mode 100644
index 0000000..353686b
--- /dev/null
+++ b/audio/effect/6.0/xml/Android.bp
@@ -0,0 +1,6 @@
+
+xsd_config {
+ name: "audio_effects_conf_V6_0",
+ srcs: ["audio_effects_conf.xsd"],
+ package_name: "audio.effects.V6_0",
+}
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
new file mode 100644
index 0000000..2021639
--- /dev/null
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -0,0 +1,132 @@
+// Signature format: 2.0
+package audio.effects.V6_0 {
+
+ public class AudioEffectsConf {
+ ctor public AudioEffectsConf();
+ method public audio.effects.V6_0.EffectsType getEffects();
+ method public audio.effects.V6_0.LibrariesType getLibraries();
+ method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
+ method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
+ method public audio.effects.V6_0.VersionType getVersion();
+ method public void setEffects(audio.effects.V6_0.EffectsType);
+ method public void setLibraries(audio.effects.V6_0.LibrariesType);
+ method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
+ method public void setPreprocess(audio.effects.V6_0.AudioEffectsConf.Preprocess);
+ method public void setVersion(audio.effects.V6_0.VersionType);
+ }
+
+ public static class AudioEffectsConf.Postprocess {
+ ctor public AudioEffectsConf.Postprocess();
+ method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
+ }
+
+ public static class AudioEffectsConf.Preprocess {
+ ctor public AudioEffectsConf.Preprocess();
+ method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
+ }
+
+ public class EffectImplType {
+ ctor public EffectImplType();
+ method public String getLibrary();
+ method public String getUuid();
+ method public void setLibrary(String);
+ method public void setUuid(String);
+ }
+
+ public class EffectProxyType extends audio.effects.V6_0.EffectType {
+ ctor public EffectProxyType();
+ method public audio.effects.V6_0.EffectImplType getLibhw();
+ method public audio.effects.V6_0.EffectImplType getLibsw();
+ method public void setLibhw(audio.effects.V6_0.EffectImplType);
+ method public void setLibsw(audio.effects.V6_0.EffectImplType);
+ }
+
+ public class EffectType extends audio.effects.V6_0.EffectImplType {
+ ctor public EffectType();
+ method public String getName();
+ method public void setName(String);
+ }
+
+ public class EffectsType {
+ ctor public EffectsType();
+ method public java.util.List<audio.effects.V6_0.EffectProxyType> getEffectProxy_optional();
+ method public java.util.List<audio.effects.V6_0.EffectType> getEffect_optional();
+ }
+
+ public class LibrariesType {
+ ctor public LibrariesType();
+ method public java.util.List<audio.effects.V6_0.LibrariesType.Library> getLibrary();
+ }
+
+ public static class LibrariesType.Library {
+ ctor public LibrariesType.Library();
+ method public String getName();
+ method public String getPath();
+ method public void setName(String);
+ method public void setPath(String);
+ }
+
+ public enum StreamInputType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+ enum_constant public static final audio.effects.V6_0.StreamInputType mic;
+ enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_communication;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_downlink;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_performance;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_recognition;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_uplink;
+ }
+
+ public enum StreamOutputType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType music;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType notification;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType ring;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType system;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType tts;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType voice_call;
+ }
+
+ public class StreamPostprocessType extends audio.effects.V6_0.StreamProcessingType {
+ ctor public StreamPostprocessType();
+ method public audio.effects.V6_0.StreamOutputType getType();
+ method public void setType(audio.effects.V6_0.StreamOutputType);
+ }
+
+ public class StreamPreprocessType extends audio.effects.V6_0.StreamProcessingType {
+ ctor public StreamPreprocessType();
+ method public audio.effects.V6_0.StreamInputType getType();
+ method public void setType(audio.effects.V6_0.StreamInputType);
+ }
+
+ public class StreamProcessingType {
+ ctor public StreamProcessingType();
+ method public java.util.List<audio.effects.V6_0.StreamProcessingType.Apply> getApply();
+ }
+
+ public static class StreamProcessingType.Apply {
+ ctor public StreamProcessingType.Apply();
+ method public String getEffect();
+ method public void setEffect(String);
+ }
+
+ public enum VersionType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.VersionType _2_0;
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static audio.effects.V6_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/effect/6.0/xml/api/last_current.txt b/audio/effect/6.0/xml/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_current.txt
diff --git a/audio/effect/6.0/xml/api/last_removed.txt b/audio/effect/6.0/xml/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_removed.txt
diff --git a/audio/effect/6.0/xml/api/removed.txt b/audio/effect/6.0/xml/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/effect/6.0/xml/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 120000
index 0000000..9d85fa7
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1 @@
+../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index 653b30c..d9bb78b 100644
--- a/audio/effect/all-versions/default/Android.bp
+++ b/audio/effect/all-versions/default/Android.bp
@@ -52,7 +52,6 @@
"android.hardware.audio.common@2.0-util",
"android.hardware.audio.effect@2.0",
],
-
cflags: [
"-DMAJOR_VERSION=2",
"-DMINOR_VERSION=0",
@@ -68,7 +67,6 @@
"android.hardware.audio.common@4.0-util",
"android.hardware.audio.effect@4.0",
],
-
cflags: [
"-DMAJOR_VERSION=4",
"-DMINOR_VERSION=0",
@@ -84,10 +82,24 @@
"android.hardware.audio.common@5.0-util",
"android.hardware.audio.effect@5.0",
],
-
cflags: [
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio.effect@6.0-impl",
+ defaults: ["android.hardware.audio.effect-impl_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ "android.hardware.audio.effect@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index cccb5c8..edc9076 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -76,3 +76,16 @@
]
}
+cc_test {
+ name: "VtsHalAudioEffectV6_0TargetTest",
+ defaults: ["VtsHalAudioEffectTargetTest_default"],
+ static_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index c4c7f7c..3c712b5 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -28,8 +28,14 @@
#include <common/all-versions/VersionUtils.h>
+#if MAJOR_VERSION <= 5
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
+#elif MAJOR_VERSION >= 6
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
using ::android::sp;
using ::android::hardware::hidl_handle;
@@ -49,6 +55,11 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#endif
+#if MAJOR_VERSION <= 5
+// For HAL versions 2..5 Vts Environment and Test base classes are used.
+// The tests are non-parametrized.
+#define EFFECT_TEST TEST_F
+
// Test environment for Audio Effects Factory HIDL HAL.
class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -71,6 +82,18 @@
ASSERT_NE(effectsFactory, nullptr);
}
+#elif MAJOR_VERSION >= 6
+// For HAL version 6 and above, standard GTest Environment and Test base classes are used.
+// The tests are parametrized by the IEffectsFactory instance name.
+#define EFFECT_TEST TEST_P
+
+class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ effectsFactory = IEffectsFactory::getService(GetParam());
+ ASSERT_NE(effectsFactory, nullptr);
+ }
+#endif // The rest of the AudioEffectsFactoryHidlTest class definition is the same.
void TearDown() override { effectsFactory.clear(); }
protected:
@@ -81,7 +104,7 @@
sp<IEffectsFactory> effectsFactory;
};
-TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) {
description("Verify that EnumerateEffects returns at least one effect");
Result retval = Result::NOT_INITIALIZED;
size_t effectCount = 0;
@@ -95,7 +118,7 @@
EXPECT_GT(effectCount, 0u);
}
-TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) {
description("Verify that an effect can be created via CreateEffect");
bool gotEffect = false;
Uuid effectUuid;
@@ -123,7 +146,7 @@
EXPECT_NE(nullptr, effect.get());
}
-TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) {
description(
"Verify that effects factory can provide an effect descriptor via "
"GetDescriptor");
@@ -146,7 +169,7 @@
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
description("Verify that debugDump doesn't crash on invalid arguments");
#if MAJOR_VERSION == 2
Return<void> ret = effectsFactory->debugDump(hidl_handle());
@@ -168,10 +191,17 @@
std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
// The main test class for Audio Effect HIDL HAL.
+#if MAJOR_VERSION <= 5
class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
void SetUp() override {
effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+#elif MAJOR_VERSION >= 6
+class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ effectsFactory = IEffectsFactory::getService(GetParam());
+#endif
ASSERT_NE(nullptr, effectsFactory.get());
findAndCreateEffect(getEffectType());
@@ -250,14 +280,14 @@
static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
}
-TEST_F(AudioEffectHidlTest, Close) {
+EFFECT_TEST(AudioEffectHidlTest, Close) {
description("Verify that an effect can be closed");
Return<Result> ret = effect->close();
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, ret);
}
-TEST_F(AudioEffectHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) {
description("Verify that an effect can return its own descriptor via GetDescriptor");
Result retval = Result::NOT_INITIALIZED;
Uuid actualType;
@@ -272,7 +302,7 @@
EXPECT_EQ(getEffectType(), actualType);
}
-TEST_F(AudioEffectHidlTest, GetSetConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) {
description(
"Verify that it is possible to manipulate effect config via Get / "
"SetConfig");
@@ -291,26 +321,26 @@
EXPECT_EQ(Result::OK, ret2);
}
-TEST_F(AudioEffectHidlTest, GetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) {
description("Verify that GetConfigReverse does not crash");
Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
description("Verify that GetSupportedAuxChannelsConfigs does not crash");
Return<void> ret = effect->getSupportedAuxChannelsConfigs(
0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) {
description("Verify that GetAuxChannelsConfig does not crash");
Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) {
description("Verify that SetAuxChannelsConfig does not crash");
Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
EXPECT_TRUE(ret.isOk());
@@ -349,7 +379,7 @@
} // namespace hardware
} // namespace android
-TEST_F(AudioEffectHidlTest, Reset) {
+EFFECT_TEST(AudioEffectHidlTest, Reset) {
description("Verify that Reset preserves effect configuration");
Result retval = Result::NOT_INITIALIZED;
EffectConfig originalConfig;
@@ -374,7 +404,7 @@
EXPECT_EQ(originalConfig, configAfterReset);
}
-TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) {
description("Verify Disable -> Enable -> Disable sequence for an effect");
Return<Result> ret = effect->disable();
EXPECT_TRUE(ret.isOk());
@@ -387,14 +417,14 @@
EXPECT_EQ(Result::OK, ret);
}
-TEST_F(AudioEffectHidlTest, SetDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetDevice) {
description("Verify that SetDevice works for an output chain effect");
Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, ret);
}
-TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) {
description("Verify that SetAndGetVolume method works for an effect");
uint32_t channelCount;
getChannelCount(&channelCount);
@@ -410,7 +440,7 @@
EXPECT_EQ(Result::OK, retval);
}
-TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) {
description("Verify that effect accepts VolumeChangeNotification");
uint32_t channelCount;
getChannelCount(&channelCount);
@@ -424,32 +454,32 @@
EXPECT_EQ(Result::OK, ret);
}
-TEST_F(AudioEffectHidlTest, SetAudioMode) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) {
description("Verify that SetAudioMode works for an effect");
Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, ret);
}
-TEST_F(AudioEffectHidlTest, SetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) {
description("Verify that SetConfigReverse does not crash");
Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, SetInputDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) {
description("Verify that SetInputDevice does not crash");
Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, SetAudioSource) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) {
description("Verify that SetAudioSource does not crash");
Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, Offload) {
+EFFECT_TEST(AudioEffectHidlTest, Offload) {
description("Verify that calling Offload method does not crash");
EffectOffloadParameter offloadParam;
offloadParam.isOffload = false;
@@ -458,7 +488,7 @@
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) {
description("Verify that PrepareForProcessing method works for an effect");
Result retval = Result::NOT_INITIALIZED;
Return<void> ret = effect->prepareForProcessing(
@@ -467,7 +497,7 @@
EXPECT_EQ(Result::OK, retval);
}
-TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) {
description("Verify that SetProcessBuffers works for an effect");
sp<IAllocator> ashmem = IAllocator::getService("ashmem");
ASSERT_NE(nullptr, ashmem.get());
@@ -486,41 +516,41 @@
EXPECT_EQ(Result::OK, ret2);
}
-TEST_F(AudioEffectHidlTest, Command) {
+EFFECT_TEST(AudioEffectHidlTest, Command) {
description("Verify that Command does not crash");
Return<void> ret =
effect->command(0, hidl_vec<uint8_t>(), 0, [&](int32_t, const hidl_vec<uint8_t>&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, SetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, SetParameter) {
description("Verify that SetParameter does not crash");
Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, GetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, GetParameter) {
description("Verify that GetParameter does not crash");
Return<void> ret =
effect->getParameter(hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
description("Verify that GetSupportedConfigsForFeature does not crash");
Return<void> ret = effect->getSupportedConfigsForFeature(
0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) {
description("Verify that GetCurrentConfigForFeature does not crash");
Return<void> ret =
effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
EXPECT_TRUE(ret.isOk());
}
-TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) {
description("Verify that SetCurrentConfigForFeature does not crash");
Return<Result> ret = effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>());
EXPECT_TRUE(ret.isOk());
@@ -606,21 +636,21 @@
ASSERT_EQ(Result::OK, retval);
}
-TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) {
description("Verify that Equalizer effect reports at least one band");
uint16_t numBands = 0;
getNumBands(&numBands);
EXPECT_GT(numBands, 0);
}
-TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) {
description("Verify that Equalizer effect reports adequate band level range");
int16_t minLevel = 0x7fff, maxLevel = 0;
getLevelRange(&minLevel, &maxLevel);
EXPECT_GT(maxLevel, minLevel);
}
-TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
description("Verify that manipulating band levels works for Equalizer effect");
uint16_t numBands = 0;
getNumBands(&numBands);
@@ -649,7 +679,7 @@
}
}
-TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
description("Verify that Equalizer effect reports adequate band frequency range");
uint16_t numBands = 0;
getNumBands(&numBands);
@@ -664,7 +694,7 @@
}
}
-TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
description("Verify that Equalizer effect supports GetBandForFrequency correctly");
uint16_t numBands = 0;
getNumBands(&numBands);
@@ -693,14 +723,14 @@
}
}
-TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) {
description("Verify that Equalizer effect reports at least one preset");
size_t presetCount;
getPresetCount(&presetCount);
EXPECT_GT(presetCount, 0u);
}
-TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
description("Verify that manipulating the current preset for Equalizer effect");
size_t presetCount;
getPresetCount(&presetCount);
@@ -723,7 +753,7 @@
}
}
-TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
description(
"Verify that setting band levels and presets works via Get / "
"SetAllProperties for Equalizer effect");
@@ -787,7 +817,7 @@
sp<ILoudnessEnhancerEffect> enhancer;
};
-TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
description(
"Verify that manipulating the target gain works for Loudness Enhancer "
"effect");
@@ -808,6 +838,7 @@
EXPECT_EQ(gain, actualGain);
}
+#if MAJOR_VERSION <= 5
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
@@ -816,3 +847,17 @@
LOG(INFO) << "Test result = " << status;
return status;
}
+#elif MAJOR_VERSION >= 6
+INSTANTIATE_TEST_SUITE_P(
+ EffectsFactory, AudioEffectsFactoryHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+ Equalizer, EqualizerAudioEffectHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+ LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+#endif
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
index f2b3a8a..9ce9cda 100644
--- a/authsecret/1.0/vts/functional/Android.bp
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -19,5 +19,9 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
static_libs: ["android.hardware.authsecret@1.0"],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+ require_root: true,
}
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
index 255d4de..0bff9df 100644
--- a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -16,36 +16,22 @@
#include <android/hardware/authsecret/1.0/IAuthSecret.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::hardware::hidl_vec;
using ::android::hardware::authsecret::V1_0::IAuthSecret;
using ::android::sp;
-// Test environment for Boot HIDL HAL.
-class AuthSecretHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static AuthSecretHidlEnvironment* Instance() {
- static AuthSecretHidlEnvironment* instance = new AuthSecretHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IAuthSecret>(); }
-
- private:
- AuthSecretHidlEnvironment() {}
-};
-
/**
* There is no expected behaviour that can be tested so these tests check the
* HAL doesn't crash with different execution orders.
*/
-struct AuthSecretHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class AuthSecretHidlTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>(
- AuthSecretHidlEnvironment::Instance()->getServiceName<IAuthSecret>());
+ authsecret = IAuthSecret::getService(GetParam());
ASSERT_NE(authsecret, nullptr);
// All tests must enroll the correct secret first as this cannot be changed
@@ -59,18 +45,18 @@
};
/* Provision the primary user with a secret. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredential) {
// Secret provisioned by SetUp()
}
/* Provision the primary user with a secret and pass the secret again. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
// Secret provisioned by SetUp()
authsecret->primaryUserCredential(CORRECT_SECRET);
}
/* Provision the primary user with a secret and pass the secret again repeatedly. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
// Secret provisioned by SetUp()
constexpr int N = 5;
for (int i = 0; i < N; ++i) {
@@ -82,16 +68,12 @@
* should never happen and is an framework bug if it does. As the secret is
* wrong, the HAL implementation may not be able to function correctly but it
* should fail gracefully. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
// Secret provisioned by SetUp()
authsecret->primaryUserCredential(WRONG_SECRET);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(AuthSecretHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- AuthSecretHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, AuthSecretHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAuthSecret::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
index d2e85f1..c850c91 100644
--- a/automotive/evs/1.1/Android.bp
+++ b/automotive/evs/1.1/Android.bp
@@ -10,13 +10,15 @@
"types.hal",
"IEvsCamera.hal",
"IEvsCameraStream.hal",
+ "IEvsEnumerator.hal",
],
interfaces: [
"android.hardware.automotive.evs@1.0",
+ "android.hardware.camera.device@3.2",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
"android.hidl.base@1.0",
],
- gen_java: true,
+ gen_java: false,
}
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 21ca79e..975b6c6 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -26,6 +26,14 @@
*/
interface IEvsCamera extends @1.0::IEvsCamera {
/**
+ * Returns the description of this camera.
+ *
+ * @return info The description of this camera. This must be the same value as
+ * reported by EvsEnumerator::getCameraList_1_1().
+ */
+ getCameraInfo_1_1() generates (CameraDesc info);
+
+ /**
* Requests to pause EVS camera stream events.
*
* Like stopVideoStream(), events may continue to arrive for some time
@@ -100,7 +108,27 @@
unsetMaster() generates (EvsResult result);
/**
- * Requests to set a camera parameter.
+ * Retrieves a list of parameters this camera supports.
+ *
+ * @return params A list of CameraParam that this camera supports.
+ */
+ getParameterList() generates (vec<CameraParam> params);
+
+ /**
+ * Requests a valid value range of a camera parameter
+ *
+ * @param id The identifier of camera parameter, CameraParam enum.
+ *
+ * @return min The lower bound of valid parameter value range.
+ * @return max The upper bound of valid parameter value range.
+ * @return step The resolution of values in valid range.
+ */
+ getIntParameterRange(CameraParam id)
+ generates (int32_t min, int32_t max, int32_t step);
+
+ /**
+ * Requests to set a camera parameter. Only a request from the master
+ * client will be processed successfully.
*
* @param id The identifier of camera parameter, CameraParam enum.
* value A desired parameter value.
@@ -114,7 +142,7 @@
* from what the client gives if, for example, the
* driver does not support a target parameter.
*/
- setParameter(CameraParam id, int32_t value)
+ setIntParameter(CameraParam id, int32_t value)
generates (EvsResult result, int32_t effectiveValue);
/**
@@ -126,5 +154,5 @@
* not supported.
* value A value of requested camera parameter.
*/
- getParameter(CameraParam id) generates(EvsResult result, int32_t value);
+ getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 7c7f832..9e4ea19 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -17,15 +17,32 @@
package android.hardware.automotive.evs@1.1;
import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEvent;
/**
* Implemented on client side to receive asynchronous streaming event deliveries.
*/
interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+ /**
+ * Receives calls from the HAL each time a video frame is ready for inspection.
+ * Buffer handles received by this method must be returned via calls to
+ * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
+ * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+ * some time as the pipeline drains. Each frame must still be returned.
+ * When the last frame in the stream has been delivered, STREAM_STOPPED
+ * event must be delivered. No further frame deliveries may happen
+ * thereafter.
+ *
+ * @param buffer a buffer descriptor of a delivered image frame.
+ */
+ oneway deliverFrame_1_1(BufferDesc buffer);
+
/**
* Receives calls from the HAL each time an event happens.
*
* @param event EVS event with possible event information.
*/
- oneway notifyEvent(EvsEvent event);
+ oneway notify(EvsEvent event);
};
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
new file mode 100644
index 0000000..1695821
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import IEvsCamera;
+import @1.0::IEvsEnumerator;
+import @1.0::EvsResult;
+import android.hardware.camera.device@3.2::Stream;
+
+/**
+ * Provides the mechanism for EVS camera discovery
+ */
+interface IEvsEnumerator extends @1.0::IEvsEnumerator {
+ /**
+ * Returns a list of all EVS cameras available to the system
+ *
+ * @return cameras A list of cameras availale for EVS service.
+ */
+ getCameraList_1_1() generates (vec<CameraDesc> cameras);
+
+ /**
+ * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+ *
+ * Given a camera's unique cameraId from CameraDesc, returns the
+ * IEvsCamera interface associated with the specified camera. When
+ * done using the camera, the caller may release it by calling closeCamera().
+ *
+ * @param cameraId A unique identifier of the camera.
+ * @param streamCfg A stream configuration the client wants to use.
+ * @return evsCamera EvsCamera object associated with a given cameraId.
+ * Returned object would be null if a camera device does
+ * not support a given stream configuration or is already
+ * configured differently by another client.
+ */
+ openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index a463471..41cb426 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -7,25 +7,41 @@
"service.cpp",
"EvsCamera.cpp",
"EvsEnumerator.cpp",
- "EvsDisplay.cpp"
+ "EvsDisplay.cpp",
+ "ConfigManager.cpp",
+ "ConfigManagerUtil.cpp",
],
init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
shared_libs: [
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.1",
+ "android.hardware.camera.device@3.2",
"libbase",
"libbinder",
- "libcutils",
+ "liblog",
"libhardware",
"libhidlbase",
"liblog",
"libui",
"libutils",
+ "libcamera_metadata",
+ "libtinyxml2",
],
cflags: [
"-O0",
"-g",
],
+
+ required: [
+ "evs_default_configuration.xml",
+ ],
+}
+
+prebuilt_etc {
+ name: "evs_default_configuration.xml",
+
+ src: "resources/evs_default_configuration.xml",
+ sub_dir: "automotive/evs",
}
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..96a2f98
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,487 @@
+/*
+ * 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+ /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+ if (aCameraElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curElem = aCameraElem->FirstChildElement();
+ while (curElem != nullptr) {
+ if (!strcmp(curElem->Name(), "group")) {
+ /* camera group identifier */
+ const char *group_id = curElem->FindAttribute("group_id")->Value();
+
+ /* create CameraGroup */
+ unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+
+ /* add a camera device to its group */
+ addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
+
+ /* a list of camera stream configurations */
+ const XMLElement *childElem =
+ curElem->FirstChildElement("caps")->FirstChildElement("stream");
+ while (childElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = childElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = childElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = childElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = childElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCameraGroup->streamConfigurations[id] = cfg;
+ }
+
+ childElem = childElem->NextSiblingElement("stream");
+ }
+
+ /* camera group synchronization */
+ const char *sync = curElem->FindAttribute("synchronized")->Value();
+ aCameraGroup->synchronized =
+ static_cast<bool>(strcmp(sync, "false"));
+
+ /* add a group to hash map */
+ mCameraGroups[group_id] = std::move(aCameraGroup);
+ } else if (!strcmp(curElem->Name(), "device")) {
+ /* camera unique identifier */
+ const char *id = curElem->FindAttribute("id")->Value();
+
+ /* camera mount location */
+ const char *pos = curElem->FindAttribute("position")->Value();
+
+ /* store read camera module information */
+ mCameraInfo[id] = readCameraDeviceInfo(curElem);
+
+ /* assign a camera device to a position group */
+ mCameraPosition[pos].emplace(id);
+ } else {
+ /* ignore other device types */
+ ALOGD("Unknown element %s is ignored", curElem->Name());
+ }
+
+ curElem = curElem->NextSiblingElement();
+ }
+}
+
+
+unique_ptr<ConfigManager::CameraInfo>
+ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
+ if (aDeviceElem == nullptr) {
+ return nullptr;
+ }
+
+ /* create a CameraInfo to be filled */
+ unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
+
+ /* size information to allocate camera_metadata_t */
+ size_t totalEntries = 0;
+ size_t totalDataSize = 0;
+
+ /* read device capabilities */
+ totalEntries +=
+ readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+ aCamera,
+ totalDataSize);
+
+
+ /* read camera metadata */
+ totalEntries +=
+ readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+ aCamera,
+ totalDataSize);
+
+ /* construct camera_metadata_t */
+ if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+ ALOGW("Either failed to allocate memory or "
+ "allocated memory was not large enough");
+ }
+
+ return aCamera;
+}
+
+
+size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr) {
+ return 0;
+ }
+
+ string token;
+ const XMLElement *curElem = nullptr;
+
+ /* a list of supported camera parameters/controls */
+ curElem = aCapElem->FirstChildElement("supported_controls");
+ if (curElem != nullptr) {
+ const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+ while (ctrlElem != nullptr) {
+ const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+ const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+ const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+ int32_t stepVal = 1;
+ const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+ if (stepAttr != nullptr) {
+ stepVal = stoi(stepAttr->Value());
+ }
+
+ CameraParam aParam;
+ if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+ aParam)) {
+ aCamera->controls.emplace(
+ aParam,
+ make_tuple(minVal, maxVal, stepVal)
+ );
+ }
+
+ ctrlElem = ctrlElem->NextSiblingElement("control");
+ }
+ }
+
+ /* a list of camera stream configurations */
+ curElem = aCapElem->FirstChildElement("stream");
+ while (curElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = curElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = curElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCamera->streamConfigurations[id] = cfg;
+ }
+
+ curElem = curElem->NextSiblingElement("stream");
+ }
+
+ dataSize = calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ ),
+ aCamera->streamConfigurations.size() * kStreamCfgSz
+ );
+
+ /* a single camera metadata entry contains multiple stream configurations */
+ return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr) {
+ return 0;
+ }
+
+ const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+ size_t numEntries = 0;
+ camera_metadata_tag_t tag;
+ while (curElem != nullptr) {
+ if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+ tag)) {
+ switch(tag) {
+ case ANDROID_LENS_DISTORTION:
+ case ANDROID_LENS_POSE_ROTATION:
+ case ANDROID_LENS_POSE_TRANSLATION:
+ case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+ /* float[] */
+ size_t count = 0;
+ void *data = ConfigManagerUtil::convertFloatArray(
+ curElem->FindAttribute("size")->Value(),
+ curElem->FindAttribute("value")->Value(),
+ count
+ );
+
+ aCamera->cameraMetadata[tag] =
+ make_pair(make_unique<void *>(data), count);
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), count
+ );
+
+ break;
+ }
+
+ default:
+ ALOGW("Parameter %s is not supported",
+ curElem->FindAttribute("name")->Value());
+ break;
+ }
+ }
+
+ curElem = curElem->NextSiblingElement("parameter");
+ }
+
+ return numEntries;
+}
+
+
+bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize) {
+ if (!aCamera->allocate(totalEntries, totalDataSize)) {
+ ALOGE("Failed to allocate memory for camera metadata");
+ return false;
+ }
+
+ const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+ unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+ int32_t *ptr = data.get();
+ for (auto &cfg : aCamera->streamConfigurations) {
+ for (auto i = 0; i < kStreamCfgSz; ++i) {
+ *ptr++ = cfg.second[i];
+ }
+ }
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ data.get(),
+ numStreamConfigs * kStreamCfgSz);
+
+ if (err) {
+ ALOGE("Failed to add stream configurations to metadata, ignored");
+ return false;
+ }
+
+ bool success = true;
+ for (auto &[tag, entry] : aCamera->cameraMetadata) {
+ /* try to add new camera metadata entry */
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ tag,
+ entry.first.get(),
+ entry.second);
+ if (err) {
+ ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+ /* may exceed preallocated capacity */
+ ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+ ALOGE("\tCurrent metadata entry requires %ld bytes",
+ (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+ success = false;
+ }
+ }
+
+ ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+
+ return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+ if (aSysElem == nullptr) {
+ return;
+ }
+
+ /*
+ * Please note that this function assumes that a given system XML element
+ * and its child elements follow DTD. If it does not, it will cause a
+ * segmentation fault due to the failure of finding expected attributes.
+ */
+
+ /* read number of cameras available in the system */
+ const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+ if (xmlElem != nullptr) {
+ mSystemInfo.numCameras =
+ stoi(xmlElem->FindAttribute("value")->Value());
+ }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+ if (aDisplayElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+ while (curDev != nullptr) {
+ const char *id = curDev->FindAttribute("id")->Value();
+ //const char *pos = curDev->FirstAttribute("position")->Value();
+
+ unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+ if (dpy == nullptr) {
+ ALOGE("Failed to allocate memory for DisplayInfo");
+ return;
+ }
+
+ const XMLElement *cap = curDev->FirstChildElement("caps");
+ if (cap != nullptr) {
+ const XMLElement *curStream = cap->FirstChildElement("stream");
+ while (curStream != nullptr) {
+ /* read 4 attributes */
+ const XMLAttribute *idAttr = curStream->FindAttribute("id");
+ const XMLAttribute *widthAttr = curStream->FindAttribute("width");
+ const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curStream->FindAttribute("format");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+ 0 // unused
+ };
+ dpy->streamConfigurations[id] = cfg;
+ }
+
+ curStream = curStream->NextSiblingElement("stream");
+ }
+ }
+
+ mDisplayInfo[id] = std::move(dpy);
+ curDev = curDev->NextSiblingElement("device");
+ }
+
+ return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+ XMLDocument xmlDoc;
+
+ const int64_t parsingStart = android::elapsedRealtimeNano();
+
+ /* load and parse a configuration file */
+ xmlDoc.LoadFile(mConfigFilePath);
+ if (xmlDoc.ErrorID() != XML_SUCCESS) {
+ ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+ return false;
+ }
+
+ /* retrieve the root element */
+ const XMLElement *rootElem = xmlDoc.RootElement();
+ if (strcmp(rootElem->Name(), "configuration")) {
+ ALOGE("A configuration file is not in the required format. "
+ "See /etc/automotive/evs/evs_configuration.dtd");
+ return false;
+ }
+
+ /*
+ * parse camera information; this needs to be done before reading system
+ * information
+ */
+ readCameraInfo(rootElem->FirstChildElement("camera"));
+
+ /* parse system information */
+ readSystemInfo(rootElem->FirstChildElement("system"));
+
+ /* parse display information */
+ readDisplayInfo(rootElem->FirstChildElement("display"));
+
+ const int64_t parsingEnd = android::elapsedRealtimeNano();
+ ALOGI("Parsing configuration file takes %lf (ms)",
+ (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+ return true;
+}
+
+
+void ConfigManager::addCameraDevices(const char *devices,
+ unique_ptr<CameraGroup> &aGroup) {
+ stringstream device_list(devices);
+ string token;
+ while (getline(device_list, token, ',')) {
+ aGroup->devices.emplace(token);
+ }
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+ unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+ /*
+ * Read a configuration from XML file
+ *
+ * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+ * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+ * to the filesystem and construct CameraInfo instead; this was
+ * evaluated as 10x faster.
+ */
+ if (!cfgMgr->readConfigDataFromXML()) {
+ return nullptr;
+ } else {
+ return cfgMgr;
+ }
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
new file mode 100644
index 0000000..0275f90
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <log/log.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+ static std::unique_ptr<ConfigManager> Create(const char *path = "");
+ ConfigManager(const ConfigManager&) = delete;
+ ConfigManager& operator=(const ConfigManager&) = delete;
+
+ virtual ~ConfigManager();
+
+ /* Camera device's capabilities and metadata */
+ class CameraInfo {
+ public:
+ CameraInfo() :
+ characteristics(nullptr) {
+ /* Nothing to do */
+ }
+
+ virtual ~CameraInfo() {
+ free_camera_metadata(characteristics);
+ }
+
+ /* Allocate memory for camera_metadata_t */
+ bool allocate(size_t entry_cap, size_t data_cap) {
+ if (characteristics != nullptr) {
+ ALOGE("Camera metadata is already allocated");
+ return false;
+ }
+
+ characteristics = allocate_camera_metadata(entry_cap, data_cap);
+ return characteristics != nullptr;
+ }
+
+ /*
+ * List of supported controls that the master client can program.
+ * Paraemters are stored with its valid range
+ */
+ unordered_map<CameraParam,
+ tuple<int32_t, int32_t, int32_t>> controls;
+
+ /* List of supported frame rates */
+ unordered_set<int32_t> frameRates;
+
+ /*
+ * List of supported output stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+ /*
+ * Internal storage for camera metadata. Each entry holds a pointer to
+ * data and number of elements
+ */
+ unordered_map<camera_metadata_tag_t,
+ pair<unique_ptr<void *>, size_t>> cameraMetadata;
+
+ /* Camera module characteristics */
+ camera_metadata_t *characteristics;
+ };
+
+ class CameraGroup {
+ public:
+ CameraGroup() {}
+
+ /* ID of member camera devices */
+ unordered_set<string> devices;
+
+ /* The capture operation of member camera devices are synchronized */
+ bool synchronized = false;
+
+ /*
+ * List of stream configurations that are supposed by all camera devices
+ * in this group.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+ };
+
+ class SystemInfo {
+ public:
+ /* number of available cameras */
+ int32_t numCameras = 0;
+ };
+
+ class DisplayInfo {
+ public:
+ /*
+ * List of supported input stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+ };
+
+ /*
+ * Return system information
+ *
+ * @return SystemInfo
+ * Constant reference of SystemInfo.
+ */
+ const SystemInfo &getSystemInfo() {
+ return mSystemInfo;
+ }
+
+ /*
+ * Return a list of cameras
+ *
+ * This function assumes that it is not being called frequently.
+ *
+ * @return vector<string>
+ * A vector that contains unique camera device identifiers.
+ */
+ vector<string> getCameraList() {
+ vector<string> aList;
+ for (auto &v : mCameraInfo) {
+ aList.emplace_back(v.first);
+ }
+
+ return aList;
+ }
+
+
+ /*
+ * Return a list of cameras
+ *
+ * @return CameraGroup
+ * A pointer to a camera group identified by a given id.
+ */
+ unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
+ return mCameraGroups[gid];
+ }
+
+
+ /*
+ * Return a camera metadata
+ *
+ * @param cameraId
+ * Unique camera node identifier in string
+ *
+ * @return unique_ptr<CameraInfo>
+ * A pointer to CameraInfo that is associated with a given camera
+ * ID. This returns a null pointer if this does not recognize a
+ * given camera identifier.
+ */
+ unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+ return mCameraInfo[cameraId];
+ }
+
+private:
+ /* Constructors */
+ ConfigManager(const char *xmlPath) :
+ mConfigFilePath(xmlPath) {
+ }
+
+ /* System configuration */
+ SystemInfo mSystemInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+ /* Camera groups are stored in <groud id, CameraGroup> hash map */
+ unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+
+ /*
+ * Camera positions are stored in <position, camera id set> hash map.
+ * The position must be one of front, rear, left, and right.
+ */
+ unordered_map<string, unordered_set<string>> mCameraPosition;
+
+ /* A path to XML configuration file */
+ const char *mConfigFilePath;
+
+ /*
+ * Parse a given EVS configuration file and store the information
+ * internally.
+ *
+ * @return bool
+ * True if it completes parsing a file successfully.
+ */
+ bool readConfigDataFromXML() noexcept;
+
+ /*
+ * read the information of the vehicle
+ *
+ * @param aSysElem
+ * A pointer to "system" XML element.
+ */
+ void readSystemInfo(const XMLElement * const aSysElem);
+
+ /*
+ * read the information of camera devices
+ *
+ * @param aCameraElem
+ * A pointer to "camera" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readCameraInfo(const XMLElement * const aCameraElem);
+
+ /*
+ * read display device information
+ *
+ * @param aDisplayElem
+ * A pointer to "display" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+ /*
+ * read camera device information
+ *
+ * @param aDeviceElem
+ * A pointer to "device" XML element that contains camera module
+ * capability info and its characteristics.
+ *
+ * @return unique_ptr<CameraInfo>
+ * A pointer to CameraInfo class that contains camera module
+ * capability and characteristics. Please note that this transfers
+ * the ownership of created CameraInfo to the caller.
+ */
+ unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+
+ /*
+ * read camera metadata
+ *
+ * @param aCapElem
+ * A pointer to "cap" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method. This is calculated in this method and returned to the
+ * caller for camera_metadata allocation.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraCapabilities(const XMLElement * const aCapElem,
+ unique_ptr<CameraInfo> &aCamera,
+ size_t &dataSize);
+
+ /*
+ * read camera metadata
+ *
+ * @param aParamElem
+ * A pointer to "characteristics" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraMetadata(const XMLElement * const aParamElem,
+ unique_ptr<CameraInfo> &aCamera,
+ size_t &dataSize);
+
+ /*
+ * construct camera_metadata_t from camera capabilities and metadata
+ *
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param totalEntries
+ * Number of camera metadata entries to be added.
+ * @param totalDataSize
+ * Sum of sizes of camera metadata entries to be added.
+ *
+ * @return bool
+ * False if either it fails to allocate memory for camera metadata
+ * or its size is not large enough to add all found camera metadata
+ * entries.
+ */
+ bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize);
+
+ /*
+ * parse a comma-separated list of camera devices and add them to
+ * CameraGroup.
+ *
+ * @param devices
+ * A comma-separated list of camera device identifiers.
+ * @param aGroup
+ * Camera group which cameras will be added to.
+ */
+ void addCameraDevices(const char *devices,
+ unique_ptr<CameraGroup> &aGroup);
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..8206daa
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+
+#include <log/log.h>
+#include <system/graphics-base-v1.0.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+ CameraParam &camParam) {
+ string trimmed = ConfigManagerUtil::trimString(id);
+ bool success = true;
+
+ if (!trimmed.compare("BRIGHTNESS")) {
+ camParam = CameraParam::BRIGHTNESS;
+ } else if (!trimmed.compare("CONTRAST")) {
+ camParam = CameraParam::CONTRAST;
+ } else if (!trimmed.compare("AUTOGAIN")) {
+ camParam = CameraParam::AUTOGAIN;
+ } else if (!trimmed.compare("GAIN")) {
+ camParam = CameraParam::GAIN;
+ } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+ camParam = CameraParam::AUTO_WHITE_BALANCE;
+ } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+ camParam = CameraParam::WHITE_BALANCE_TEMPERATURE;
+ } else if (!trimmed.compare("SHARPNESS")) {
+ camParam = CameraParam::SHARPNESS;
+ } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+ camParam = CameraParam::AUTO_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+ camParam = CameraParam::ABSOLUTE_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+ camParam = CameraParam::ABSOLUTE_FOCUS;
+ } else if (!trimmed.compare("AUTO_FOCUS")) {
+ camParam = CameraParam::AUTO_FOCUS;
+ } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+ camParam = CameraParam::ABSOLUTE_ZOOM;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+ int32_t &pixFormat) {
+ string trimmed = ConfigManagerUtil::trimString(format);
+ bool success = true;
+
+ if (!trimmed.compare("RGBA_8888")) {
+ pixFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ } else if (!trimmed.compare("YCRCB_420_SP")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP;
+ } else if (!trimmed.compare("YCBCR_422_I")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag) {
+ if (!strcmp(name, "LENS_DISTORTION")) {
+ aTag = ANDROID_LENS_DISTORTION;
+ } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+ aTag = ANDROID_LENS_INTRINSIC_CALIBRATION;
+ } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+ aTag = ANDROID_LENS_POSE_ROTATION;
+ } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
+ aTag = ANDROID_LENS_POSE_TRANSLATION;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+ size_t &count, const char delimiter) {
+ string size_string(sz);
+ string value_string(vals);
+
+ count = stoi(size_string);
+ float *result = new float[count];
+ stringstream values(value_string);
+
+ int32_t idx = 0;
+ string token;
+ while (getline(values, token, delimiter)) {
+ result[idx++] = stof(token);
+ }
+
+ return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+ const auto s = src.find_first_not_of(ws);
+ if (s == string::npos) {
+ return "";
+ }
+
+ const auto e = src.find_last_not_of(ws);
+ const auto r = e - s + 1;
+
+ return src.substr(s, r);
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
new file mode 100644
index 0000000..8c89ae7
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+ /**
+ * Convert a given string into V4L2_CID_*
+ */
+ static bool convertToEvsCameraParam(const string &id,
+ CameraParam &camParam);
+ /**
+ * Convert a given string into android.hardware.graphics.common.PixelFormat
+ */
+ static bool convertToPixelFormat(const string &format,
+ int32_t &pixelFormat);
+ /**
+ * Convert a given string into corresponding camera metadata data tag defined in
+ * system/media/camera/include/system/camera_metadta_tags.h
+ */
+ static bool convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag);
+ /**
+ * Convert a given string into a floating value array
+ */
+ static float *convertFloatArray(const char *sz,
+ const char *vals,
+ size_t &count,
+ const char delimiter = ',');
+ /**
+ * Trim a string
+ */
+ static string trimString(const string &src,
+ const string &ws = " \n\r\t\f\v");
+};
+
+#endif // CONFIG_MANAGER_UTIL_H
+
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 2d55566..5ba753d 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -40,28 +40,21 @@
const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
-EvsCamera::EvsCamera(const char *id) :
+EvsCamera::EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo) :
mFramesAllowed(0),
mFramesInUse(0),
- mStreamState(STOPPED) {
+ mStreamState(STOPPED),
+ mCameraInfo(camInfo) {
ALOGD("EvsCamera instantiated");
- mDescription.cameraId = id;
+ /* set a camera id */
+ mDescription.v1.cameraId = id;
- // Set up dummy data for testing
- if (mDescription.cameraId == kCameraName_Backup) {
- mWidth = 640; // full NTSC/VGA
- mHeight = 480; // full NTSC/VGA
- mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
- } else {
- mWidth = 320; // 1/2 NTSC/VGA
- mHeight = 240; // 1/2 NTSC/VGA
- }
-
- mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
- mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
- GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+ /* set camera metadata */
+ mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+ get_camera_metadata_size(camInfo->characteristics));
}
@@ -109,7 +102,7 @@
ALOGD("getCameraInfo");
// Send back our self description
- _hidl_cb(mDescription);
+ _hidl_cb(mDescription.v1);
return Void();
}
@@ -194,7 +187,7 @@
// Block outside the mutex until the "stop" flag has been acknowledged
// We won't send any more frames, but the client might still get some already in flight
- ALOGD("Waiting for stream thread to end..");
+ ALOGD("Waiting for stream thread to end...");
lock.unlock();
mCaptureThread.join();
lock.lock();
@@ -238,6 +231,15 @@
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+ ALOGD("getCameraInfo_1_1");
+
+ // Send back our self description
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
std::lock_guard <std::mutex> lock(mAccessLock);
returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
@@ -278,8 +280,29 @@
}
-Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
- setParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+ hidl_vec<CameraParam> hidlCtrls;
+ hidlCtrls.resize(mCameraInfo->controls.size());
+ unsigned idx = 0;
+ for (auto& [cid, cfg] : mCameraInfo->controls) {
+ hidlCtrls[idx++] = cid;
+ }
+
+ _hidl_cb(hidlCtrls);
+ return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) {
+ auto range = mCameraInfo->controls[id];
+ _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+ return Void();
+}
+
+
+Return<void> EvsCamera::setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) {
// Default implementation does not support this.
(void)id;
(void)value;
@@ -288,7 +311,8 @@
}
-Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) {
// Default implementation does not support this.
(void)id;
_hidl_cb(EvsResult::INVALID_ARG, 0);
@@ -471,9 +495,7 @@
fillTestFrame(newBuffer);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- EvsEvent event;
- event.buffer(newBuffer);
- auto result = mStream->notifyEvent(event);
+ auto result = mStream->deliverFrame_1_1(newBuffer);
if (result.isOk()) {
ALOGD("Delivered %p as id %d",
newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -506,10 +528,8 @@
// If we've been asked to stop, send an event to signal the actual end of stream
EvsEvent event;
- InfoEventDesc desc = {};
- desc.aType = InfoEventType::STREAM_STOPPED;
- event.info(desc);
- auto result = mStream->notifyEvent(event);
+ event.aType = EvsEventType::STREAM_STOPPED;
+ auto result = mStream->notify(event);
if (!result.isOk()) {
ALOGE("Error delivering end of stream marker");
}
@@ -616,6 +636,38 @@
}
+sp<EvsCamera> EvsCamera::Create(const char *deviceName) {
+ unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+ return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg) {
+ sp<EvsCamera> evsCamera = new EvsCamera(deviceName, camInfo);
+ if (evsCamera == nullptr) {
+ return nullptr;
+ }
+
+ /* default implementation does not use a given configuration */
+ (void)streamCfg;
+
+ /* Use the first resolution from the list for the testing */
+ auto it = camInfo->streamConfigurations.begin();
+ evsCamera->mWidth = it->second[1];
+ evsCamera->mHeight = it->second[2];
+ evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+
+ evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+
+ return evsCamera;
+}
+
+
} // namespace implementation
} // namespace V1_0
} // namespace evs
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 47a3164..c15b4b1 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -25,6 +25,8 @@
#include <thread>
+#include "ConfigManager.h"
+
using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
@@ -59,18 +61,28 @@
Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+ Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
Return<EvsResult> pauseVideoStream() override;
Return<EvsResult> resumeVideoStream() override;
Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
Return<EvsResult> setMaster() override;
Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
Return<EvsResult> unsetMaster() override;
- Return<void> setParameter(CameraParam id, int32_t value,
- setParameter_cb _hidl_cb) override;
- Return<void> getParameter(CameraParam id, getParameter_cb _hidl_cb) override;
+ Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
+ Return<void> getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) override;
+ Return<void> setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) override;
+ Return<void> getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) override;
- // Implementation details
- EvsCamera(const char *id);
+ static sp<EvsCamera> Create(const char *deviceName);
+ static sp<EvsCamera> Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg = nullptr);
+ EvsCamera(const EvsCamera&) = delete;
+ EvsCamera& operator=(const EvsCamera&) = delete;
+
virtual ~EvsCamera() override;
void forceShutdown(); // This gets called if another caller "steals" ownership of the camera
@@ -79,7 +91,10 @@
static const char kCameraName_Backup[];
private:
+ EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo);
// These three functions are expected to be called while mAccessLock is held
+ //
bool setAvailableFrames_Locked(unsigned bufferCount);
unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
@@ -124,6 +139,9 @@
// Synchronization necessary to deconflict mCaptureThread from the main service thread
std::mutex mAccessLock;
+
+ // Static camera module information
+ unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
};
} // namespace implementation
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index b324907..a010729 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -33,6 +33,7 @@
// constructs a new instance for each client.
std::list<EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
wp<EvsDisplay> EvsEnumerator::sActiveDisplay;
+unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
EvsEnumerator::EvsEnumerator() {
@@ -40,9 +41,11 @@
// Add sample camera data to our list of cameras
// In a real driver, this would be expected to can the available hardware
- sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
- sCameraList.emplace_back("LaneView");
- sCameraList.emplace_back("right turn");
+ sConfigManager =
+ ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+ for (auto v : sConfigManager->getCameraList()) {
+ sCameraList.emplace_back(v.c_str());
+ }
}
@@ -57,7 +60,7 @@
std::vector<CameraDesc_1_0> descriptions;
descriptions.reserve(numCameras);
for (const auto& cam : sCameraList) {
- descriptions.push_back( cam.desc );
+ descriptions.push_back( cam.desc.v1 );
}
// Encapsulate our camera descriptions in the HIDL vec type
@@ -78,7 +81,7 @@
// Find the named camera
CameraRecord *pRecord = nullptr;
for (auto &&cam : sCameraList) {
- if (cam.desc.cameraId == cameraId) {
+ if (cam.desc.v1.cameraId == cameraId) {
// Found a match!
pRecord = &cam;
break;
@@ -99,7 +102,12 @@
}
// Construct a camera instance for the caller
- pActiveCamera = new EvsCamera(cameraId.c_str());
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId));
+ }
pRecord->activeInstance = pActiveCamera;
if (pActiveCamera == nullptr) {
ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
@@ -120,15 +128,15 @@
// Get the camera id so we can find it in our list
std::string cameraId;
- pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) {
- cameraId = desc.cameraId;
+ pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) {
+ cameraId = desc.v1.cameraId;
}
);
// Find the named camera
CameraRecord *pRecord = nullptr;
for (auto &&cam : sCameraList) {
- if (cam.desc.cameraId == cameraId) {
+ if (cam.desc.v1.cameraId == cameraId) {
// Found a match!
pRecord = &cam;
break;
@@ -209,6 +217,89 @@
}
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = sCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc_1_1> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : sCameraList) {
+ descriptions.push_back( cam.desc );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc_1_1> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+Return<sp<IEvsCamera_1_1>>
+EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is this a recognized camera id?
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ }
+
+ // Has this camera already been instantiated by another caller?
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+ if (pActiveCamera != nullptr) {
+ ALOGW("Killing previous camera because of new caller");
+ closeCamera(pActiveCamera);
+ }
+
+ // Construct a camera instance for the caller
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId),
+ &streamCfg);
+ }
+
+ pRecord->activeInstance = pActiveCamera;
+ if (pActiveCamera == nullptr) {
+ ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+ }
+
+ return pActiveCamera;
+}
+
+
+EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ return pRecord;
+}
+
} // namespace implementation
} // namespace V1_1
} // namespace evs
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 11c2170..475ec76 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -17,18 +17,20 @@
#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <list>
+#include "ConfigManager.h"
+
using ::android::hardware::automotive::evs::V1_0::EvsResult;
using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
namespace android {
@@ -53,6 +55,11 @@
Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
Return<DisplayState> getDisplayState() override;
+ // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+ Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+ Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) override;
+
// Implementation details
EvsEnumerator();
@@ -61,14 +68,20 @@
// That is to say, this is effectively a singleton despite the fact that HIDL
// constructs a new instance for each client.
struct CameraRecord {
- CameraDesc_1_0 desc;
+ CameraDesc_1_1 desc;
wp<EvsCamera> activeInstance;
- CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+ CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
};
- static std::list<CameraRecord> sCameraList;
- static wp<EvsDisplay> sActiveDisplay; // Weak pointer. Object destructs if client dies.
+ static CameraRecord* findCameraById(const std::string& cameraId);
+
+ static std::list<CameraRecord> sCameraList;
+
+ // Weak pointer. Object destructs if client dies.
+ static wp<EvsDisplay> sActiveDisplay;
+
+ static unique_ptr<ConfigManager> sConfigManager;
};
} // namespace implementation
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
new file mode 100644
index 0000000..692102e
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,68 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- 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.
+-->
+
+<!-- Exterior View System Example Configuration
+
+ Android Automotive axes are used to define coordinates.
+ See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+ Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+ <!-- system configuration -->
+ <system>
+ <!-- number of cameras available to EVS -->
+ <num_cameras value='1'/>
+ </system>
+
+ <!-- camera device information -->
+ <camera>
+ <!-- camera device starts -->
+ <device id='/dev/video1' position='rear'>
+ <caps>
+ <!-- list of supported controls -->
+ <supported_controls>
+ <control name='BRIGHTNESS' min='0' max='255'/>
+ <control name='CONTRAST' min='0' max='255'/>
+ </supported_controls>
+
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <!-- Camera intrinsic calibration matrix. See
+ https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+ -->
+ <parameter
+ name='LENS_INTRINSIC_CALIBRATION'
+ type='float'
+ size='5'
+ value='0.0,0.0,0.0,0.0,0.0'
+ />
+ </characteristics>
+ </device>
+ </camera>
+ <display>
+ <device id='display0' position='driver'>
+ <caps>
+ <!-- list of supported inpu stream configurations -->
+ <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+ </caps>
+ </device>
+ </display>
+</configuration>
+
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
index 128a14a..5135864 100644
--- a/automotive/evs/1.1/default/service.cpp
+++ b/automotive/evs/1.1/default/service.cpp
@@ -33,7 +33,7 @@
using android::hardware::joinRpcThreadpool;
// Generated HIDL files
-using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
using android::hardware::automotive::evs::V1_0::IEvsDisplay;
// The namespace in which all our implementation code lives
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index 2c6b2ed..dcb2abb 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -21,6 +21,22 @@
import @1.0::DisplayState;
import @1.0::EvsResult;
import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.camera.device@3.2::CameraMetadata;
+
+/**
+ * Structure describing the basic properties of an EVS camera, extended from its
+ * v1.0 declaration.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+struct CameraDesc {
+ @1.0::CameraDesc v1;
+ /**
+ * Store camera metadata such as lens characteristics.
+ */
+ CameraMetadata metadata;
+};
/**
* Structure representing an image buffer through our APIs
@@ -50,7 +66,7 @@
/**
* Types of informative streaming events
*/
-enum InfoEventType : uint32_t {
+enum EvsEventType : uint32_t {
/**
* Video stream is started
*/
@@ -81,11 +97,11 @@
/**
* Structure that describes informative events occurred during EVS is streaming
*/
-struct InfoEventDesc {
+struct EvsEvent {
/**
* Type of an informative event
*/
- InfoEventType aType;
+ EvsEventType aType;
/**
* Possible additional information
*/
@@ -93,20 +109,6 @@
};
/**
- * EVS event definition
- */
-safe_union EvsEvent {
- /**
- * A buffer descriptor of an image frame
- */
- BufferDesc buffer;
- /**
- * General streaming events
- */
- InfoEventDesc info;
-};
-
-/**
* EVS Camera Parameter
*/
enum CameraParam : uint32_t {
@@ -127,14 +129,6 @@
*/
GAIN,
/**
- * Mirror the image horizontally
- */
- HFLIP,
- /**
- * Mirror the image vertically
- */
- VFLIP,
- /**
* Automatic Whitebalance
*/
AUTO_WHITE_BALANCE,
@@ -156,11 +150,6 @@
*/
ABSOLUTE_EXPOSURE,
/**
- * When AEC is running in either auto or aperture priority, this parameter
- * sets whether a frame rate varies.
- */
- AUTO_EXPOSURE_PRIORITY,
- /**
* Set the focal point of the camera to the specified position. This
* parameter may not be effective when auto focus is enabled.
*/
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index 55c50a4..4753933 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -23,6 +23,7 @@
defaults: ["VtsHalTargetTestDefaults"],
shared_libs: [
"libui",
+ "libcamera_metadata",
],
static_libs: [
"android.hardware.automotive.evs@1.0",
@@ -31,6 +32,7 @@
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
+ "android.hardware.camera.device@3.2",
],
test_suites: ["general-tests"],
cflags: [
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 1627689..6d53652 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -138,93 +138,93 @@
}
-Return<void> FrameHandler::notifyEvent(const EvsEvent& event) {
- // Local flag we use to keep track of when the stream is stopping
- auto type = event.getDiscriminator();
- if (type == EvsEvent::hidl_discriminator::info) {
- mLock.lock();
- mLatestEventDesc = event.info();
- if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) {
- // Signal that the last frame has been received and the stream is stopped
- mRunning = false;
- } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) {
- ALOGD("Camera parameter 0x%X is changed to 0x%X",
- mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+ ALOGD("Received a frame from the camera (%p)",
+ bufDesc.buffer.nativeHandle.getNativeHandle());
+
+ // Store a dimension of a received frame.
+ mFrameWidth = pDesc->width;
+ mFrameHeight = pDesc->height;
+
+ // If we were given an opened display at construction time, then send the received
+ // image back down the camera.
+ if (mDisplay.get()) {
+ // Get the output buffer we'll use to display the imagery
+ BufferDesc_1_0 tgtBuffer = {};
+ mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+ tgtBuffer = buff;
+ }
+ );
+
+ if (tgtBuffer.memHandle == nullptr) {
+ printf("Didn't get target buffer - frame lost\n");
+ ALOGE("Didn't get requested output buffer -- skipping this frame.");
} else {
- ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
- }
- mLock.unlock();
- mEventSignal.notify_all();
- } else {
- auto bufDesc = event.buffer();
- const AHardwareBuffer_Desc* pDesc =
- reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
- ALOGD("Received a frame from the camera (%p)",
- bufDesc.buffer.nativeHandle.getNativeHandle());
+ // Copy the contents of the of buffer.memHandle into tgtBuffer
+ copyBufferContents(tgtBuffer, bufDesc);
- // Store a dimension of a received frame.
- mFrameWidth = pDesc->width;
- mFrameHeight = pDesc->height;
-
- // If we were given an opened display at construction time, then send the received
- // image back down the camera.
- if (mDisplay.get()) {
- // Get the output buffer we'll use to display the imagery
- BufferDesc_1_0 tgtBuffer = {};
- mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
- tgtBuffer = buff;
- }
- );
-
- if (tgtBuffer.memHandle == nullptr) {
- printf("Didn't get target buffer - frame lost\n");
- ALOGE("Didn't get requested output buffer -- skipping this frame.");
+ // Send the target buffer back for display
+ Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+ if (!result.isOk()) {
+ printf("HIDL error on display buffer (%s)- frame lost\n",
+ result.description().c_str());
+ ALOGE("Error making the remote function call. HIDL said %s",
+ result.description().c_str());
+ } else if (result != EvsResult::OK) {
+ printf("Display reported error - frame lost\n");
+ ALOGE("We encountered error %d when returning a buffer to the display!",
+ (EvsResult) result);
} else {
- // Copy the contents of the of buffer.memHandle into tgtBuffer
- copyBufferContents(tgtBuffer, bufDesc);
-
- // Send the target buffer back for display
- Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
- if (!result.isOk()) {
- printf("HIDL error on display buffer (%s)- frame lost\n",
- result.description().c_str());
- ALOGE("Error making the remote function call. HIDL said %s",
- result.description().c_str());
- } else if (result != EvsResult::OK) {
- printf("Display reported error - frame lost\n");
- ALOGE("We encountered error %d when returning a buffer to the display!",
- (EvsResult) result);
- } else {
- // Everything looks good!
- // Keep track so tests or watch dogs can monitor progress
- mLock.lock();
- mFramesDisplayed++;
- mLock.unlock();
- }
+ // Everything looks good!
+ // Keep track so tests or watch dogs can monitor progress
+ mLock.lock();
+ mFramesDisplayed++;
+ mLock.unlock();
}
}
-
-
- switch (mReturnMode) {
- case eAutoReturn:
- // Send the camera buffer back now that the client has seen it
- ALOGD("Calling doneWithFrame");
- // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer?
- mCamera->doneWithFrame_1_1(bufDesc);
- break;
- case eNoAutoReturn:
- // Hang onto the buffer handle for now -- the client will return it explicitly later
- mHeldBuffers.push(bufDesc);
- }
-
- mLock.lock();
- ++mFramesReceived;
- mLock.unlock();
- mFrameSignal.notify_all();
-
- ALOGD("Frame handling complete");
}
+
+ switch (mReturnMode) {
+ case eAutoReturn:
+ // Send the camera buffer back now that the client has seen it
+ ALOGD("Calling doneWithFrame");
+ mCamera->doneWithFrame_1_1(bufDesc);
+ break;
+ case eNoAutoReturn:
+ // Hang onto the buffer handle for now -- the client will return it explicitly later
+ mHeldBuffers.push(bufDesc);
+ }
+
+ mLock.lock();
+ ++mFramesReceived;
+ mLock.unlock();
+ mFrameSignal.notify_all();
+
+ ALOGD("Frame handling complete");
+
+ return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEvent& event) {
+ // Local flag we use to keep track of when the stream is stopping
+ mLock.lock();
+ mLatestEventDesc = event;
+ if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+ // Signal that the last frame has been received and the stream is stopped
+ mRunning = false;
+ } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+ ALOGD("Camera parameter 0x%X is changed to 0x%X",
+ mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+ } else {
+ ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
+ }
+ mLock.unlock();
+ mEventSignal.notify_all();
+
return Void();
}
@@ -342,18 +342,18 @@
}
}
-bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
- InfoEventDesc &eventDesc) {
+bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
+ EvsEvent &event) {
// Wait until we get an expected parameter change event.
std::unique_lock<std::mutex> lock(mLock);
auto now = std::chrono::system_clock::now();
bool result = mEventSignal.wait_until(lock, now + 5s,
- [this, aTargetEvent, &eventDesc](){
+ [this, aTargetEvent, &event](){
bool flag = mLatestEventDesc.aType == aTargetEvent;
if (flag) {
- eventDesc.aType = mLatestEventDesc.aType;
- eventDesc.payload[0] = mLatestEventDesc.payload[0];
- eventDesc.payload[1] = mLatestEventDesc.payload[1];
+ event.aType = mLatestEventDesc.aType;
+ event.payload[0] = mLatestEventDesc.payload[0];
+ event.payload[1] = mLatestEventDesc.payload[1];
}
return flag;
@@ -363,21 +363,22 @@
return !result;
}
-const char *FrameHandler::eventToString(const InfoEventType aType) {
+const char *FrameHandler::eventToString(const EvsEventType aType) {
switch (aType) {
- case InfoEventType::STREAM_STARTED:
+ case EvsEventType::STREAM_STARTED:
return "STREAM_STARTED";
- case InfoEventType::STREAM_STOPPED:
+ case EvsEventType::STREAM_STOPPED:
return "STREAM_STOPPED";
- case InfoEventType::FRAME_DROPPED:
+ case EvsEventType::FRAME_DROPPED:
return "FRAME_DROPPED";
- case InfoEventType::TIMEOUT:
+ case EvsEventType::TIMEOUT:
return "TIMEOUT";
- case InfoEventType::PARAMETER_CHANGED:
+ case EvsEventType::PARAMETER_CHANGED:
return "PARAMETER_CHANGED";
- case InfoEventType::MASTER_RELEASED:
+ case EvsEventType::MASTER_RELEASED:
return "MASTER_RELEASED";
default:
return "Unknown";
}
}
+
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index 7f87cb4..e5f1b8f 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -33,7 +33,6 @@
using ::android::sp;
using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
@@ -56,6 +55,13 @@
FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
android::sp <IEvsDisplay> pDisplay = nullptr,
BufferControlFlag mode = eAutoReturn);
+ virtual ~FrameHandler() {
+ if (mCamera != nullptr) {
+ /* shutdown a camera explicitly */
+ shutdown();
+ }
+ }
+
void shutdown();
bool startStream();
@@ -67,19 +73,22 @@
bool isRunning();
void waitForFrameCount(unsigned frameCount);
- bool waitForEvent(const InfoEventType aTargetEvent,
- InfoEventDesc &eventDesc);
+ bool waitForEvent(const EvsEventType aTargetEvent,
+ EvsEvent &eventDesc);
void getFramesCounters(unsigned* received, unsigned* displayed);
void getFrameDimension(unsigned* width, unsigned* height);
private:
- // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
- Return<void> notifyEvent(const EvsEvent& event) override;
+
+ // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
+ Return<void> notify(const EvsEvent& event) override;
// Local implementation details
bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
- const char *eventToString(const InfoEventType aType);
+ const char *eventToString(const EvsEventType aType);
// Values initialized as startup
android::sp <IEvsCamera> mCamera;
@@ -100,7 +109,7 @@
unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually!
unsigned mFrameWidth = 0;
unsigned mFrameHeight = 0;
- InfoEventDesc mLatestEventDesc;
+ EvsEvent mLatestEventDesc;
};
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index a6e4881..1d3fd87 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -38,8 +38,9 @@
#include "FrameHandler.h"
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
@@ -50,8 +51,10 @@
#include <android/log.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
@@ -64,13 +67,28 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::sp;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 5;
+typedef struct {
+ int32_t width;
+ int32_t height;
+ int32_t format;
+ int32_t direction;
+ int32_t framerate;
+} RawStreamConfig;
+
+
// Test environment for Evs HIDL HAL.
class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -107,15 +125,16 @@
assert(pEnumerator != nullptr);
// Get the camera list
- pEnumerator->getCameraList([this](hidl_vec <CameraDesc> cameraList) {
- ALOGI("Camera list callback received %zu cameras",
- cameraList.size());
- cameraInfo.reserve(cameraList.size());
- for (auto&& cam: cameraList) {
- ALOGI("Found camera %s", cam.cameraId.c_str());
- cameraInfo.push_back(cam);
- }
- }
+ pEnumerator->getCameraList_1_1(
+ [this](hidl_vec <CameraDesc> cameraList) {
+ ALOGI("Camera list callback received %zu cameras",
+ cameraList.size());
+ cameraInfo.reserve(cameraList.size());
+ for (auto&& cam: cameraList) {
+ ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+ cameraInfo.push_back(cam);
+ }
+ }
);
// We insist on at least one camera for EVS to pass any camera tests
@@ -143,19 +162,23 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
for (int pass = 0; pass < 2; pass++) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
// Verify that this camera self-identifies correctly
- pCam->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
// Explicitly close the camera so resources are released right away
@@ -177,22 +200,26 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
// Verify that this camera self-identifies correctly
- pCam->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
sp<IEvsCamera_1_1> pCam2 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, pCam2);
ASSERT_NE(pCam2, nullptr);
@@ -210,10 +237,10 @@
pEnumerator->closeCamera(pCam);
// Verify that the second camera instance self-identifies correctly
- pCam2->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
// Close the second camera instance
@@ -235,10 +262,14 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -303,11 +334,15 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -371,6 +406,10 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Request exclusive access to the EVS display
sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
ASSERT_NE(pDisplay, nullptr);
@@ -378,7 +417,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -439,16 +478,20 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
@@ -486,7 +529,6 @@
nsecs_t runTime = end - firstFrame;
float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
- printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1);
ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
@@ -526,14 +568,33 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
+ Return<EvsResult> result = EvsResult::OK;
for (auto&& cam: cameraInfo) {
// Create a camera client
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Get the parameter list
+ std::vector<CameraParam> cmds;
+ pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
+ cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (cmds.size() < 1) {
+ continue;
+ }
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
nullptr,
@@ -547,83 +608,70 @@
// Ensure the stream starts
frameHandler->waitForFrameCount(1);
- // Try to program few parameters
- EvsResult result = EvsResult::OK;
- int32_t val0 = 100;
- int32_t val1 = 0;
-
result = pCam->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
- pCam->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ for (auto &cmd : cmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::BRIGHTNESS,
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+ int32_t val1 = 0;
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCam->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+
+ ASSERT_EQ(EvsResult::OK, result);
+
+ pCam->getIntParameter(cmd,
[&result, &val1](auto status, auto value) {
result = status;
if (status == EvsResult::OK) {
val1 = value;
}
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
- }
-
- val0 = 80;
- val1 = 0;
- pCam->setParameter(CameraParam::CONTRAST, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::CONTRAST,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
- }
-
- val0 = 300;
- val1 = 0;
- pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::ABSOLUTE_ZOOM,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::OK, result);
ASSERT_EQ(val0, val1) << "Values are not matched.";
}
result = pCam->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Shutdown
frameHandler->shutdown();
@@ -650,15 +698,19 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
sp<IEvsCamera_1_1> pCamNonMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
@@ -698,15 +750,15 @@
// Non-master client expects to receive a master role relesed
// notification.
- InfoEventDesc aNotification = {};
+ EvsEvent aNotification = {};
// Release a master role.
pCamMaster->unsetMaster();
// Verify a change notification.
- frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(InfoEventType::MASTER_RELEASED,
- static_cast<InfoEventType>(aNotification.aType));
+ frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
// Non-master becomes a master.
result = pCamNonMaster->setMaster();
@@ -720,9 +772,9 @@
frameHandlerNonMaster->shutdown();
// Verify a change notification.
- frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(InfoEventType::MASTER_RELEASED,
- static_cast<InfoEventType>(aNotification.aType));
+ frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
// Closing another stream.
frameHandlerMaster->shutdown();
@@ -752,18 +804,46 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
sp<IEvsCamera_1_1> pCamNonMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Get the parameter list
+ std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
+ pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
+ camMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
+ camNonMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camNonMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (camMasterCmds.size() < 1 ||
+ camNonMasterCmds.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,
@@ -778,11 +858,11 @@
// Set one client as the master
EvsResult result = pCamMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to set another client as the master.
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Start the camera's video stream via a master client.
bool startResult = frameHandlerMaster->startStream();
@@ -798,131 +878,168 @@
// Ensure the stream starts
frameHandlerNonMaster->waitForFrameCount(1);
- // Try to program CameraParam::BRIGHTNESS
- int32_t val0 = 100;
+ int32_t val0 = 0;
int32_t val1 = 0;
+ for (auto &cmd : camMasterCmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCamMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 1;
+ pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- InfoEventDesc aNotification = {};
+ // Try to program a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
- pCamMaster->getParameter(CameraParam::BRIGHTNESS,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
- if (result == EvsResult::OK) {
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCamMaster->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
- // Verify a change notification
- frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
- static_cast<InfoEventType>(aNotification.aType));
- ASSERT_EQ(CameraParam::BRIGHTNESS,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ // Wait a moment
+ sleep(1);
- // Try to program CameraParam::CONTRAST
- val0 = 80;
- val1 = 0;
- pCamMaster->setParameter(CameraParam::CONTRAST, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ // Non-master client expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ EvsEvent aNotification = {};
- if (result == EvsResult::OK) {
- pCamMaster->getParameter(CameraParam::CONTRAST,
+ pCamMaster->getIntParameter(cmd,
[&result, &val1](auto status, auto value) {
result = status;
if (status == EvsResult::OK) {
val1 = value;
}
});
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
ASSERT_EQ(val0, val1) << "Values are not matched.";
-
// Verify a change notification
- frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
- static_cast<InfoEventType>(aNotification.aType));
- ASSERT_EQ(CameraParam::CONTRAST,
+ frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification.aType));
+ ASSERT_EQ(cmd,
static_cast<CameraParam>(aNotification.payload[0]));
ASSERT_EQ(val1,
static_cast<int32_t>(aNotification.payload[1]));
}
// Try to adjust a parameter via non-master client
- pCamNonMaster->setParameter(CameraParam::CONTRAST, val0,
+ pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
// Non-master client attemps to be a master
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Master client retires from a master role
result = pCamMaster->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to adjust a parameter after being retired
- pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+ pCamMaster->setIntParameter(camMasterCmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
// Non-master client becomes a master
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to adjust a parameter via new master client
- pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ for (auto &cmd : camNonMasterCmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCamNonMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- // Wait a moment
- sleep(1);
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 1;
+ pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
- // Verify a change notification
- if (result == EvsResult::OK) {
- frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
+ // Try to program a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCamNonMaster->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Wait a moment
+ sleep(1);
+
+ // Non-master client expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ EvsEvent aNotification = {};
+
+ pCamNonMaster->getIntParameter(cmd,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+ // Verify a change notification
+ frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification.aType));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification.payload[0]));
ASSERT_EQ(val1,
static_cast<int32_t>(aNotification.payload[1]));
}
// New master retires from a master role
result = pCamNonMaster->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Shutdown
frameHandlerMaster->shutdown();
@@ -943,9 +1060,18 @@
TEST_F(EvsHidlTest, HighPriorityCameraClient) {
ALOGI("Starting HighPriorityCameraClient test");
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Request exclusive access to the EVS display
sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
ASSERT_NE(pDisplay, nullptr);
@@ -954,15 +1080,38 @@
for (auto&& cam: cameraInfo) {
// Create two clients
sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Get the parameter list; this test will use the first command in both
+ // lists.
+ std::vector<CameraParam> cam0Cmds, cam1Cmds;
+ pCam0->getParameterList([&cam0Cmds](hidl_vec<CameraParam> cmdList) {
+ cam0Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam0Cmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCam1->getParameterList([&cam1Cmds](hidl_vec<CameraParam> cmdList) {
+ cam1Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam1Cmds.push_back(cmd);
+ }
+ }
+ );
+ if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+ // Cannot execute this test.
+ return;
+ }
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
pDisplay,
@@ -982,67 +1131,121 @@
frameHandler0->waitForFrameCount(1);
frameHandler1->waitForFrameCount(1);
- // Client 1 becomes a master and programs a brightness.
+ // Client 1 becomes a master and programs a parameter.
EvsResult result = EvsResult::OK;
- int32_t val0 = 100;
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam1->getIntParameterRange(
+ cam1Cmds[0],
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
int32_t val1 = 0;
- result = pCam1->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ // Rounding down
+ val0 = val0 - (val0 % step);
- pCam1->setParameter(CameraParam::BRIGHTNESS, val0,
+ result = pCam1->setMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ pCam1->setIntParameter(cam1Cmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
+ ASSERT_EQ(EvsResult::OK, result);
// Verify a change notification
- InfoEventDesc aNotification = {};
- if (result == EvsResult::OK) {
- bool timeout =
- frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ EvsEvent aNotification = {};
+ bool timeout =
+ frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam1Cmds[0]);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
// Client 0 steals a master role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
- frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::MASTER_RELEASED);
+ frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::MASTER_RELEASED);
- // Client 0 programs a brightness
- val0 = 50;
+ // Client 0 programs a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
val1 = 0;
- pCam0->setParameter(CameraParam::BRIGHTNESS, val0,
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+
+ if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ pCam0->setIntParameter(cam0Cmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::OK, result);
// Verify a change notification
- if (result == EvsResult::OK) {
- bool timeout =
- frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ timeout =
+ frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam0Cmds[0]);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
// Turn off the display (yes, before the stream stops -- it should be handled)
pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1061,6 +1264,248 @@
}
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display. Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+ ALOGI("Starting CameraUseStreamConfigToDisplay test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ // Current EVS camera does not provide stream configurations in the
+ // metadata.
+ continue;
+ }
+
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ pDisplay,
+ FrameHandler::eAutoReturn);
+
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+ kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+ kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) {
+ ALOGI("Starting MultiCameraStream test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
+ cam.v1.cameraId.c_str());
+
+ continue;
+ }
+
+ // Create the first camera client with a selected stream configuration.
+ sp<IEvsCamera_1_1> pCam0 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam0, nullptr);
+
+ // Try to create the second camera client with different stream
+ // configuration.
+ int32_t id = targetCfg.id;
+ targetCfg.id += 1; // EVS manager sees only the stream id.
+ sp<IEvsCamera_1_1> pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_EQ(pCam1, nullptr);
+
+ // Try again with same stream configuration.
+ targetCfg.id = id;
+ pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam1, nullptr);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler0, nullptr);
+
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ bool startResult = false;
+ startResult = frameHandler0->startStream() &&
+ frameHandler1->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+}
+
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
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 094a372..f41b33c 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
@@ -370,31 +370,34 @@
},
.initialValue = {.floatValues = {100.0f}}}, // units in meters
- {.config = {.prop = toInt(VehicleProperty::TIRE_PRESSURE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = WHEEL_FRONT_LEFT,
- .minFloatValue = 100.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_FRONT_RIGHT,
- .minFloatValue = 100.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_LEFT,
- .minFloatValue = 100.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_RIGHT,
- .minFloatValue = 100.0f,
- .maxFloatValue = 300.0f,
- }}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_LEFT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_RIGHT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_LEFT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_RIGHT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ }},
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
.initialValue = {.floatValues = {200.0f}}}, // units in kPa
{.config =
@@ -595,11 +598,14 @@
.configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}},
.initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
- {.config = {.prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
+ },
.initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
{.config =
@@ -692,13 +698,18 @@
},
},
- {.config = {.prop = kMixedTypePropertyForTest,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
- .initialValue = {.stringValue = "MIXED property",
- .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
- .floatValues = {4.5f}}},
+ {
+ .config = {.prop = kMixedTypePropertyForTest,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
+ .initialValue =
+ {
+ .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
+ .floatValues = {4.5f},
+ .stringValue = "MIXED property",
+ },
+ },
{.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
.access = VehiclePropertyAccess::READ_WRITE,
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 9d249be..dc051d8 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
@@ -286,8 +286,8 @@
// Create a separate instance for each individual zone
VehiclePropValue prop = {
- .prop = cfg.prop,
- .areaId = curArea,
+ .areaId = curArea,
+ .prop = cfg.prop,
};
if (it.initialAreaValues.size() > 0) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index b8fd2ba..8677f83 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -101,9 +101,11 @@
rawEvent.toStyledString().c_str());
continue;
}
- VehiclePropValue event = {.prop = rawEvent["prop"].asInt(),
- .areaId = rawEvent["areaId"].asInt(),
- .timestamp = rawEvent["timestamp"].asInt64()};
+ VehiclePropValue event = {
+ .timestamp = rawEvent["timestamp"].asInt64(),
+ .areaId = rawEvent["areaId"].asInt(),
+ .prop = rawEvent["prop"].asInt(),
+ };
Json::Value rawEventValue = rawEvent["value"];
auto& value = event.value;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 356a6b9..9dc7085 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -120,7 +120,10 @@
}
{
- VehiclePropValue request = { .prop = propId, .areaId = areaId };
+ VehiclePropValue request = {
+ .areaId = areaId,
+ .prop = propId,
+ };
StatusCode halStatus;
auto val = mHal->get(request, &halStatus);
if (val != nullptr) {
@@ -150,10 +153,10 @@
VehicleEmulator::EmulatorMessage& respMsg) {
emulator::VehiclePropValue protoVal = rxMsg.value(0);
VehiclePropValue val = {
- .prop = protoVal.prop(),
- .areaId = protoVal.area_id(),
- .status = (VehiclePropertyStatus)protoVal.status(),
- .timestamp = elapsedRealtimeNano(),
+ .timestamp = elapsedRealtimeNano(),
+ .areaId = protoVal.area_id(),
+ .prop = protoVal.prop(),
+ .status = (VehiclePropertyStatus)protoVal.status(),
};
respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
diff --git a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
index a291351..4e3ade1 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -57,11 +57,11 @@
};
TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) {
- void* raw = valuePool->obtain(VehiclePropertyType::INT32).get();
+ auto value = valuePool->obtain(VehiclePropertyType::INT32);
// At this point, v1 should be recycled and the only object in the pool.
- ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get());
+ ASSERT_EQ(value.get(), valuePool->obtain(VehiclePropertyType::INT32).get());
// Obtaining value of another type - should return a new object
- ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get());
+ ASSERT_NE(value.get(), valuePool->obtain(VehiclePropertyType::FLOAT).get());
ASSERT_EQ(3u, stats->Obtained);
ASSERT_EQ(2u, stats->Created);
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 1355d9f..bc0b4d3 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2569,6 +2569,11 @@
/** AP can only shutdown with postponing allowed. */
SHUTDOWN_ONLY = 3,
+
+ /**
+ * AP may enter deep sleep, but must either sleep or shut down immediately.
+ * Postponing is not allowed. */
+ SLEEP_IMMEDIATELY = 4,
};
enum VehicleApPowerStateReport : int32_t {
@@ -3581,4 +3586,3 @@
enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
PUBLISHER_ID = 1,
};
-
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp
index 60228f2..c418032 100644
--- a/biometrics/fingerprint/2.1/vts/functional/Android.bp
+++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -19,6 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
static_libs: ["android.hardware.biometrics.fingerprint@2.1"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
index d577ce4..bdbf72d 100644
--- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -16,14 +16,15 @@
#define LOG_TAG "fingerprint_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <utils/Condition.h>
#include <cinttypes>
@@ -183,315 +184,295 @@
std::promise<void> promise;
};
-// Test environment for Fingerprint HIDL HAL.
-class FingerprintHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static FingerprintHidlEnvironment* Instance() {
- static FingerprintHidlEnvironment* instance = new FingerprintHidlEnvironment;
- return instance;
- }
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = IBiometricsFingerprint::getService(GetParam());
+ ASSERT_FALSE(mService == nullptr);
- virtual void registerTestServices() override { registerTestService<IBiometricsFingerprint>(); }
-};
+ /*
+ * Devices shipped from now on will instead store
+ * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+ * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+ */
-class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(
- FingerprintHidlEnvironment::Instance()->getServiceName<IBiometricsFingerprint>());
- ASSERT_FALSE(mService == nullptr);
+ uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+ ASSERT_TRUE(api_level != 0);
- /*
- * Devices shipped from now on will instead store
- * fingerprint data under /data/vendor_de/<user-id>/fpdata.
- * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
- */
+ // 27 is the API number for O-MR1
+ if (api_level <= 27) {
+ kTmpDir = "/data/system/users/0/fpdata/";
+ } else {
+ kTmpDir = "/data/vendor_de/0/fpdata/";
+ }
- uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
- if (api_level == 0) {
- api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
- }
- ASSERT_TRUE(api_level != 0);
-
- // 27 is the API number for O-MR1
- if (api_level <= 27) {
- kTmpDir = "/data/system/users/0/fpdata/";
- } else {
- kTmpDir = "/data/vendor_de/0/fpdata/";
+ Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
}
- Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- }
+ virtual void TearDown() override {}
- virtual void TearDown() override {}
-
- sp<IBiometricsFingerprint> mService;
+ sp<IBiometricsFingerprint> mService;
};
-
// The service should be reachable.
-TEST_F(FingerprintHidlTest, ConnectTest) {
- sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, ConnectTest) {
+ sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
}
// Starting the service with null callback should succeed.
-TEST_F(FingerprintHidlTest, ConnectNullTest) {
- Return<uint64_t> rc = mService->setNotify(NULL);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, ConnectNullTest) {
+ Return<uint64_t> rc = mService->setNotify(NULL);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
}
// Pre-enroll should always return unique, cryptographically secure, non-zero number
-TEST_F(FingerprintHidlTest, PreEnrollTest) {
- std::map<uint64_t, uint64_t> m;
+TEST_P(FingerprintHidlTest, PreEnrollTest) {
+ std::map<uint64_t, uint64_t> m;
- for(unsigned int i = 0; i < kIterations; ++i) {
- uint64_t res = static_cast<uint64_t>(mService->preEnroll());
- EXPECT_NE(0UL, res);
- m[res]++;
- EXPECT_EQ(1UL, m[res]);
- }
+ for (unsigned int i = 0; i < kIterations; ++i) {
+ uint64_t res = static_cast<uint64_t>(mService->preEnroll());
+ EXPECT_NE(0UL, res);
+ m[res]++;
+ EXPECT_EQ(1UL, m[res]);
+ }
}
// Enroll with an invalid (all zeroes) HAT should fail.
-TEST_F(FingerprintHidlTest, EnrollInvalidHatTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnrollInvalidHatTest) {
+ sp<ErrorCallback> cb = new ErrorCallback();
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- uint8_t token[69];
- for(int i=0; i<69; i++) {
- token[i] = 0;
- }
+ uint8_t token[69];
+ for (int i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
- Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // At least one call to onError should occur
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
+ // At least one call to onError should occur
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
}
// Enroll with an invalid (null) HAT should fail.
-TEST_F(FingerprintHidlTest, EnrollNullTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnrollNullTest) {
+ sp<ErrorCallback> cb = new ErrorCallback();
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- uint8_t token[69];
- Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ uint8_t token[69];
+ Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // At least one call to onError should occur
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
+ // At least one call to onError should occur
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
}
// PostEnroll should always return within 3s
-TEST_F(FingerprintHidlTest, PostEnrollTest) {
- sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
- Return<uint64_t> rc = mService->setNotify(cb);
+TEST_P(FingerprintHidlTest, PostEnrollTest) {
+ sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
+ Return<uint64_t> rc = mService->setNotify(cb);
- auto start = std::chrono::system_clock::now();
- Return<RequestStatus> res = mService->postEnroll();
- auto elapsed = std::chrono::system_clock::now() - start;
- ASSERT_GE(kTimeoutInSeconds, elapsed);
+ auto start = std::chrono::system_clock::now();
+ Return<RequestStatus> res = mService->postEnroll();
+ auto elapsed = std::chrono::system_clock::now() - start;
+ ASSERT_GE(kTimeoutInSeconds, elapsed);
}
// getAuthenticatorId should always return non-zero numbers
-TEST_F(FingerprintHidlTest, GetAuthenticatorIdTest) {
- Return<uint64_t> res = mService->getAuthenticatorId();
- EXPECT_NE(0UL, static_cast<uint64_t>(res));
+TEST_P(FingerprintHidlTest, GetAuthenticatorIdTest) {
+ Return<uint64_t> res = mService->getAuthenticatorId();
+ EXPECT_NE(0UL, static_cast<uint64_t>(res));
}
// Enumerate should always trigger onEnumerated(fid=0, rem=0) when there are no fingerprints
-TEST_F(FingerprintHidlTest, EnumerateTest) {
- sp<EnumerateCallback> cb = new EnumerateCallback();
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnumerateTest) {
+ sp<EnumerateCallback> cb = new EnumerateCallback();
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- // Callback will return when rem=0 is found
- Return<RequestStatus> res = mService->enumerate();
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- EXPECT_EQ(0UL, cb->fingerId);
- EXPECT_EQ(0UL, cb->remaining);
-
+ // Callback will return when rem=0 is found
+ Return<RequestStatus> res = mService->enumerate();
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ EXPECT_EQ(0UL, cb->fingerId);
+ EXPECT_EQ(0UL, cb->remaining);
}
// Remove should succeed on any inputs
// At least one callback with "remaining=0" should occur
-TEST_F(FingerprintHidlTest, RemoveFingerprintTest) {
- // Register callback
- sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, RemoveFingerprintTest) {
+ // Register callback
+ sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- // Remove a fingerprint
- Return<RequestStatus> res = mService->remove(kGroupId, 1);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Remove a fingerprint
+ Return<RequestStatus> res = mService->remove(kGroupId, 1);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // At least one call to onRemove with remaining=0 should occur
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // At least one call to onRemove with remaining=0 should occur
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
}
// Remove should accept 0 to delete all fingerprints
// At least one callback with "remaining=0" should occur.
-TEST_F(FingerprintHidlTest, RemoveAllFingerprintsTest) {
- // Register callback
- sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, RemoveAllFingerprintsTest) {
+ // Register callback
+ sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- // Remove all fingerprints
- Return<RequestStatus> res = mService->remove(kGroupId, 0);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // Remove all fingerprints
+ Return<RequestStatus> res = mService->remove(kGroupId, 0);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
}
// Active group should successfully set to a writable location.
-TEST_F(FingerprintHidlTest, SetActiveGroupTest) {
- // Create an active group
- Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupTest) {
+ // Create an active group
+ Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // Reset active group
- res = mService->setActiveGroup(kGroupId, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Reset active group
+ res = mService->setActiveGroup(kGroupId, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
}
// Active group should fail to set to an unwritable location.
-TEST_F(FingerprintHidlTest, SetActiveGroupUnwritableTest) {
- // Create an active group to an unwritable location (device root dir)
- Return<RequestStatus> res = mService->setActiveGroup(3, "/");
- ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupUnwritableTest) {
+ // Create an active group to an unwritable location (device root dir)
+ Return<RequestStatus> res = mService->setActiveGroup(3, "/");
+ ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // Reset active group
- res = mService->setActiveGroup(kGroupId, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Reset active group
+ res = mService->setActiveGroup(kGroupId, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
}
// Active group should fail to set to a null location.
-TEST_F(FingerprintHidlTest, SetActiveGroupNullTest) {
- // Create an active group to a null location.
- Return<RequestStatus> res = mService->setActiveGroup(4, nullptr);
- ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupNullTest) {
+ // Create an active group to a null location.
+ Return<RequestStatus> res = mService->setActiveGroup(4, nullptr);
+ ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // Reset active group
- res = mService->setActiveGroup(kGroupId, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Reset active group
+ res = mService->setActiveGroup(kGroupId, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
}
// Cancel should always return ERROR_CANCELED from any starting state including
// the IDLE state.
-TEST_F(FingerprintHidlTest, CancelTest) {
- sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelTest) {
+ sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0UL, static_cast<uint64_t>(rc));
- Return<RequestStatus> res = mService->cancel();
- // check that we were able to make an IPC request successfully
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ Return<RequestStatus> res = mService->cancel();
+ // check that we were able to make an IPC request successfully
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be ERROR_CANCELED
- ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+ // make sure callback was invoked within kTimeoutInSeconds
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // check error should be ERROR_CANCELED
+ ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
}
// A call to cancel should succeed during enroll.
-TEST_F(FingerprintHidlTest, CancelEnrollTest) {
- Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, CancelEnrollTest) {
+ Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0U, static_cast<uint64_t>(rc));
+ sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0U, static_cast<uint64_t>(rc));
- uint8_t token[69];
- res = mService->enroll(token, kGroupId, kTimeout);
- // check that we were able to make an IPC request successfully
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ uint8_t token[69];
+ res = mService->enroll(token, kGroupId, kTimeout);
+ // check that we were able to make an IPC request successfully
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- res = mService->cancel();
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ res = mService->cancel();
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // make sure callback was invoked within kTimeoutInSeconds
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be ERROR_CANCELED
- ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+ // check error should be ERROR_CANCELED
+ ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
}
// A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelAuthTest) {
- sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelAuthTest) {
+ sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0U, static_cast<uint64_t>(rc));
- Return<RequestStatus> res = mService->authenticate(0, kGroupId);
- // check that we were able to make an IPC request successfully
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ Return<RequestStatus> res = mService->authenticate(0, kGroupId);
+ // check that we were able to make an IPC request successfully
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- res = mService->cancel();
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ res = mService->cancel();
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // make sure callback was invoked within kTimeoutInSeconds
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be ERROR_CANCELED
- ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+ // check error should be ERROR_CANCELED
+ ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
}
// A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelRemoveTest) {
- sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelRemoveTest) {
+ sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0U, static_cast<uint64_t>(rc));
- // Remove a fingerprint
- Return<RequestStatus> res = mService->remove(kGroupId, 1);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Remove a fingerprint
+ Return<RequestStatus> res = mService->remove(kGroupId, 1);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- res = mService->cancel();
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ res = mService->cancel();
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // make sure callback was invoked within kTimeoutInSeconds
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be ERROR_CANCELED
- ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+ // check error should be ERROR_CANCELED
+ ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
}
// A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelRemoveAllTest) {
- sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
- Return<uint64_t> rc = mService->setNotify(cb);
- ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelRemoveAllTest) {
+ sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+ Return<uint64_t> rc = mService->setNotify(cb);
+ ASSERT_NE(0U, static_cast<uint64_t>(rc));
- // Remove a fingerprint
- Return<RequestStatus> res = mService->remove(kGroupId, 0);
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ // Remove a fingerprint
+ Return<RequestStatus> res = mService->remove(kGroupId, 0);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- res = mService->cancel();
- ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ res = mService->cancel();
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ // make sure callback was invoked within kTimeoutInSeconds
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be ERROR_CANCELED
- ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+ // check error should be ERROR_CANCELED
+ ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
}
} // anonymous namespace
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(FingerprintHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- FingerprintHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
-
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IBiometricsFingerprint::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
index 85e8742..838d1cc 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
@@ -156,8 +156,9 @@
static constexpr PcmParameters kInvalidPcmParameters = {
.sampleRate = SampleRate::RATE_UNKNOWN,
+ .channelMode = ChannelMode::UNKNOWN,
.bitsPerSample = BitsPerSample::BITS_UNKNOWN,
- .channelMode = ChannelMode::UNKNOWN};
+ };
// can't be constexpr because of non-literal type
static const CodecConfiguration kInvalidCodecConfiguration;
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
index 292e28b..6ea61e1 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
@@ -94,16 +94,18 @@
static const AptxParameters kDefaultOffloadAptxCapability = {
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
SampleRate::RATE_48000),
+ .channelMode = ChannelMode::STEREO,
.bitsPerSample = BitsPerSample::BITS_16,
- .channelMode = ChannelMode::STEREO};
+};
// aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
// mChannelMode:(STEREO)
static const AptxParameters kDefaultOffloadAptxHdCapability = {
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
SampleRate::RATE_48000),
+ .channelMode = ChannelMode::STEREO,
.bitsPerSample = BitsPerSample::BITS_24,
- .channelMode = ChannelMode::STEREO};
+};
const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
{.codecType = CodecType::SBC, .capabilities = {}},
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp
index 5d1a9cb..5244b95 100644
--- a/boot/1.0/vts/functional/Android.bp
+++ b/boot/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalBootV1_0TargetTest.cpp"],
static_libs: ["android.hardware.boot@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
index 2f2052c..fbddf6d 100644
--- a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
+++ b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
#include <android/hardware/boot/1.0/IBootControl.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unordered_set>
@@ -37,30 +38,17 @@
using std::unordered_set;
using std::vector;
-// Test environment for Boot HIDL HAL.
-class BootHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static BootHidlEnvironment* Instance() {
- static BootHidlEnvironment* instance = new BootHidlEnvironment;
- return instance;
+// The main test class for the Boot HIDL HAL.
+class BootHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ boot = IBootControl::getService(GetParam());
+ ASSERT_NE(boot, nullptr);
}
- virtual void registerTestServices() override { registerTestService<IBootControl>(); }
-};
+ virtual void TearDown() override {}
-// The main test class for the Boot HIDL HAL.
-class BootHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- boot = ::testing::VtsHalHidlTargetTestBase::getService<IBootControl>(
- BootHidlEnvironment::Instance()->getServiceName<IBootControl>());
- ASSERT_NE(boot, nullptr);
- }
-
- virtual void TearDown() override {}
-
- sp<IBootControl> boot;
+ sp<IBootControl> boot;
};
auto generate_callback(CommandResult *dest) {
@@ -68,108 +56,105 @@
}
// Sanity check Boot::getNumberSlots().
-TEST_F(BootHidlTest, GetNumberSlots) {
- uint32_t slots = boot->getNumberSlots();
- EXPECT_LE((uint32_t)2, slots);
+TEST_P(BootHidlTest, GetNumberSlots) {
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_LE((uint32_t)2, slots);
}
// Sanity check Boot::getCurrentSlot().
-TEST_F(BootHidlTest, GetCurrentSlot) {
- Slot curSlot = boot->getCurrentSlot();
- uint32_t slots = boot->getNumberSlots();
- EXPECT_LT(curSlot, slots);
+TEST_P(BootHidlTest, GetCurrentSlot) {
+ Slot curSlot = boot->getCurrentSlot();
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_LT(curSlot, slots);
}
// Sanity check Boot::markBootSuccessful().
-TEST_F(BootHidlTest, MarkBootSuccessful) {
- CommandResult cr;
- Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
- ASSERT_TRUE(result.isOk());
- if (cr.success) {
- Slot curSlot = boot->getCurrentSlot();
- BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
- EXPECT_EQ(BoolResult::TRUE, ret);
- }
+TEST_P(BootHidlTest, MarkBootSuccessful) {
+ CommandResult cr;
+ Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+ ASSERT_TRUE(result.isOk());
+ if (cr.success) {
+ Slot curSlot = boot->getCurrentSlot();
+ BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
+ EXPECT_EQ(BoolResult::TRUE, ret);
+ }
}
// Sanity check Boot::setActiveBootSlot() on good and bad inputs.
-TEST_F(BootHidlTest, SetActiveBootSlot) {
- for (Slot s = 0; s < 2; s++) {
- CommandResult cr;
- Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- }
- {
- // Restore original flags to avoid problems on reboot
- CommandResult cr;
- Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(cr.success);
- }
- {
- CommandResult cr;
- uint32_t slots = boot->getNumberSlots();
- Return<void> result =
- boot->setActiveBootSlot(slots, generate_callback(&cr));
- ASSERT_TRUE(result.isOk());
- EXPECT_EQ(false, cr.success);
- }
+TEST_P(BootHidlTest, SetActiveBootSlot) {
+ for (Slot s = 0; s < 2; s++) {
+ CommandResult cr;
+ Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ }
+ {
+ // Restore original flags to avoid problems on reboot
+ CommandResult cr;
+ Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ }
+ {
+ CommandResult cr;
+ uint32_t slots = boot->getNumberSlots();
+ Return<void> result = boot->setActiveBootSlot(slots, generate_callback(&cr));
+ ASSERT_TRUE(result.isOk());
+ EXPECT_EQ(false, cr.success);
+ }
}
// Sanity check Boot::setSlotAsUnbootable() on good and bad inputs.
-TEST_F(BootHidlTest, SetSlotAsUnbootable) {
- {
- CommandResult cr;
- Slot curSlot = boot->getCurrentSlot();
- Slot otherSlot = curSlot ? 0 : 1;
- Return<void> result =
- boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- if (cr.success) {
- EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
+TEST_P(BootHidlTest, SetSlotAsUnbootable) {
+ {
+ CommandResult cr;
+ Slot curSlot = boot->getCurrentSlot();
+ Slot otherSlot = curSlot ? 0 : 1;
+ Return<void> result = boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ if (cr.success) {
+ EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
- // Restore original flags to avoid problems on reboot
- result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(cr.success);
- result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(cr.success);
- result = boot->markBootSuccessful(generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- EXPECT_TRUE(cr.success);
+ // Restore original flags to avoid problems on reboot
+ result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ result = boot->markBootSuccessful(generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ }
}
- }
- {
- CommandResult cr;
- uint32_t slots = boot->getNumberSlots();
- Return<void> result =
- boot->setSlotAsUnbootable(slots, generate_callback(&cr));
- EXPECT_TRUE(result.isOk());
- EXPECT_EQ(false, cr.success);
- }
+ {
+ CommandResult cr;
+ uint32_t slots = boot->getNumberSlots();
+ Return<void> result = boot->setSlotAsUnbootable(slots, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_EQ(false, cr.success);
+ }
}
// Sanity check Boot::isSlotBootable() on good and bad inputs.
-TEST_F(BootHidlTest, IsSlotBootable) {
- for (Slot s = 0; s < 2; s++) {
- EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
- }
- uint32_t slots = boot->getNumberSlots();
- EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
+TEST_P(BootHidlTest, IsSlotBootable) {
+ for (Slot s = 0; s < 2; s++) {
+ EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
+ }
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
}
// Sanity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
-TEST_F(BootHidlTest, IsSlotMarkedSuccessful) {
- for (Slot s = 0; s < 2; s++) {
- EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
- }
- uint32_t slots = boot->getNumberSlots();
- EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
+TEST_P(BootHidlTest, IsSlotMarkedSuccessful) {
+ for (Slot s = 0; s < 2; s++) {
+ EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
+ }
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
}
// Sanity check Boot::getSuffix() on good and bad inputs.
-TEST_F(BootHidlTest, GetSuffix) {
+TEST_P(BootHidlTest, GetSuffix) {
string suffixStr;
unordered_set<string> suffixes;
auto cb = [&](hidl_string suffix) { suffixStr = suffix.c_str(); };
@@ -191,11 +176,7 @@
}
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(BootHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- BootHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, BootHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBootControl::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
index dca5c26..abf1bf9 100644
--- a/boot/1.1/default/Android.bp
+++ b/boot/1.1/default/Android.bp
@@ -1,5 +1,6 @@
cc_library_shared {
name: "android.hardware.boot@1.1-impl",
+ stem: "android.hardware.boot@1.0-impl-1.1",
defaults: [
"hidl_defaults",
"libboot_control_defaults",
@@ -31,6 +32,10 @@
init_rc: ["android.hardware.boot@1.1-service.rc"],
srcs: ["service.cpp"],
+ vintf_fragments: [
+ "android.hardware.boot@1.1.xml",
+ ],
+
shared_libs: [
"liblog",
"libhardware",
diff --git a/boot/1.1/default/android.hardware.boot@1.1.xml b/boot/1.1/default/android.hardware.boot@1.1.xml
new file mode 100644
index 0000000..83d5d2e
--- /dev/null
+++ b/boot/1.1/default/android.hardware.boot@1.1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.boot</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.1::IBootControl/default</fqname>
+ </hal>
+</manifest>
diff --git a/boot/1.1/default/service.cpp b/boot/1.1/default/service.cpp
index b24b464..93eaeda 100644
--- a/boot/1.1/default/service.cpp
+++ b/boot/1.1/default/service.cpp
@@ -15,11 +15,11 @@
*/
#define LOG_TAG "android.hardware.boot@1.1-service"
-#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
#include <hidl/LegacySupport.h>
using android::hardware::defaultPassthroughServiceImplementation;
-using ::android::hardware::boot::V1_1::IBootControl;
+using ::android::hardware::boot::V1_0::IBootControl;
int main(int /* argc */, char* /* argv */[]) {
return defaultPassthroughServiceImplementation<IBootControl>();
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 9a2fddf..f518a15 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -754,11 +754,11 @@
int fd, double fpsUpperBound, SupportedV4L2Format* format) {
format->frameRates.clear();
- v4l2_frmivalenum frameInterval {
- .pixel_format = format->fourcc,
- .width = format->width,
- .height = format->height,
- .index = 0
+ v4l2_frmivalenum frameInterval{
+ .index = 0,
+ .pixel_format = format->fourcc,
+ .width = format->width,
+ .height = format->height,
};
for (frameInterval.index = 0;
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index dc5579a..9ff0d74 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -2412,9 +2412,7 @@
mV4L2BufferCount = req_buffers.count;
for (uint32_t i = 0; i < req_buffers.count; i++) {
v4l2_buffer buffer = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .index = i,
- .memory = V4L2_MEMORY_MMAP};
+ .index = i, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index 622baa5..ab39c0e 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,6 +29,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index f0bba57..0f16de5 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "mediacas_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/ICas.h>
#include <android/hardware/cas/1.0/ICasListener.h>
@@ -27,8 +25,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.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>
@@ -208,29 +209,16 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
- protected:
+ protected:
static void description(const std::string& description) {
RecordProperty("description", description);
}
@@ -419,7 +407,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, EnumeratePlugins) {
+TEST_P(MediaCasHidlTest, EnumeratePlugins) {
description("Test enumerate plugins");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -440,7 +428,7 @@
}
}
-TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) {
+TEST_P(MediaCasHidlTest, TestInvalidSystemIdFails) {
description("Test failure for invalid system ID");
sp<MediaCasListener> casListener = new MediaCasListener();
@@ -458,7 +446,7 @@
EXPECT_EQ(descramblerBase, nullptr);
}
-TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) {
+TEST_P(MediaCasHidlTest, TestClearKeyPluginInstalled) {
description("Test if ClearKey plugin is installed");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -480,7 +468,7 @@
ASSERT_TRUE(false) << "ClearKey plugin not installed";
}
-TEST_F(MediaCasHidlTest, TestClearKeyApis) {
+TEST_P(MediaCasHidlTest, TestClearKeyApis) {
description("Test that valid call sequences succeed");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -584,7 +572,7 @@
EXPECT_EQ(Status::OK, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
+TEST_P(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
description("Test that all sessions are closed after a MediaCas object is released");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -611,7 +599,7 @@
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeyErrors) {
+TEST_P(MediaCasHidlTest, TestClearKeyErrors) {
description("Test that invalid call sequences fail with expected error codes");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -700,7 +688,7 @@
EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
}
-TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+TEST_P(MediaCasHidlTest, TestClearKeyOobFails) {
description("Test that oob descramble request fails with expected error");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -849,11 +837,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp
index 8afd19a..9e8eb52 100644
--- a/cas/1.1/vts/functional/Android.bp
+++ b/cas/1.1/vts/functional/Android.bp
@@ -30,6 +30,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 0264bdd..7e5a61a 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -27,8 +27,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.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>
@@ -251,27 +254,14 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
protected:
static void description(const std::string& description) {
@@ -453,7 +443,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
description("Test that valid call sequences with SessionEvent send and receive");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -561,11 +551,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/cas/1.2/Android.bp b/cas/1.2/Android.bp
new file mode 100644
index 0000000..af98b2e
--- /dev/null
+++ b/cas/1.2/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.cas@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "ICas.hal",
+ "ICasListener.hal",
+ "IMediaCasService.hal",
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/cas/1.2/ICas.hal b/cas/1.2/ICas.hal
new file mode 100644
index 0000000..23edc50
--- /dev/null
+++ b/cas/1.2/ICas.hal
@@ -0,0 +1,43 @@
+/*
+ * 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.cas@1.2;
+
+import @1.0::HidlCasSessionId;
+import @1.1::ICas;
+import ScramblingMode;
+import SessionIntent;
+import Status;
+
+/**
+ * ICas is the API to control the cas system and is accessible from both
+ * Java and native level. It is used to manage sessions, provision/refresh
+ * the cas system, and process the EMM/ECM messages. It also allows bi-directional,
+ * scheme-specific communications between the client and the cas system.
+ */
+interface ICas extends @1.1::ICas {
+ /**
+ * Open a session to descramble one or more streams by specifying intention
+ * and scrambling mode.
+ *
+ * @param intent the intention of the session to be opened.
+ * @param mode the scrambling mode the session will use.
+ * @return status the status of the call.
+ * @return sessionId the id of the newly opened session.
+ */
+ openSession_1_2(SessionIntent intent, ScramblingMode mode)
+ generates (Status status, HidlCasSessionId sessionId);
+};
diff --git a/cas/1.2/ICasListener.hal b/cas/1.2/ICasListener.hal
new file mode 100644
index 0000000..9a8be20
--- /dev/null
+++ b/cas/1.2/ICasListener.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.cas@1.2;
+
+import @1.1::ICasListener;
+import StatusEvent;
+
+interface ICasListener extends @1.1::ICasListener {
+ /**
+ * Notify the listener that the status of CAS system has changed.
+ *
+ * @param event the event type of status change.
+ * @param number value for status event.
+ * For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+ * the positive number presents how many plugins are inserted;
+ * the negative number presents how many plugins are removed.
+ * Client must enumerate plugins after receive the event.
+ * For PLUGIN_SESSION_NUMBER_CHANGED event:
+ * the number presents how many sessions are supported
+ * in the plugin.
+ */
+ onStatusUpdate(StatusEvent event, int32_t number);
+};
diff --git a/cas/1.2/IMediaCasService.hal b/cas/1.2/IMediaCasService.hal
new file mode 100644
index 0000000..a0bec7e
--- /dev/null
+++ b/cas/1.2/IMediaCasService.hal
@@ -0,0 +1,35 @@
+/*
+ * 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.cas@1.2;
+
+import ICas;
+import ICasListener;
+import @1.1::IMediaCasService;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ *
+ * The 1.2 must always create 1.2 ICas interfaces, which are
+ * returned via the 1.1 createPluginExt method.
+ *
+ * To use 1.2 features the caller must cast the returned interface to a
+ * 1.2 HAL, using V1_2::ICas::castFrom().
+ */
+interface IMediaCasService extends @1.1::IMediaCasService {};
diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp
new file mode 100644
index 0000000..9e53148
--- /dev/null
+++ b/cas/1.2/default/Android.bp
@@ -0,0 +1,49 @@
+cc_defaults {
+ name: "cas_service_defaults@1.2",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "CasImpl.cpp",
+ "DescramblerImpl.cpp",
+ "MediaCasService.cpp",
+ "service.cpp",
+ "SharedLibrary.cpp",
+ "TypeConvert.cpp",
+ ],
+
+ compile_multilib: "32",
+
+ shared_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas@1.1",
+ "android.hardware.cas@1.2",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.memory@1.0",
+ "libbinder",
+ "libhidlbase",
+ "libhidlmemory",
+ "liblog",
+ "libutils",
+ ],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ "media_plugin_headers",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.cas@1.2-service",
+ vintf_fragments: ["android.hardware.cas@1.2-service.xml"],
+ defaults: ["cas_service_defaults@1.2"],
+ init_rc: ["android.hardware.cas@1.2-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.cas@1.2-service-lazy",
+ vintf_fragments: ["android.hardware.cas@1.2-service-lazy.xml"],
+ overrides: ["android.hardware.cas@1.2-service"],
+ defaults: ["cas_service_defaults@1.2"],
+ init_rc: ["android.hardware.cas@1.2-service-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/cas/1.2/default/CasImpl.cpp b/cas/1.2/default/CasImpl.cpp
new file mode 100644
index 0000000..46dd251
--- /dev/null
+++ b/cas/1.2/default/CasImpl.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ icensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+#define LOG_TAG "android.hardware.cas@1.1-CasImpl"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+CasImpl::CasImpl(const sp<ICasListener>& listener) : mListener(listener) {
+ ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+ ALOGV("DTOR");
+ release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin* plugin) {
+ mLibrary = library;
+ std::shared_ptr<CasPlugin> holder(plugin);
+ std::atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ HidlCasData eventData;
+ if (data != NULL) {
+ eventData.setToExternal(data, size);
+ }
+
+ mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ HidlCasData eventData;
+ if (data != NULL) {
+ eventData.setToExternal(data, size);
+ }
+
+ if (sessionId != NULL) {
+ mListener->onSessionEvent(*sessionId, event, arg, eventData);
+ } else {
+ mListener->onEvent(event, arg, eventData);
+ }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+ if (mListener == NULL) {
+ return;
+ }
+ sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(mListener);
+
+ if (listenerV1_2 != NULL) {
+ listenerV1_2->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+ }
+}
+
+Return<Status> CasImpl::setPluginStatusUpdateCallback() {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setPrivateData(pvtData));
+}
+
+Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+ CasSessionId sessionId;
+
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ status_t err = INVALID_OPERATION;
+ if (holder.get() != nullptr) {
+ err = holder->openSession(&sessionId);
+ holder.reset();
+ }
+
+ _hidl_cb(toStatus(err), sessionId);
+
+ return Void();
+}
+
+Return<void> CasImpl::openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+ openSession_1_2_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+ CasSessionId sessionId;
+
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ status_t err = INVALID_OPERATION;
+ if (holder.get() != nullptr) {
+ err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+ &sessionId);
+ holder.reset();
+ }
+
+ _hidl_cb(toStatus_1_2(err), sessionId);
+
+ return Void();
+}
+
+Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
+ const HidlCasData& pvtData) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->closeSession(sessionId));
+}
+
+Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEmm(emm));
+}
+
+Return<Status> CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendEvent(event, arg, eventData);
+ return toStatus(err);
+}
+
+Return<Status> CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+ int32_t arg, const HidlCasData& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+ return toStatus(err);
+}
+
+Return<Status> CasImpl::provision(const hidl_string& provisionString) {
+ ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+Return<Status> CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) {
+ ALOGV("%s", __FUNCTION__);
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->refreshEntitlements(refreshType, refreshData);
+ return toStatus(err);
+}
+
+Return<Status> CasImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ std::shared_ptr<CasPlugin> holder(nullptr);
+ std::atomic_store(&mPluginHolder, holder);
+
+ return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.2/default/CasImpl.h b/cas/1.2/default/CasImpl.h
new file mode 100644
index 0000000..4325c20
--- /dev/null
+++ b/cas/1.2/default/CasImpl.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+
+#include <android/hardware/cas/1.1/ICas.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct CasPlugin;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+struct ICasListener;
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasData;
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+using ::android::hardware::cas::V1_2::ScramblingMode;
+using ::android::hardware::cas::V1_2::SessionIntent;
+using ::android::hardware::cas::V1_2::StatusEvent;
+
+class SharedLibrary;
+
+class CasImpl : public V1_2::ICas {
+ public:
+ CasImpl(const sp<ICasListener>& listener);
+ virtual ~CasImpl();
+
+ static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId);
+
+ static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+ void init(const sp<SharedLibrary>& library, CasPlugin* plugin);
+ void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size);
+
+ void onStatusUpdate(int32_t event, int32_t arg);
+
+ // ICas inherits
+
+ Return<Status> setPluginStatusUpdateCallback();
+
+ virtual Return<Status> setPrivateData(const HidlCasData& pvtData) override;
+
+ virtual Return<void> openSession(openSession_cb _hidl_cb) override;
+
+ virtual Return<void> openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+ openSession_1_2_cb _hidl_cb) override;
+
+ virtual Return<Status> closeSession(const HidlCasSessionId& sessionId) override;
+
+ virtual Return<Status> setSessionPrivateData(const HidlCasSessionId& sessionId,
+ const HidlCasData& pvtData) override;
+
+ virtual Return<Status> processEcm(const HidlCasSessionId& sessionId,
+ const HidlCasData& ecm) override;
+
+ virtual Return<Status> processEmm(const HidlCasData& emm) override;
+
+ virtual Return<Status> sendEvent(int32_t event, int32_t arg,
+ const HidlCasData& eventData) override;
+
+ virtual Return<Status> sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+ int32_t arg, const HidlCasData& eventData) override;
+
+ virtual Return<Status> provision(const hidl_string& provisionString) override;
+
+ virtual Return<Status> refreshEntitlements(int32_t refreshType,
+ const HidlCasData& refreshData) override;
+
+ virtual Return<Status> release() override;
+
+ private:
+ struct PluginHolder;
+ sp<SharedLibrary> mLibrary;
+ std::shared_ptr<CasPlugin> mPluginHolder;
+ sp<ICasListener> mListener;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp
new file mode 100644
index 0000000..36dc1a5
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl"
+
+#include <hidlmemory/mapping.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+using hidl::memory::V1_0::IMemory;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+#define CHECK_SUBSAMPLE_DEF(type) \
+ static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfClearData) == \
+ offsetof(type::SubSample, mNumBytesOfClearData), \
+ "SubSample: numBytesOfClearData offset doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \
+ offsetof(type::SubSample, mNumBytesOfEncryptedData), \
+ "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin)
+ : mLibrary(library), mPluginHolder(plugin) {
+ ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+ ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+ release();
+}
+
+Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->setMediaCasSession(sessionId));
+}
+
+Return<bool> DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) {
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return false;
+ }
+
+ return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+}
+
+static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
+ return isInRange<uint64_t, uint64_t>(0, size, offset, length);
+}
+
+Return<void> DescramblerImpl::descramble(ScramblingControl scramblingControl,
+ const hidl_vec<SubSample>& subSamples,
+ const SharedBuffer& srcBuffer, uint64_t srcOffset,
+ const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+ descramble_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
+ // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed
+ // but the mapped memory's actual size will be smaller than the reported size.
+ if (srcBuffer.heapBase.size() > SIZE_MAX) {
+ ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size());
+ android_errorWriteLog(0x534e4554, "79376389");
+ _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+ return Void();
+ }
+
+ sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
+
+ // Validate if the offset and size in the SharedBuffer is consistent with the
+ // mapped ashmem, since the offset and size is controlled by client.
+ if (srcMem == NULL) {
+ ALOGE("Failed to map src buffer.");
+ _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+ return Void();
+ }
+ if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) {
+ ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
+ srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
+ android_errorWriteLog(0x534e4554, "67962232");
+ _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+ return Void();
+ }
+
+ // use 64-bit here to catch bad subsample size that might be overflowing.
+ uint64_t totalBytesInSubSamples = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ totalBytesInSubSamples +=
+ (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData;
+ }
+ // Further validate if the specified srcOffset and requested total subsample size
+ // is consistent with the source shared buffer size.
+ if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid srcOffset and subsample size: "
+ "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+ srcOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+ return Void();
+ }
+
+ void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset;
+ void* dstPtr = NULL;
+ if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+ // When using shared memory, src buffer is also used as dst,
+ // we don't map it again here.
+ dstPtr = srcPtr;
+
+ // In this case the dst and src would be the same buffer, need to validate
+ // dstOffset against the buffer size too.
+ if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid dstOffset and subsample size: "
+ "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+ dstOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+ return Void();
+ }
+ } else {
+ native_handle_t* handle =
+ const_cast<native_handle_t*>(dstBuffer.secureMemory.getNativeHandle());
+ dstPtr = static_cast<void*>(handle);
+ }
+
+ // Get a local copy of the shared_ptr for the plugin. Note that before
+ // calling the HIDL callback, this shared_ptr must be manually reset,
+ // since the client side could proceed as soon as the callback is called
+ // without waiting for this method to go out of scope.
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
+ return Void();
+ }
+
+ // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
+ // to ensure structs are actually idential
+
+ int32_t result =
+ holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY,
+ (DescramblerPlugin::ScramblingControl)scramblingControl,
+ subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+ srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+ holder.reset();
+ _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
+ return Void();
+}
+
+Return<Status> DescramblerImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ std::shared_ptr<DescramblerPlugin> holder(nullptr);
+ std::atomic_store(&mPluginHolder, holder);
+
+ return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.2/default/DescramblerImpl.h b/cas/1.2/default/DescramblerImpl.h
new file mode 100644
index 0000000..011eace
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct DescramblerPlugin;
+using namespace hardware::cas::native::V1_0;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+
+class SharedLibrary;
+
+class DescramblerImpl : public IDescrambler {
+ public:
+ DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin);
+ virtual ~DescramblerImpl();
+
+ virtual Return<Status> setMediaCasSession(const HidlCasSessionId& sessionId) override;
+
+ virtual Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) override;
+
+ virtual Return<void> descramble(ScramblingControl scramblingControl,
+ const hidl_vec<SubSample>& subSamples,
+ const SharedBuffer& srcBuffer, uint64_t srcOffset,
+ const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+ descramble_cb _hidl_cb) override;
+
+ virtual Return<Status> release() override;
+
+ private:
+ sp<SharedLibrary> mLibrary;
+ std::shared_ptr<DescramblerPlugin> mPluginHolder;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
diff --git a/cas/1.2/default/FactoryLoader.h b/cas/1.2/default/FactoryLoader.h
new file mode 100644
index 0000000..7403f86
--- /dev/null
+++ b/cas/1.2/default/FactoryLoader.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+
+template <class T>
+class FactoryLoader {
+ public:
+ FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+ virtual ~FactoryLoader() { closeFactory(); }
+
+ bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
+ T** factory = NULL);
+
+ bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
+
+ private:
+ typedef T* (*CreateFactoryFunc)();
+
+ Mutex mMapLock;
+ T* mFactory;
+ const char* mCreateFactoryFuncName;
+ sp<SharedLibrary> mLibrary;
+ KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+ KeyedVector<String8, wp<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+ bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ sp<SharedLibrary>* library, T** factory);
+
+ bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
+
+ bool openFactory(const String8& path);
+ void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
+ T** factory) {
+ if (library != NULL) {
+ library->clear();
+ }
+ if (factory != NULL) {
+ *factory = NULL;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+ if (index >= 0) {
+ return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+ library, factory);
+ }
+
+ // no luck, have to search
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+ mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+ closedir(pDir);
+
+ return true;
+ }
+ }
+ }
+
+ closedir(pDir);
+
+ ALOGE("Failed to find plugin");
+ return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
+ ALOGI("enumeratePlugins");
+
+ results->clear();
+
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ queryPluginsFromPath(pluginPath, results);
+ }
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ sp<SharedLibrary>* library, T** factory) {
+ closeFactory();
+
+ if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+ closeFactory();
+ return false;
+ }
+
+ if (library != NULL) {
+ *library = mLibrary;
+ }
+ if (factory != NULL) {
+ *factory = mFactory;
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+ vector<HidlCasPluginDescriptor>* results) {
+ closeFactory();
+
+ vector<CasPluginDescriptor> descriptors;
+ if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+ closeFactory();
+ return false;
+ }
+
+ for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+ results->push_back(
+ HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = new SharedLibrary(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+ }
+
+ CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+ if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+ delete mFactory;
+ mFactory = NULL;
+ mLibrary.clear();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
diff --git a/cas/1.2/default/MediaCasService.cpp b/cas/1.2/default/MediaCasService.cpp
new file mode 100644
index 0000000..4ecd52b
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-MediaCasService"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class Wrapper : public V1_1::ICasListener {
+ public:
+ static sp<V1_1::ICasListener> wrap(sp<V1_0::ICasListener> impl) {
+ sp<V1_1::ICasListener> cast = V1_1::ICasListener::castFrom(impl);
+ if (cast == NULL) {
+ cast = new Wrapper(impl);
+ }
+ return cast;
+ }
+
+ virtual Return<void> onEvent(int32_t event, int32_t arg,
+ const hidl_vec<uint8_t>& data) override {
+ mImpl->onEvent(event, arg, data);
+ return Void();
+ }
+
+ virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /* sessionId */,
+ int32_t /* event */, int32_t /* arg */,
+ const hidl_vec<uint8_t>& /*data*/) override {
+ ALOGV("Do nothing on Session Event for cas@1.0 client in cas@1.1");
+ return Void();
+ }
+
+ private:
+ Wrapper(sp<V1_0::ICasListener> impl) : mImpl(impl){};
+ sp<V1_0::ICasListener> mImpl;
+};
+
+MediaCasService::MediaCasService()
+ : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+Return<void> MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ vector<HidlCasPluginDescriptor> results;
+ mCasLoader.enumeratePlugins(&results);
+
+ _hidl_cb(results);
+ return Void();
+}
+
+Return<bool> MediaCasService::isSystemIdSupported(int32_t CA_system_id) {
+ ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+ return mCasLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<V1_0::ICas>> MediaCasService::createPlugin(int32_t CA_system_id,
+ const sp<V1_0::ICasListener>& listener) {
+ ALOGV("%s:Use createPluginExt to create plugin in cas@1.1", __FUNCTION__);
+
+ sp<ICas> result;
+
+ sp<V1_1::ICasListener> listenerV1_1 = Wrapper::wrap(listener);
+
+ result = createPluginExt(CA_system_id, listenerV1_1);
+
+ return result;
+}
+
+Return<sp<ICas>> MediaCasService::createPluginExt(int32_t CA_system_id,
+ const sp<ICasListener>& listener) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+ if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+ sp<V1_2::ICas> result;
+
+ CasFactory* factory;
+ sp<SharedLibrary> library;
+ if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ CasPlugin* plugin = NULL;
+ sp<CasImpl> casImpl = new CasImpl(listener);
+ if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+ OK &&
+ plugin != NULL) {
+ casImpl->init(library, plugin);
+ result = casImpl;
+
+ sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(listener);
+ if (listenerV1_2 != NULL) {
+ casImpl->setPluginStatusUpdateCallback();
+ }
+ }
+ }
+
+ return result;
+}
+
+Return<bool> MediaCasService::isDescramblerSupported(int32_t CA_system_id) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ return mDescramblerLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<IDescramblerBase>> MediaCasService::createDescrambler(int32_t CA_system_id) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ sp<IDescrambler> result;
+
+ DescramblerFactory* factory;
+ sp<SharedLibrary> library;
+ if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ DescramblerPlugin* plugin = NULL;
+ if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+ result = new DescramblerImpl(library, plugin);
+ }
+ }
+
+ return result;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.2/default/MediaCasService.h b/cas/1.2/default/MediaCasService.h
new file mode 100644
index 0000000..01e11db
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+
+#include <android/hardware/cas/1.1/IMediaCasService.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+struct CasFactory;
+struct DescramblerFactory;
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using ::android::hardware::cas::V1_0::IDescramblerBase;
+
+class MediaCasService : public V1_2::IMediaCasService {
+ public:
+ MediaCasService();
+
+ virtual Return<void> enumeratePlugins(enumeratePlugins_cb _hidl_cb) override;
+
+ virtual Return<bool> isSystemIdSupported(int32_t CA_system_id) override;
+
+ virtual Return<sp<V1_0::ICas>> createPlugin(int32_t CA_system_id,
+ const sp<V1_0::ICasListener>& listener) override;
+
+ virtual Return<sp<ICas>> createPluginExt(int32_t CA_system_id,
+ const sp<ICasListener>& listener) override;
+
+ virtual Return<bool> isDescramblerSupported(int32_t CA_system_id) override;
+
+ virtual Return<sp<IDescramblerBase>> createDescrambler(int32_t CA_system_id) override;
+
+ private:
+ FactoryLoader<CasFactory> mCasLoader;
+ FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+ virtual ~MediaCasService();
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
diff --git a/cas/1.2/default/SharedLibrary.cpp b/cas/1.2/default/SharedLibrary.cpp
new file mode 100644
index 0000000..ffe4bb9
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+ mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+ if (mLibHandle != NULL) {
+ dlclose(mLibHandle);
+ mLibHandle = NULL;
+ }
+}
+
+bool SharedLibrary::operator!() const {
+ return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+ if (!mLibHandle) {
+ return NULL;
+ }
+ // Clear last error before we load the symbol again,
+ // in case the caller didn't retrieve it.
+ (void)dlerror();
+ return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+ const char* error = dlerror();
+ return error ? error : "No errors or unknown error";
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.2/default/SharedLibrary.h b/cas/1.2/default/SharedLibrary.h
new file mode 100644
index 0000000..b85f557
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class SharedLibrary : public RefBase {
+ public:
+ explicit SharedLibrary(const String8& path);
+ ~SharedLibrary();
+
+ bool operator!() const;
+ void* lookup(const char* symbol) const;
+ const char* lastError() const;
+
+ private:
+ void* mLibHandle;
+ DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
diff --git a/cas/1.2/default/TypeConvert.cpp b/cas/1.2/default/TypeConvert.cpp
new file mode 100644
index 0000000..c4bd0dd
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-TypeConvert"
+
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+ Status status;
+ switch (legacyStatus) {
+ case android::OK:
+ status = Status::OK;
+ break;
+ case android::ERROR_CAS_NO_LICENSE:
+ status = Status::ERROR_CAS_NO_LICENSE;
+ break;
+ case android::ERROR_CAS_LICENSE_EXPIRED:
+ status = Status::ERROR_CAS_LICENSE_EXPIRED;
+ break;
+ case android::ERROR_CAS_SESSION_NOT_OPENED:
+ status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+ break;
+ case android::ERROR_CAS_CANNOT_HANDLE:
+ status = Status::ERROR_CAS_CANNOT_HANDLE;
+ break;
+ case android::ERROR_CAS_TAMPER_DETECTED:
+ status = Status::ERROR_CAS_INVALID_STATE;
+ break;
+ case android::BAD_VALUE:
+ status = Status::BAD_VALUE;
+ break;
+ case android::ERROR_CAS_NOT_PROVISIONED:
+ status = Status::ERROR_CAS_NOT_PROVISIONED;
+ break;
+ case android::ERROR_CAS_RESOURCE_BUSY:
+ status = Status::ERROR_CAS_RESOURCE_BUSY;
+ break;
+ case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+ status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+ break;
+ case android::ERROR_CAS_DEVICE_REVOKED:
+ status = Status::ERROR_CAS_DEVICE_REVOKED;
+ break;
+ case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+ status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+ break;
+ case android::ERROR_CAS_DECRYPT:
+ status = Status::ERROR_CAS_DECRYPT;
+ break;
+ default:
+ ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+ status = Status::ERROR_CAS_UNKNOWN;
+ break;
+ }
+ return status;
+}
+
+V1_2::Status toStatus_1_2(status_t legacyStatus) {
+ V1_2::Status status = static_cast<V1_2::Status>(toStatus(legacyStatus));
+ if (status == V1_2::Status::ERROR_CAS_UNKNOWN) {
+ switch (legacyStatus) {
+ case android::ERROR_CAS_NEED_ACTIVATION:
+ status = V1_2::Status::ERROR_CAS_NEED_ACTIVATION;
+ break;
+ case android::ERROR_CAS_NEED_PAIRING:
+ status = V1_2::Status::ERROR_CAS_NEED_PAIRING;
+ break;
+ case android::ERROR_CAS_NO_CARD:
+ status = V1_2::Status::ERROR_CAS_NO_CARD;
+ break;
+ case android::ERROR_CAS_CARD_MUTE:
+ status = V1_2::Status::ERROR_CAS_CARD_MUTE;
+ break;
+ case android::ERROR_CAS_CARD_INVALID:
+ status = V1_2::Status::ERROR_CAS_CARD_INVALID;
+ break;
+ case android::ERROR_CAS_BLACKOUT:
+ status = V1_2::Status::ERROR_CAS_BLACKOUT;
+ break;
+ }
+ }
+ return status;
+}
+
+String8 sessionIdToString(const CasSessionId& sessionId) {
+ String8 result;
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ result.appendFormat("%02x ", sessionId[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.2/default/TypeConvert.h b/cas/1.2/default/TypeConvert.h
new file mode 100644
index 0000000..018f310
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <media/cas/CasAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::Status;
+
+Status toStatus(status_t legacyStatus);
+
+V1_2::Status toStatus_1_2(status_t legacyStatus);
+
+String8 sessionIdToString(const CasSessionId& sessionId);
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
new file mode 100644
index 0000000..1c75100
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -0,0 +1,11 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service-lazy
+ interface android.hardware.cas@1.0::IMediaCasService default
+ interface android.hardware.cas@1.1::IMediaCasService default
+ interface android.hardware.cas@1.2::IMediaCasService default
+ oneshot
+ disabled
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
similarity index 63%
copy from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
copy to cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
index 172aa21..9b36406 100644
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -1,10 +1,10 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.vibrator</name>
+ <name>android.hardware.cas</name>
<transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1.2</version>
<interface>
- <name>IVibrator</name>
+ <name>IMediaCasService</name>
<instance>default</instance>
</interface>
</hal>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
new file mode 100644
index 0000000..d1c853e
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -0,0 +1,6 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
similarity index 63%
copy from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
copy to cas/1.2/default/android.hardware.cas@1.2-service.xml
index 172aa21..9b36406 100644
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -1,10 +1,10 @@
<manifest version="1.0" type="device">
<hal format="hidl">
- <name>android.hardware.vibrator</name>
+ <name>android.hardware.cas</name>
<transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1.2</version>
<interface>
- <name>IVibrator</name>
+ <name>IMediaCasService</name>
<instance>default</instance>
</interface>
</hal>
diff --git a/cas/1.2/default/service.cpp b/cas/1.2/default/service.cpp
new file mode 100644
index 0000000..a623447
--- /dev/null
+++ b/cas/1.2/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.cas@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.cas@1.1-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "MediaCasService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::cas::V1_1::implementation::MediaCasService;
+using android::hardware::cas::V1_2::IMediaCasService;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+
+ // Setup hwbinder service
+ android::sp<IMediaCasService> service = new MediaCasService();
+ 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 cas service: %d", status);
+
+ joinRpcThreadpool();
+ return 0;
+}
diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal
new file mode 100644
index 0000000..40c06cf
--- /dev/null
+++ b/cas/1.2/types.hal
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas@1.2;
+
+import android.hardware.cas@1.0;
+import android.hardware.cas@1.1;
+
+enum Status : @1.0::Status {
+ /**
+ * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+ */
+ ERROR_CAS_NEED_ACTIVATION,
+ /**
+ * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+ */
+ ERROR_CAS_NEED_PAIRING,
+ /**
+ * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+ */
+ ERROR_CAS_NO_CARD,
+ /**
+ * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+ * descrambling.
+ */
+ ERROR_CAS_CARD_MUTE,
+ /**
+ * ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+ */
+ ERROR_CAS_CARD_INVALID,
+ /**
+ * ERROR_CAS_BLACKOUT is used to report geographical blackout.
+ */
+ ERROR_CAS_BLACKOUT,
+};
+
+/**
+ * The intented usage for the session.
+ */
+enum SessionIntent : uint32_t {
+ /**
+ * Live Stream.
+ */
+ LIVE,
+ /**
+ * Playback Recorded Stream.
+ */
+ PLAYBACK,
+ /**
+ * Record Live Stream.
+ */
+ RECORD,
+ /**
+ * View the content with Time Shift capability
+ */
+ TIMESHIFT,
+};
+
+/**
+ * The Scrambling Mode.
+ */
+enum ScramblingMode : uint32_t {
+ RESERVED = 0,
+ /**
+ * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+ * the default mode and shall be used when the scrambling descriptor
+ * is not present in the program map section. DVB scrambling mode is
+ * specified in ETSI EN 300 468 specification.
+ */
+ DVB_CSA1,
+ DVB_CSA2,
+ /**
+ * DVB-CSA3 in standard mode.
+ */
+ DVB_CSA3_STANDARD,
+ /**
+ * DVB-CSA3 in minimally enhanced mode.
+ */
+ DVB_CSA3_MINIMAL,
+ /**
+ * DVB-CSA3 in fully enhanced mode.
+ */
+ DVB_CSA3_ENHANCE,
+ /**
+ * DVB-CISSA version 1.
+ */
+ DVB_CISSA_V1,
+ /**
+ * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+ */
+ DVB_IDSA,
+ /**
+ * a symmetric key algorithm.
+ */
+ MULTI2,
+ /**
+ * Advanced Encryption System (AES) 128-bit Encryption mode.
+ */
+ AES128,
+ /**
+ * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+ */
+ AES_ECB,
+ /**
+ * Advanced Encryption System (AES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ AES_SCTE52,
+ /**
+ * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+ */
+ TDES_ECB,
+ /**
+ * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ TDES_SCTE52,
+ };
+
+/**
+ * The Event Type for status change.
+ */
+enum StatusEvent : uint8_t {
+ /**
+ * The status of CAS plugin was changed due to physical module insertion or
+ * removal. Client must call enumeratePlugins to update plugins' status.
+ */
+ PLUGIN_PHYSICAL_MODULE_CHANGED,
+ /**
+ * The status of supported session number was changed due to physical module
+ * insertion or removal. Client must update session resource according to
+ * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+ * sesssion by default.
+ */
+ PLUGIN_SESSION_NUMBER_CHANGED,
+};
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..9bc372c
--- /dev/null
+++ b/cas/1.2/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalCasV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalCasV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas@1.1",
+ "android.hardware.cas@1.2",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlallocatorutils",
+ "libhidlmemory",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ test_suites: ["general-tests"],
+}
+
diff --git a/cas/1.2/vts/functional/OWNERS b/cas/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..29246ed
--- /dev/null
+++ b/cas/1.2/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+nchalko@google.com
+chz@google.com
+quxiangfang@google.com
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
new file mode 100644
index 0000000..8439ceb
--- /dev/null
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -0,0 +1,619 @@
+/*
+ * 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 "mediacas_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/cas/1.0/IDescramblerBase.h>
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR \
+ "{ " \
+ " \"id\": 21140844, " \
+ " \"name\": \"Test Title\", " \
+ " \"lowercase_organization_name\": \"Android\", " \
+ " \"asset_key\": { " \
+ " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \
+ " }, " \
+ " \"cas_type\": 1, " \
+ " \"track_types\": [ ] " \
+ "} "
+
+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_string;
+using android::hardware::hidl_vec;
+using android::hardware::HidlMemory;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::cas::native::V1_0::BufferType;
+using android::hardware::cas::native::V1_0::DestinationBuffer;
+using android::hardware::cas::native::V1_0::IDescrambler;
+using android::hardware::cas::native::V1_0::ScramblingControl;
+using android::hardware::cas::native::V1_0::SharedBuffer;
+using android::hardware::cas::native::V1_0::SubSample;
+using android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using android::hardware::cas::V1_0::IDescramblerBase;
+using android::hardware::cas::V1_0::Status;
+using android::hardware::cas::V1_2::ICas;
+using android::hardware::cas::V1_2::ICasListener;
+using android::hardware::cas::V1_2::IMediaCasService;
+using android::hardware::cas::V1_2::ScramblingMode;
+using android::hardware::cas::V1_2::SessionIntent;
+using android::hardware::cas::V1_2::StatusEvent;
+
+namespace {
+
+const uint8_t kEcmBinaryBuffer[] = {
+ 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+ 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+ 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+ 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+ 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+ 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+ 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+ 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+ 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+ 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+ 0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+ 0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+ 0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+ 0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+ 0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+ 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+ 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+ 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+ 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+ 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+ 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+ 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+ 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+ 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+ 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+ 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+ 0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+ 0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+ 0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+ 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+ 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+ 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+ 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+ 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+ 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+ 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+ 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+ 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+ 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+ 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+ 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+ 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+ 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+ 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+ 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+ 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+ 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+ 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+ 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+ 0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public ICasListener {
+ public:
+ virtual Return<void> onEvent(int32_t event, int32_t arg,
+ const hidl_vec<uint8_t>& data) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return Void();
+ }
+
+ virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const hidl_vec<uint8_t>& data) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ mSessionId = sessionId;
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return Void();
+ }
+
+ virtual Return<void> onStatusUpdate(StatusEvent event, int32_t arg) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ mStatusEvent = event;
+ mEventArg = arg;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return Void();
+ }
+
+ void testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ hidl_vec<uint8_t>& eventData);
+
+ void testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+ int32_t& event, int32_t& eventArg, hidl_vec<uint8_t>& eventData);
+
+ void testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId, SessionIntent intent,
+ ScramblingMode mode);
+
+ private:
+ int32_t mEvent = -1;
+ int32_t mEventArg = -1;
+ StatusEvent mStatusEvent;
+ bool mEventReceived = false;
+ hidl_vec<uint8_t> mEventData;
+ hidl_vec<uint8_t> mSessionId;
+ android::Mutex mMsgLock;
+ android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ hidl_vec<uint8_t>& eventData) {
+ mEventReceived = false;
+ auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+ int32_t& event, int32_t& eventArg,
+ hidl_vec<uint8_t>& eventData) {
+ mEventReceived = false;
+ auto returnStatus = mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_TRUE(mSessionId == sessionId);
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode) {
+ mEventReceived = false;
+ android::hardware::cas::V1_2::Status sessionStatus;
+ auto returnVoid = mediaCas->openSession_1_2(
+ intent, mode,
+ [&](android::hardware::cas::V1_2::Status status, const hidl_vec<uint8_t>& id) {
+ sessionStatus = status;
+ *sessionId = id;
+ });
+ EXPECT_TRUE(returnVoid.isOk());
+ EXPECT_EQ(android::hardware::cas::V1_2::Status::OK, sessionStatus);
+
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "event not received within timeout";
+ return;
+ }
+ }
+ EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+ EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+// Test environment for Cas HIDL HAL.
+class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static CasHidlEnvironment* Instance() {
+ static CasHidlEnvironment* instance = new CasHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
+};
+
+class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
+ CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ ASSERT_NE(mService, nullptr);
+ }
+
+ sp<IMediaCasService> mService;
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<ICas> mMediaCas;
+ sp<IDescramblerBase> mDescramblerBase;
+ sp<MediaCasListener> mCasListener;
+ typedef struct _OobInputTestParams {
+ const SubSample* subSamples;
+ uint32_t numSubSamples;
+ size_t imemSizeActual;
+ uint64_t imemOffset;
+ uint64_t imemSize;
+ uint64_t srcOffset;
+ uint64_t dstOffset;
+ } OobInputTestParams;
+
+ ::testing::AssertionResult createCasPlugin(int32_t caSystemId);
+ ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId);
+ ::testing::AssertionResult openCasSession_1_2(std::vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode);
+ ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler,
+ Status* descrambleStatus,
+ sp<IMemory>* hidlInMemory);
+ ::testing::AssertionResult descrambleTestOobInput(const sp<IDescrambler>& descrambler,
+ Status* descrambleStatus,
+ const OobInputTestParams& params);
+};
+
+::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) {
+ auto status = mService->isSystemIdSupported(caSystemId);
+ if (!status.isOk() || !status) {
+ return ::testing::AssertionFailure();
+ }
+ status = mService->isDescramblerSupported(caSystemId);
+ if (!status.isOk() || !status) {
+ return ::testing::AssertionFailure();
+ }
+
+ mCasListener = new MediaCasListener();
+ auto pluginStatus = mService->createPluginExt(caSystemId, mCasListener);
+ if (!pluginStatus.isOk()) {
+ return ::testing::AssertionFailure();
+ }
+ mMediaCas = ICas::castFrom(pluginStatus);
+ if (mMediaCas == nullptr) {
+ return ::testing::AssertionFailure();
+ }
+
+ auto descramblerStatus = mService->createDescrambler(caSystemId);
+ if (!descramblerStatus.isOk()) {
+ return ::testing::AssertionFailure();
+ }
+ mDescramblerBase = descramblerStatus;
+ return ::testing::AssertionResult(mDescramblerBase != nullptr);
+}
+
+::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector<uint8_t>* sessionId) {
+ Status sessionStatus;
+ auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec<uint8_t>& id) {
+ sessionStatus = status;
+ *sessionId = id;
+ });
+ return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus));
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer(
+ const sp<IDescrambler>& descrambler, Status* descrambleStatus, sp<IMemory>* inMemory) {
+ hidl_vec<SubSample> hidlSubSamples;
+ hidlSubSamples.setToExternal(const_cast<SubSample*>(kSubSamples),
+ (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/);
+
+ sp<MemoryDealer> dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas");
+ if (nullptr == dealer.get()) {
+ ALOGE("couldn't get MemoryDealer!");
+ return ::testing::AssertionFailure();
+ }
+
+ sp<IMemory> mem = dealer->allocate(sizeof(kInBinaryBuffer));
+ if (nullptr == mem.get()) {
+ ALOGE("couldn't allocate IMemory!");
+ return ::testing::AssertionFailure();
+ }
+ *inMemory = mem;
+
+ // build HidlMemory from memory heap
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ if (nullptr == heap.get()) {
+ ALOGE("couldn't get memory heap!");
+ return ::testing::AssertionFailure();
+ }
+
+ uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
+ memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
+
+ // hidlMemory is not to be passed out of scope!
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+ SharedBuffer srcBuffer = {
+ .heapBase = *hidlMemory, .offset = (uint64_t)offset, .size = (uint64_t)size};
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.type = BufferType::SHARED_MEMORY;
+ dstBuffer.nonsecureMemory = srcBuffer;
+
+ uint32_t outBytes;
+ hidl_string detailedError;
+ auto returnVoid = descrambler->descramble(
+ ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0,
+ [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+ *descrambleStatus = status;
+ outBytes = bytesWritten;
+ detailedError = detailedErr;
+ });
+ if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+ ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+ returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+ }
+ return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput(
+ const sp<IDescrambler>& descrambler, Status* descrambleStatus,
+ const OobInputTestParams& params) {
+ hidl_vec<SubSample> hidlSubSamples;
+ hidlSubSamples.setToExternal(const_cast<SubSample*>(params.subSamples), params.numSubSamples,
+ false /*own*/);
+
+ sp<MemoryDealer> dealer = new MemoryDealer(params.imemSizeActual, "vts-cas");
+ if (nullptr == dealer.get()) {
+ ALOGE("couldn't get MemoryDealer!");
+ return ::testing::AssertionFailure();
+ }
+
+ sp<IMemory> mem = dealer->allocate(params.imemSizeActual);
+ if (nullptr == mem.get()) {
+ ALOGE("couldn't allocate IMemory!");
+ return ::testing::AssertionFailure();
+ }
+
+ // build HidlMemory from memory heap
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ if (nullptr == heap.get()) {
+ ALOGE("couldn't get memory heap!");
+ return ::testing::AssertionFailure();
+ }
+
+ // hidlMemory is not to be passed out of scope!
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+ SharedBuffer srcBuffer = {
+ .heapBase = *hidlMemory,
+ .offset = (uint64_t)offset + params.imemOffset,
+ .size = (uint64_t)params.imemSize,
+ };
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.type = BufferType::SHARED_MEMORY;
+ dstBuffer.nonsecureMemory = srcBuffer;
+
+ uint32_t outBytes;
+ hidl_string detailedError;
+ auto returnVoid = descrambler->descramble(
+ ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, params.srcOffset,
+ dstBuffer, params.dstOffset,
+ [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+ *descrambleStatus = status;
+ outBytes = bytesWritten;
+ detailedError = detailedErr;
+ });
+ if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+ ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+ returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+ }
+ return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+ description("Test that valid call sequences with SessionEvent send and receive");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR));
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ hidl_vec<uint8_t> hidlPvtData;
+ hidlPvtData.resize(256);
+ returnStatus = mMediaCas->setPrivateData(hidlPvtData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ std::vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId));
+ returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ std::vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSession(&streamSessionId));
+ returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ returnStatus = mDescramblerBase->setMediaCasSession(sessionId);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ hidl_vec<uint8_t> hidlNullPtr;
+ hidlNullPtr.setToExternal(static_cast<uint8_t*>(nullptr), 0);
+ returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ uint8_t refreshData[] = {0, 1, 2, 3};
+ hidl_vec<uint8_t> hidlRefreshData;
+ hidlRefreshData.setToExternal(static_cast<uint8_t*>(refreshData), sizeof(refreshData));
+ returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ int32_t eventID = 1;
+ int32_t eventArg = 2;
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlNullPtr);
+
+ eventID = 3;
+ eventArg = 4;
+ uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+ hidl_vec<uint8_t> hidlEventData;
+ hidlEventData.setToExternal(static_cast<uint8_t*>(eventData), sizeof(eventData));
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlEventData);
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+ mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+ uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+ hidl_vec<uint8_t> hidlClearKeyEmm;
+ hidlClearKeyEmm.setToExternal(static_cast<uint8_t*>(clearKeyEmmData), sizeof(clearKeyEmmData));
+ returnStatus = mMediaCas->processEmm(hidlClearKeyEmm);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ hidl_vec<uint8_t> hidlEcm;
+ hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer));
+ returnStatus = mMediaCas->processEcm(sessionId, hidlEcm);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+ returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm);
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc"));
+
+ sp<IDescrambler> descrambler;
+ descrambler = IDescrambler::castFrom(mDescramblerBase);
+ ASSERT_NE(descrambler, nullptr);
+
+ Status descrambleStatus = Status::OK;
+ sp<IMemory> dataMemory;
+
+ ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory));
+ EXPECT_EQ(Status::OK, descrambleStatus);
+
+ ASSERT_NE(nullptr, dataMemory.get());
+ uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
+
+ int compareResult =
+ memcmp(static_cast<const void*>(opBuffer),
+ static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
+ EXPECT_EQ(0, compareResult);
+
+ returnStatus = mDescramblerBase->release();
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+
+ returnStatus = mMediaCas->release();
+ EXPECT_TRUE(returnStatus.isOk());
+ EXPECT_EQ(Status::OK, returnStatus);
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ CasHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index a409650..541cfc6 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -10,6 +10,7 @@
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>5.0</version>
+ <version>6.0</version>
<interface>
<name>IDevicesFactory</name>
<instance>default</instance>
@@ -18,6 +19,7 @@
<hal format="hidl" optional="false">
<name>android.hardware.audio.effect</name>
<version>5.0</version>
+ <version>6.0</version>
<interface>
<name>IEffectsFactory</name>
<instance>default</instance>
@@ -221,7 +223,7 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.health</name>
- <version>2.0</version>
+ <version>2.1</version>
<interface>
<name>IHealth</name>
<instance>default</instance>
diff --git a/configstore/1.0/vts/functional/Android.bp b/configstore/1.0/vts/functional/Android.bp
index 008b59d..31d4b1c 100644
--- a/configstore/1.0/vts/functional/Android.bp
+++ b/configstore/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalConfigstoreV1_0TargetTest.cpp"],
static_libs: ["android.hardware.configstore@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
index 70b5830..8a1a313 100644
--- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
+++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
@@ -16,11 +16,12 @@
#define LOG_TAG "ConfigstoreHidlHalTest"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unistd.h>
using ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
@@ -35,25 +36,12 @@
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-// Test environment for Configstore HIDL HAL.
-class ConfigstoreHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ConfigstoreHidlEnvironment* Instance() {
- static ConfigstoreHidlEnvironment* instance = new ConfigstoreHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<ISurfaceFlingerConfigs>(); }
-};
-
-class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ConfigstoreHidlTest : public ::testing::TestWithParam<std::string> {
public:
sp<ISurfaceFlingerConfigs> sfConfigs;
virtual void SetUp() override {
- sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>(
- ConfigstoreHidlEnvironment::Instance()->getServiceName<ISurfaceFlingerConfigs>());
+ sfConfigs = ISurfaceFlingerConfigs::getService(GetParam());
ASSERT_NE(sfConfigs, nullptr);
}
@@ -63,7 +51,7 @@
/**
* Ensure all ISurfaceFlingerConfigs.hal function calls are successful.
*/
-TEST_F(ConfigstoreHidlTest, TestFunctionCalls) {
+TEST_P(ConfigstoreHidlTest, TestFunctionCalls) {
bool tmp;
Return<void> status = sfConfigs->vsyncEventPhaseOffsetNs(
@@ -118,7 +106,7 @@
/**
* Ensure repeated call to the same function returns the same result.
*/
-TEST_F(ConfigstoreHidlTest, TestSameReturnValue) {
+TEST_P(ConfigstoreHidlTest, TestSameReturnValue) {
int64_t original_ret;
Return<void> status = sfConfigs->vsyncEventPhaseOffsetNs(
[&original_ret](OptionalInt64 arg) { original_ret = arg.value; });
@@ -135,7 +123,7 @@
* Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
* are enforced.
*/
-TEST_F(ConfigstoreHidlTest, TestColorConstrainsBasic) {
+TEST_P(ConfigstoreHidlTest, TestColorConstrainsBasic) {
bool hasWideColorDisplay;
bool hasHDRDisplay;
@@ -152,11 +140,7 @@
}
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ConfigstoreHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ConfigstoreHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISurfaceFlingerConfigs::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/current.txt b/current.txt
index 4e0d0e0..3ccc531 100644
--- a/current.txt
+++ b/current.txt
@@ -589,12 +589,17 @@
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice
b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types
-04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi
-270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant
-dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
-91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types
-033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator
5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback
+033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
+3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
+0a7ff83fd0326b82232e1609da98f34960be11335df72fc407ad238d7bd0e081 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardware.wifi.supplicant@1.3::types
+41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types
+a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio
+a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
+15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse
+
diff --git a/dumpstate/1.0/vts/functional/Android.bp b/dumpstate/1.0/vts/functional/Android.bp
index fc64d05..3bac281 100644
--- a/dumpstate/1.0/vts/functional/Android.bp
+++ b/dumpstate/1.0/vts/functional/Android.bp
@@ -18,5 +18,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalDumpstateV1_0TargetTest.cpp"],
static_libs: ["android.hardware.dumpstate@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
index 57ebf2a..96b13c5 100644
--- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
+++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
@@ -21,32 +21,19 @@
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
#include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
using ::android::hardware::Return;
using ::android::sp;
-// Test environment for Dumpstate HIDL HAL.
-class DumpstateHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static DumpstateHidlEnvironment* Instance() {
- static DumpstateHidlEnvironment* instance = new DumpstateHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IDumpstateDevice>(); }
-};
-
-class DumpstateHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class DumpstateHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- dumpstate = ::testing::VtsHalHidlTargetTestBase::getService<IDumpstateDevice>(
- DumpstateHidlEnvironment::Instance()->getServiceName<IDumpstateDevice>());
+ dumpstate = IDumpstateDevice::getService(GetParam());
ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
}
@@ -54,14 +41,14 @@
};
// Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
-TEST_F(DumpstateHidlTest, TestNullHandle) {
+TEST_P(DumpstateHidlTest, TestNullHandle) {
Return<void> status = dumpstate->dumpstateBoard(nullptr);
ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
}
// Negative test: make sure dumpstateBoard() ignores a handle with no FD.
-TEST_F(DumpstateHidlTest, TestHandleWithNoFd) {
+TEST_P(DumpstateHidlTest, TestHandleWithNoFd) {
native_handle_t* handle = native_handle_create(0, 0);
ASSERT_NE(handle, nullptr) << "Could not create native_handle";
@@ -74,7 +61,7 @@
}
// Positive test: make sure dumpstateBoard() writes something to the FD.
-TEST_F(DumpstateHidlTest, TestOk) {
+TEST_P(DumpstateHidlTest, TestOk) {
// Index 0 corresponds to the read end of the pipe; 1 to the write end.
int fds[2];
ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -94,7 +81,7 @@
}
// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
-TEST_F(DumpstateHidlTest, TestHandleWithTwoFds) {
+TEST_P(DumpstateHidlTest, TestHandleWithTwoFds) {
int fds1[2];
int fds2[2];
ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
@@ -111,11 +98,7 @@
native_handle_close(handle);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(DumpstateHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- DumpstateHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, DumpstateHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
index 32c131c..7d1cacf 100644
--- a/gnss/1.0/default/Gnss.cpp
+++ b/gnss/1.0/default/Gnss.cpp
@@ -128,20 +128,20 @@
for (size_t i = 0; i < svStatus.numSvs; i++) {
auto svInfo = status->gnss_sv_list[i];
IGnssCallback::GnssSvInfo gnssSvInfo = {
- .svid = svInfo.svid,
- .constellation = static_cast<
- android::hardware::gnss::V1_0::GnssConstellationType>(
- svInfo.constellation),
- .cN0Dbhz = svInfo.c_n0_dbhz,
- .elevationDegrees = svInfo.elevation,
- .azimuthDegrees = svInfo.azimuth,
- // Older chipsets do not provide carrier frequency, hence
- // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
- // are not set. So we are resetting both fields here.
- .svFlag = static_cast<uint8_t>(
- svInfo.flags &= ~(static_cast<uint8_t>(
- IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
- .carrierFrequencyHz = 0};
+ .svid = svInfo.svid,
+ .constellation = static_cast<android::hardware::gnss::V1_0::GnssConstellationType>(
+ svInfo.constellation),
+ .cN0Dbhz = svInfo.c_n0_dbhz,
+ .elevationDegrees = svInfo.elevation,
+ .azimuthDegrees = svInfo.azimuth,
+ .carrierFrequencyHz = 0,
+ // Older chipsets do not provide carrier frequency, hence
+ // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
+ // are not set. So we are resetting both fields here.
+ .svFlag = static_cast<uint8_t>(
+ svInfo.flags &=
+ ~(static_cast<uint8_t>(IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
+ };
svStatus.gnssSvList[i] = gnssSvInfo;
}
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp
index 505cb41..d73b32e 100644
--- a/gnss/1.0/vts/functional/Android.bp
+++ b/gnss/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalGnssV1_0TargetTest.cpp"],
static_libs: ["android.hardware.gnss@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index c26f60a..1a80ecf 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -16,11 +16,11 @@
#define LOG_TAG "VtsHalGnssV1_0TargetTest"
#include <android/hardware/gnss/1.0/IGnss.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
#include <chrono>
#include <condition_variable>
#include <mutex>
@@ -42,23 +42,8 @@
bool sAgpsIsPresent = false; // if SUPL or XTRA assistance available
bool sSignalIsWeak = false; // if GNSS signals are weak (e.g. light indoor)
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+class GnssHalTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
// Clean between tests
@@ -67,8 +52,7 @@
info_called_count_ = 0;
notify_count_ = 0;
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
gnss_cb_ = new GnssCallback(*this);
@@ -344,14 +328,14 @@
* Since this is just the basic operation of SetUp() and TearDown(),
* the function definition is intentionally empty
*/
-TEST_F(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
+TEST_P(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
/*
* GetLocation:
* Turns on location, waits 45 second for at least 5 locations,
* and checks them for reasonable validity.
*/
-TEST_F(GnssHalTest, GetLocation) {
+TEST_P(GnssHalTest, GetLocation) {
#define MIN_INTERVAL_MSEC 500
#define PREFERRED_ACCURACY 0 // Ideally perfect (matches GnssLocationProvider)
#define PREFERRED_TIME_MSEC 0 // Ideally immediate
@@ -391,7 +375,7 @@
* InjectDelete:
* Ensures that calls to inject and/or delete information state are handled.
*/
-TEST_F(GnssHalTest, InjectDelete) {
+TEST_P(GnssHalTest, InjectDelete) {
// confidently, well north of Alaska
auto result = gnss_hal_->injectLocation(80.0, -170.0, 1000.0);
@@ -424,7 +408,7 @@
* null or actual extension, no crash.
* Confirms year-based required extensions (Measurement & Debug) are present
*/
-TEST_F(GnssHalTest, GetAllExtensions) {
+TEST_P(GnssHalTest, GetAllExtensions) {
// Basic call-is-handled checks
auto gnssXtra = gnss_hal_->getExtensionXtra();
ASSERT_TRUE(gnssXtra.isOk());
@@ -470,7 +454,7 @@
* MeasurementCapabilities:
* Verifies that modern hardware supports measurement capabilities.
*/
-TEST_F(GnssHalTest, MeasurementCapabilites) {
+TEST_P(GnssHalTest, MeasurementCapabilites) {
if (info_called_count_ > 0 && last_info_.yearOfHw >= 2016) {
EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS);
}
@@ -480,16 +464,19 @@
* SchedulingCapabilities:
* Verifies that 2018+ hardware supports Scheduling capabilities.
*/
-TEST_F(GnssHalTest, SchedulingCapabilities) {
+TEST_P(GnssHalTest, SchedulingCapabilities) {
if (info_called_count_ > 0 && last_info_.yearOfHw >= 2018) {
EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::SCHEDULING);
}
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
/*
* These arguments not used by automated VTS testing.
* Only for use in manual testing, when wanting to run
@@ -502,7 +489,6 @@
sSignalIsWeak = true;
}
}
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index cc34290..bdd02d2 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -30,5 +30,5 @@
shared_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index ca9eef4..4a0a7f9 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV1_1TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V1_1::IGnss;
+
+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/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 61a2ce4..2c8a7b1 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "GnssHalTest"
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <gnss_hal_test.h>
@@ -29,8 +31,7 @@
using ::android::hardware::gnss::common::Utils;
void GnssHalTest::SetUp() {
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index e4325bf..169cd62 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -19,8 +19,7 @@
#include <android/hardware/gnss/1.1/IGnss.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
#include "GnssCallbackEventQueue.h"
using android::hardware::Return;
@@ -37,24 +36,9 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 3294bcd..79da84a 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,9 +18,8 @@
#include <gnss_hal_test.h>
-#include <VtsHalHidlTargetTestBase.h>
-
#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <gtest/gtest.h>
using android::hardware::hidl_vec;
@@ -39,13 +38,13 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementCallback:
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+TEST_P(GnssHalTest, TestGnssMeasurementCallback) {
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
ASSERT_TRUE(gnssMeasurement_1_1.isOk());
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -65,7 +64,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -97,7 +96,6 @@
gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
const int location_called_count = gnss_cb_->location_cbq_.calledCount();
-
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
if ((i == 1) && (location_called_count == 2)) {
@@ -132,7 +130,8 @@
*/
IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+ const std::list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,
+ const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration::BlacklistedSource id;
@@ -218,7 +217,7 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -244,7 +243,7 @@
*/
const int kGnssSvStatusTimeout = 2;
- list<IGnssCallback::GnssSvStatus> sv_status_list;
+ std::list<IGnssCallback::GnssSvStatus> sv_status_list;
int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_status_cbq_size);
@@ -362,7 +361,7 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellation) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -457,7 +456,7 @@
*
* Ensure successfully injecting a location.
*/
-TEST_F(GnssHalTest, InjectBestLocation) {
+TEST_P(GnssHalTest, InjectBestLocation) {
StartAndCheckLocations(1);
GnssLocation gnssLocation = gnss_cb_->last_location_;
CheckLocation(gnssLocation, true);
@@ -476,7 +475,7 @@
* GnssDebugValuesSanityTest:
* Ensures that GnssDebug values make sense.
*/
-TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index 93de89c..1f95ff9 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -119,12 +119,13 @@
V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
.v1_1 = measurement_1_1,
.codeType = "C",
- .constellation = GnssConstellationType::GLONASS,
.state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
GnssMeasurementState::STATE_SUBFRAME_SYNC |
GnssMeasurementState::STATE_TOW_DECODED |
GnssMeasurementState::STATE_GLO_STRING_SYNC |
- GnssMeasurementState::STATE_GLO_TOD_DECODED};
+ GnssMeasurementState::STATE_GLO_TOD_DECODED,
+ .constellation = GnssConstellationType::GLONASS,
+ };
hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
measurements[0] = measurement_2_0;
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 278d87b..9aa1334 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -30,4 +30,5 @@
"android.hardware.gnss@2.0",
"android.hardware.gnss@common-vts-lib",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index ae36c50..2c74fa3 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV2_0TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V2_0::IGnss;
+
+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/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 14ae43c..8ca3f68 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -20,12 +20,13 @@
#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_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 7d07c0f..4f7b87a 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -17,11 +17,11 @@
#ifndef GNSS_HAL_TEST_H_
#define GNSS_HAL_TEST_H_
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android/hardware/gnss/2.0/IGnss.h>
#include "GnssCallbackEventQueue.h"
+#include <gtest/gtest.h>
+
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
@@ -45,24 +45,9 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index ca3edc5..c442cc6 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -16,10 +16,11 @@
#define LOG_TAG "GnssHalTestCases"
-#include <VtsHalHidlTargetTestBase.h>
#include <gnss_hal_test.h>
#include "Utils.h"
+#include <gtest/gtest.h>
+
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
@@ -51,13 +52,13 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementExtension:
* Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementExtension) {
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -80,7 +81,7 @@
* The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to
* the deprecation of some methods in @1.0::IGnssConfiguration interface.
*/
-TEST_F(GnssHalTest, TestGnssConfigurationExtension) {
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -96,7 +97,7 @@
* TestGnssConfiguration_setSuplEs_Deprecation:
* Calls setSuplEs and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -111,7 +112,7 @@
* TestGnssConfiguration_setGpsLock_Deprecation:
* Calls setGpsLock and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -130,7 +131,7 @@
* @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnssRil interface.
*/
-TEST_F(GnssHalTest, TestAGnssRilExtension) {
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil_2_0.isOk());
sp<IAGnssRil_2_0> iAGnssRil_2_0 = agnssRil_2_0;
@@ -148,7 +149,7 @@
* 1. Updates GNSS HAL that a network has connected.
* 2. Updates GNSS HAL that network has disconnected.
*/
-TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
+TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil.isOk());
sp<IAGnssRil_2_0> iAGnssRil = agnssRil;
@@ -180,7 +181,7 @@
* 2. constellation is valid.
* 3. state is valid.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementFields) {
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -234,7 +235,7 @@
* @2.0::IAGnss interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnss interface.
*/
-TEST_F(GnssHalTest, TestAGnssExtension) {
+TEST_P(GnssHalTest, TestAGnssExtension) {
auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0();
ASSERT_TRUE(agnss_2_0.isOk());
sp<IAGnss_2_0> iAGnss_2_0 = agnss_2_0;
@@ -258,7 +259,7 @@
* TestGnssNiExtension_Deprecation:
* Gets the @1.0::IGnssNi extension and verifies that it is a nullptr.
*/
-TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) {
+TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) {
// Verify IGnssNi 1.0 is not supported.
auto gnssNi = gnss_hal_->getExtensionGnssNi();
ASSERT_TRUE(!gnssNi.isOk() || ((sp<IGnssNi>)gnssNi) == nullptr);
@@ -269,7 +270,7 @@
* Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports
* the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) {
+TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl();
ASSERT_TRUE(gnssVisibilityControl.isOk());
sp<IGnssVisibilityControl> iGnssVisibilityControl = gnssVisibilityControl;
@@ -290,7 +291,7 @@
* capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
* capability flag is set.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -318,7 +319,7 @@
* If measurement corrections capability is supported, verifies that it supports the
* gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrections) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -348,7 +349,7 @@
* Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member
* elapsedRealitme are valid.
*/
-TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
+TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -383,7 +384,7 @@
iGnssMeasurement->close();
}
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
StartAndCheckFirstLocation();
ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
@@ -399,7 +400,7 @@
}
// This test only verify that injectBestLocation_2_0 does not crash.
-TEST_F(GnssHalTest, TestInjectBestLocation_2_0) {
+TEST_P(GnssHalTest, TestInjectBestLocation_2_0) {
StartAndCheckFirstLocation();
gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_);
StopAndClearLocations();
@@ -410,7 +411,7 @@
* Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support
* for this interface is optional.
*/
-TEST_F(GnssHalTest, TestGnssBatchingExtension) {
+TEST_P(GnssHalTest, TestGnssBatchingExtension) {
auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
ASSERT_TRUE(gnssBatching_2_0.isOk());
}
@@ -422,7 +423,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
return;
@@ -513,7 +514,7 @@
* or a source with constellation == UNKNOWN if none are found sufficient times
*/
IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+ const std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration_1_1::BlacklistedSource id;
@@ -599,7 +600,7 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
" not supported.");
@@ -626,7 +627,7 @@
*/
const int kGnssSvStatusTimeout = 2;
- list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+ std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_info_list_cbq_size);
@@ -744,7 +745,7 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellation) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
index b1d8ed4..3dc429b 100644
--- a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
+++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
@@ -53,7 +53,7 @@
* timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
* items retrieved which will be less than count.
*/
- int retrieve(list<T>& event_list, int count, int timeout_seconds);
+ int retrieve(std::list<T>& event_list, int count, int timeout_seconds);
/* Returns the number of events pending to be retrieved from the callback event queue. */
int size() const;
@@ -97,7 +97,7 @@
}
template <class T>
-int GnssCallbackEventQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
+int GnssCallbackEventQueue<T>::retrieve(std::list<T>& event_list, int count, int timeout_seconds) {
for (int i = 0; i < count; ++i) {
T event;
if (!retrieve(event, timeout_seconds)) {
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index d910169..e2f2670 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -26,12 +26,11 @@
using mapper::V2_1::IMapper;
using renderengine::DisplaySettings;
using renderengine::LayerSettings;
+using renderengine::RenderEngineCreationArgs;
-TestRenderEngine::TestRenderEngine(common::V1_1::PixelFormat hwcFormat,
- uint32_t renderEngineFeatures) {
- mFormat = hwcFormat;
- mRenderEngine = renderengine::RenderEngine::create(
- static_cast<int32_t>(mFormat), renderEngineFeatures, mMaxFrameBufferAcquireBuffers);
+TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) {
+ mFormat = static_cast<common::V1_1::PixelFormat>(args.pixelFormat);
+ mRenderEngine = renderengine::RenderEngine::create(args);
}
void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index 0ac5a22..b936cab 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -35,11 +35,14 @@
using mapper::V2_1::IMapper;
using renderengine::DisplaySettings;
+using renderengine::RenderEngineCreationArgs;
using vts::Gralloc;
class TestRenderEngine {
public:
- TestRenderEngine(common::V1_1::PixelFormat hwcFormat, uint32_t renderEngineFeatures);
+ static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2;
+
+ TestRenderEngine(const RenderEngineCreationArgs& args);
~TestRenderEngine() = default;
void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
@@ -51,7 +54,6 @@
void checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors);
private:
- static constexpr uint32_t mMaxFrameBufferAcquireBuffers = 2;
common::V1_1::PixelFormat mFormat;
std::vector<renderengine::LayerSettings> mCompositionLayers;
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index ade7a38..6a6f7de 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -103,9 +103,14 @@
ASSERT_NO_FATAL_FAILURE(
mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
- PixelFormat::RGBA_8888,
- renderengine::RenderEngine::USE_COLOR_MANAGEMENT |
- renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT)));
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
+ .setUseColorManagerment(true)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::HIGH)
+ .build())));
renderengine::DisplaySettings clientCompositionDisplay;
clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index f5df04b..85c7c81 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -202,6 +202,9 @@
* the buffer. If the bytesPerStride is unknown or variable, a value of -1
* should be returned.
*
+ * The locked buffer must adhere to the format requested at allocation time
+ * in the BufferDescriptorInfo.
+ *
* @param buffer Buffer to lock.
* @param cpuUsage CPU usage flags to request. See +ndk
* libnativewindow#AHardwareBuffer_UsageFlags for possible values.
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
index 1c455d3..3c5877e 100644
--- a/health/2.0/default/Android.bp
+++ b/health/2.0/default/Android.bp
@@ -31,7 +31,11 @@
vendor_available: true,
srcs: [
"Health.cpp",
- "healthd_common.cpp",
+ "healthd_common_adapter.cpp",
+ ],
+
+ whole_static_libs: [
+ "libhealthloop",
],
export_include_dirs: ["include"],
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index a2b81d1..4225fd8 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -17,11 +17,15 @@
#include <android-base/logging.h>
#include <android-base/file.h>
+#include <android/hardware/health/2.0/types.h>
#include <health2/Health.h>
#include <hal_conversion.h>
#include <hidl/HidlTransportSupport.h>
+using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+
extern void healthd_battery_update_internal(bool);
namespace android {
@@ -148,7 +152,16 @@
// Retrieve all information and call healthd_mode_ops->battery_update, which calls
// notifyListeners.
- bool chargerOnline = battery_monitor_->update();
+ battery_monitor_->updateValues();
+ const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();
+ struct BatteryProperties props;
+ convertFromHealthInfo(health_info, &props);
+ bool log = healthd_board_battery_update(&props);
+ if (log) {
+ battery_monitor_->logValues();
+ }
+ healthd_mode_ops->battery_update(&props);
+ bool chargerOnline = battery_monitor_->isChargerOnline();
// adjust uevent / wakealarm periods
healthd_battery_update_internal(chargerOnline);
@@ -246,10 +259,7 @@
using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
updateAndNotify(nullptr);
- struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
-
- V1_0::HealthInfo batteryInfo;
- convertToHealthInfo(&p, batteryInfo);
+ HealthInfo healthInfo = battery_monitor_->getHealthInfo_2_0();
std::vector<StorageInfo> info;
get_storage_info(info);
@@ -265,8 +275,6 @@
currentAvg = static_cast<int32_t>(prop.valueInt64);
}
- V2_0::HealthInfo healthInfo = {};
- healthInfo.legacy = std::move(batteryInfo);
healthInfo.batteryCurrentAverage = currentAvg;
healthInfo.diskStats = stats;
healthInfo.storageInfos = info;
diff --git a/health/2.0/default/healthd_common.cpp b/health/2.0/default/healthd_common.cpp
deleted file mode 100644
index b5fdc8e..0000000
--- a/health/2.0/default/healthd_common.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.health@2.0-impl"
-#define KLOG_LEVEL 6
-
-#include <healthd/BatteryMonitor.h>
-#include <healthd/healthd.h>
-
-#include <batteryservice/BatteryService.h>
-#include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <errno.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <utils/Errors.h>
-
-#include <health2/Health.h>
-
-using namespace android;
-
-// Periodic chores fast interval in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-// Periodic chores fast interval in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-
-static struct healthd_config healthd_config = {
- .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
- .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
- .batteryStatusPath = String8(String8::kEmptyString),
- .batteryHealthPath = String8(String8::kEmptyString),
- .batteryPresentPath = String8(String8::kEmptyString),
- .batteryCapacityPath = String8(String8::kEmptyString),
- .batteryVoltagePath = String8(String8::kEmptyString),
- .batteryTemperaturePath = String8(String8::kEmptyString),
- .batteryTechnologyPath = String8(String8::kEmptyString),
- .batteryCurrentNowPath = String8(String8::kEmptyString),
- .batteryCurrentAvgPath = String8(String8::kEmptyString),
- .batteryChargeCounterPath = String8(String8::kEmptyString),
- .batteryFullChargePath = String8(String8::kEmptyString),
- .batteryCycleCountPath = String8(String8::kEmptyString),
- .energyCounter = NULL,
- .boot_min_cap = 0,
- .screen_on = NULL,
-};
-
-static int eventct;
-static int epollfd;
-
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-using ::android::hardware::health::V2_0::implementation::Health;
-
-struct healthd_mode_ops* healthd_mode_ops = nullptr;
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
- struct epoll_event ev;
-
- ev.events = EPOLLIN;
-
- if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
-
- ev.data.ptr = (void*)handler;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
- return -1;
- }
-
- eventct++;
- return 0;
-}
-
-static void wakealarm_set_interval(int interval) {
- struct itimerspec itval;
-
- if (wakealarm_fd == -1) return;
-
- wakealarm_wake_interval = interval;
-
- if (interval == -1) interval = 0;
-
- itval.it_interval.tv_sec = interval;
- itval.it_interval.tv_nsec = 0;
- itval.it_value.tv_sec = interval;
- itval.it_value.tv_nsec = 0;
-
- if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
- KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-void healthd_battery_update_internal(bool charger_online) {
- // Fast wake interval when on charger (watch for overheat);
- // slow wake interval when on battery (watch for drained battery).
-
- int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
- : healthd_config.periodic_chores_interval_slow;
-
- if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
-
- // During awake periods poll at fast rate. If wake alarm is set at fast
- // rate then just use the alarm; if wake alarm is set at slow rate then
- // poll at fast rate while awake and let alarm wake up at slow rate when
- // asleep.
-
- if (healthd_config.periodic_chores_interval_fast == -1)
- awake_poll_interval = -1;
- else
- awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast
- ? -1
- : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-static void healthd_battery_update(void) {
- Health::getImplementation()->update();
-}
-
-static void periodic_chores() {
- healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
- char msg[UEVENT_MSG_LEN + 2];
- char* cp;
- int n;
-
- n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
- if (n <= 0) return;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- return;
-
- msg[n] = '\0';
- msg[n + 1] = '\0';
- cp = msg;
-
- while (*cp) {
- if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
- healthd_battery_update();
- break;
- }
-
- /* advance to after the next \0 */
- while (*cp++)
- ;
- }
-}
-
-static void uevent_init(void) {
- uevent_fd = uevent_open_socket(64 * 1024, true);
-
- if (uevent_fd < 0) {
- KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
- return;
- }
-
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
- if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
-}
-
-static void wakealarm_event(uint32_t /*epevents*/) {
- unsigned long long wakeups;
-
- if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
- return;
- }
-
- periodic_chores();
-}
-
-static void wakealarm_init(void) {
- wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
- if (wakealarm_fd == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
- return;
- }
-
- if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
-
- wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
- int nevents = 0;
- while (1) {
- struct epoll_event events[eventct];
- int timeout = awake_poll_interval;
- int mode_timeout;
-
- /* Don't wait for first timer timeout to run periodic chores */
- if (!nevents) periodic_chores();
-
- healthd_mode_ops->heartbeat();
-
- mode_timeout = healthd_mode_ops->preparetowait();
- if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
- nevents = epoll_wait(epollfd, events, eventct, timeout);
- if (nevents == -1) {
- if (errno == EINTR) continue;
- KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
- break;
- }
-
- for (int n = 0; n < nevents; ++n) {
- if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
- }
- }
-
- return;
-}
-
-static int healthd_init() {
- epollfd = epoll_create1(EPOLL_CLOEXEC);
- if (epollfd == -1) {
- KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
- return -1;
- }
-
- healthd_mode_ops->init(&healthd_config);
- wakealarm_init();
- uevent_init();
-
- return 0;
-}
-
-int healthd_main() {
- int ret;
-
- klog_set_level(KLOG_LEVEL);
-
- if (!healthd_mode_ops) {
- KLOG_ERROR("healthd ops not set, exiting\n");
- exit(1);
- }
-
- ret = healthd_init();
- if (ret) {
- KLOG_ERROR("Initialization failed, exiting\n");
- exit(2);
- }
-
- healthd_mainloop();
- KLOG_ERROR("Main loop terminated, exiting\n");
- return 3;
-}
diff --git a/health/2.0/default/healthd_common_adapter.cpp b/health/2.0/default/healthd_common_adapter.cpp
new file mode 100644
index 0000000..8fc689d
--- /dev/null
+++ b/health/2.0/default/healthd_common_adapter.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+// Support legacy functions in healthd/healthd.h using healthd_mode_ops.
+// New code should use HealthLoop directly instead.
+
+#include <memory>
+
+#include <cutils/klog.h>
+#include <health/HealthLoop.h>
+#include <health2/Health.h>
+#include <healthd/healthd.h>
+
+using android::hardware::health::HealthLoop;
+using android::hardware::health::V2_0::implementation::Health;
+
+struct healthd_mode_ops* healthd_mode_ops = nullptr;
+
+// Adapter of HealthLoop to use legacy healthd_mode_ops.
+class HealthLoopAdapter : public HealthLoop {
+ public:
+ // Expose internal functions, assuming clients calls them in the same thread
+ // where StartLoop is called.
+ int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
+ return HealthLoop::RegisterEvent(fd, func, wakeup);
+ }
+ void AdjustWakealarmPeriods(bool charger_online) {
+ return HealthLoop::AdjustWakealarmPeriods(charger_online);
+ }
+ protected:
+ void Init(healthd_config* config) override { healthd_mode_ops->init(config); }
+ void Heartbeat() override { healthd_mode_ops->heartbeat(); }
+ int PrepareToWait() override { return healthd_mode_ops->preparetowait(); }
+ void ScheduleBatteryUpdate() override { Health::getImplementation()->update(); }
+};
+static std::unique_ptr<HealthLoopAdapter> health_loop;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+ auto wrapped_handler = [handler](auto*, uint32_t epevents) { handler(epevents); };
+ return health_loop->RegisterEvent(fd, wrapped_handler, wakeup);
+}
+
+void healthd_battery_update_internal(bool charger_online) {
+ health_loop->AdjustWakealarmPeriods(charger_online);
+}
+
+int healthd_main() {
+ if (!healthd_mode_ops) {
+ KLOG_ERROR("healthd ops not set, exiting\n");
+ exit(1);
+ }
+
+ health_loop = std::make_unique<HealthLoopAdapter>();
+
+ int ret = health_loop->StartLoop();
+
+ // Should not reach here. The following will exit().
+ health_loop.reset();
+
+ return ret;
+}
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 74fe4fb..6e13a98 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -257,15 +257,21 @@
using V1_0::BatteryStatus;
using V1_0::BatteryHealth;
- if (!((health_info.legacy.batteryChargeCounter > 0) &&
- (health_info.legacy.batteryCurrent != INT32_MIN) &&
+ if (!((health_info.legacy.batteryCurrent != INT32_MIN) &&
(0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
- (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
return false;
}
+ if (health_info.legacy.batteryPresent) {
+ // If a battery is present, the battery status must be known.
+ if (!((health_info.legacy.batteryChargeCounter > 0) &&
+ (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN))) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/health/2.1/Android.bp b/health/2.1/Android.bp
new file mode 100644
index 0000000..254bfc0
--- /dev/null
+++ b/health/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.health@2.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IHealth.hal",
+ "IHealthInfoCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.health@1.0",
+ "android.hardware.health@2.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/health/2.1/IHealth.hal b/health/2.1/IHealth.hal
new file mode 100644
index 0000000..8a5152a
--- /dev/null
+++ b/health/2.1/IHealth.hal
@@ -0,0 +1,80 @@
+/*
+ * 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.health@2.1;
+
+import @2.0::IHealth;
+import @2.0::Result;
+import HealthConfig;
+import HealthInfo;
+import IHealthInfoCallback;
+
+/**
+ * IHealth manages health info and posts events on registered callbacks.
+ *
+ * An implementation of @2.1::IHealth must be able to handle both
+ * @2.0::IHealthInfoCallback and @2.1::IHealthInfoCallback.
+ * - When registerCallback() is called, an implementation must cast the callback
+ * to @2.1::IHealthInfoCallback.
+ * - If the cast is successful, when a health info broadcast is sent, the
+ * implementation must call
+ * @2.1::IHealthInfoCallback.healthInfoChanged_2_1(). All fields introduced
+ * in 2.1 must be set appropriately. The implementation must not call
+ * @2.0::IHealthInfoCallback.healthInfoChanged().
+ * - If the cast is unsuccessful, the implementation must call
+ * @2.0::IHealthInfoCallback.healthInfoChanged().
+ * - When unregisterCallback() is called, from then on, updates must not be sent
+ * through either healthInfoChanged_2_1() or healthInfoChanged().
+ *
+ * Passthrough implementations are not required to send health info to all
+ * callbacks periodically, but they must do so when update() is called.
+ * Binderized implementations must send health info to all callbacks
+ * periodically. The intervals between two notifications must be retrieved from
+ * the passthrough implementation through the getHealthConfig() function.
+ */
+interface IHealth extends @2.0::IHealth {
+ /**
+ * Get configuration of this HAL.
+ *
+ * @return result SUCCESS if successful,
+ * NOT_SUPPORTED if this API is not supported,
+ * UNKNOWN for other errors.
+ * @return config HAL configuration, to be ignored if result is not
+ * SUCCESS.
+ */
+ getHealthConfig() generates (Result result, HealthConfig config);
+
+ /**
+ * Get Health Information.
+ *
+ * @return result SUCCESS if successful,
+ * NOT_SUPPORTED if this API is not supported,
+ * UNKNOWN for other errors.
+ * @return value Health information, to be ignored if result is not
+ * SUCCESS.
+ */
+ getHealthInfo_2_1() generates (Result result, @2.1::HealthInfo value);
+
+ /**
+ * Return whether the screen should be kept on in charger mode.
+ *
+ * @return result SUCCESS if successful,
+ * NOT_SUPPORTED if this API is not supported,
+ * UNKNOWN for other errors.
+ * @return value whether screen should be kept on.
+ */
+ shouldKeepScreenOn() generates (Result result, bool value);
+};
diff --git a/health/2.1/IHealthInfoCallback.hal b/health/2.1/IHealthInfoCallback.hal
new file mode 100644
index 0000000..275f018
--- /dev/null
+++ b/health/2.1/IHealthInfoCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * 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.health@2.1;
+
+import @2.0::IHealthInfoCallback;
+
+/**
+ * IHealthInfoCallback is the updated callback interface to
+ * {@link IHealth.registerCallback}.
+ *
+ * A @2.1::IHealthInfoCallback must implement healthInfoChanged_2_1(). The
+ * inherited healthInfoChanged() function is never called when the HAL
+ * implementation post events. See documentation on @2.1::IHealth for details.
+ */
+interface IHealthInfoCallback extends @2.0::IHealthInfoCallback {
+ /**
+ * An implementation of IHealth must call healthInfoChanged on all
+ * registered callbacks after health info changes.
+ * @param info the updated HealthInfo
+ */
+ oneway healthInfoChanged_2_1(HealthInfo info);
+};
diff --git a/health/2.1/types.hal b/health/2.1/types.hal
new file mode 100644
index 0000000..efd8d6f
--- /dev/null
+++ b/health/2.1/types.hal
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.health@2.1;
+
+import @1.0::HealthConfig;
+import @2.0::HealthInfo;
+
+/**
+ * Battery capacity level. This enum provides additional information along side
+ * with the battery capacity.
+ * Clients of this HAL must use this value before inferring it from the
+ * battery capacity.
+ */
+enum BatteryCapacityLevel : int32_t {
+ /**
+ * Battery capacity level is unknown.
+ * Battery capacity level must be set to this value if and only if battery
+ * is not present.
+ */
+ UNKNOWN = 0,
+ /**
+ * Battery is at critical level. The Android framework must schedule a
+ * shutdown when it sees this value from the HAL.
+ */
+ CRITICAL,
+ /**
+ * Battery is low. The Android framework may limit the performance of
+ * the device when it sees this value from the HAL.
+ */
+ LOW,
+ /**
+ * Battery level is normal.
+ */
+ NORMAL,
+ /**
+ * Battery level is high.
+ */
+ HIGH,
+ /**
+ * Battery is full. It must be set to FULL if and only if battery level is
+ * 100.
+ */
+ FULL,
+};
+
+/**
+ * Combined Health Information.
+ */
+struct HealthInfo {
+ /**
+ * V2.0 HealthInfo.
+ * If a member is unsupported, it is filled with:
+ * - 0 (for integers);
+ * - false (for booleans);
+ * - empty string (for strings);
+ * - UNKNOWN (for BatteryStatus and BatteryHealth).
+ */
+ @2.0::HealthInfo legacy;
+
+ /**
+ * Battery capacity level. See BatteryCapacityLevel for more details.
+ */
+ BatteryCapacityLevel batteryCapacityLevel;
+
+ /**
+ * Estimated time to fully charge the device (in seconds).
+ * Value must be 0 if and only if batteryCapacityLevel is FULL or UNKNOWN.
+ * Otherwise, value must be positive.
+ */
+ int64_t batteryChargeTimeToFullNowSeconds;
+
+ /**
+ * Estimated battery full capacity (in microamp hours, uAh).
+ * Value must be 0 if unknown.
+ * Value must be positive if known, and must be between [50%, 120%] of
+ * batteryFullCharge (the designed capacity).
+ */
+ int32_t batteryFullCapacityUah;
+};
+
+/**
+ * Combined configuration of a health HAL implementation.
+ */
+struct HealthConfig {
+ /**
+ * 1.0 version of health config.
+ */
+ @1.0::HealthConfig battery;
+
+ /**
+ * Minimum battery level for charger to reboot into Android (in percent).
+ * Value should be in range [0, 100].
+ */
+ int32_t bootMinCap;
+};
diff --git a/health/2.1/vts/OWNERS b/health/2.1/vts/OWNERS
new file mode 100644
index 0000000..20450ba
--- /dev/null
+++ b/health/2.1/vts/OWNERS
@@ -0,0 +1,3 @@
+elsk@google.com
+hridya@google.com
+sspatil@google.com
diff --git a/health/2.1/vts/functional/Android.bp b/health/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..5aa873a
--- /dev/null
+++ b/health/2.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalHealthV2_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalHealthV2_1TargetTest.cpp"],
+ static_libs: [
+ "libgflags",
+ "libgmock",
+ "android.hardware.health@1.0",
+ "android.hardware.health@2.0",
+ "android.hardware.health@2.1",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
new file mode 100644
index 0000000..7df4926
--- /dev/null
+++ b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "health_hidl_hal_test"
+
+#include <mutex>
+#include <set>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/types.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <android/hardware/health/2.1/types.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::hardware::health::V1_0::BatteryStatus;
+using ::android::hardware::health::V2_0::Result;
+using ::testing::AnyOf;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using namespace std::chrono_literals;
+
+using ::android::hardware::health::V1_0::toString;
+using ::android::hardware::health::V2_0::toString;
+using ::android::hardware::health::V2_1::toString;
+
+// Return expr if it is evaluated to false.
+#define TEST_AND_RETURN(expr) \
+ do { \
+ auto res = (expr); \
+ if (!res) return res; \
+ } while (0)
+
+// Return a descriptive AssertionFailure() if expr is evaluated to false.
+#define TEST_AND_RETURN_FAILURE(expr) \
+ do { \
+ auto res = (expr); \
+ if (!res) { \
+ return AssertionFailure() << #expr " is false"; \
+ } \
+ } while (0)
+
+namespace android {
+namespace hardware {
+namespace health {
+
+namespace V2_0 {
+std::ostream& operator<<(std::ostream& os, const Result& res) {
+ return os << toString(res);
+}
+} // namespace V2_0
+
+namespace V2_1 {
+
+class HealthHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ service_ = IHealth::getService(GetParam());
+ ASSERT_NE(nullptr, service_.get()) << "Instance '" << GetParam() << "'' is not available.";
+ }
+
+ sp<IHealth> service_;
+};
+
+class CallbackBase {
+ public:
+ Return<void> healthInfoChangedInternal() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ invoked_ = true;
+ invoked_notify_.notify_all();
+ return Void();
+ }
+ template <typename R, typename P>
+ bool waitInvoke(std::chrono::duration<R, P> duration) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ bool r = invoked_notify_.wait_for(lock, duration, [this] { return this->invoked_; });
+ invoked_ = false;
+ return r;
+ }
+
+ private:
+ std::mutex mutex_;
+ std::condition_variable invoked_notify_;
+ bool invoked_ = false;
+};
+
+class Callback_2_0 : public android::hardware::health::V2_0::IHealthInfoCallback,
+ public CallbackBase {
+ Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
+ return healthInfoChangedInternal();
+ }
+};
+
+class Callback_2_1 : public android::hardware::health::V2_1::IHealthInfoCallback,
+ public CallbackBase {
+ Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
+ ADD_FAILURE() << "android::hardware::health::V2_1::IHealthInfoCallback::healthInfoChanged "
+ << "is called, but it shouldn't be";
+ return Void();
+ }
+ Return<void> healthInfoChanged_2_1(const HealthInfo&) override {
+ return healthInfoChangedInternal();
+ }
+};
+
+template <typename T>
+AssertionResult IsOk(const Return<T>& r) {
+ return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
+}
+
+// Both IsOk() and Result::SUCCESS
+AssertionResult ResultIsSuccess(const Return<Result>& r) {
+ if (!r.isOk()) {
+ return AssertionFailure() << r.description();
+ }
+ if (static_cast<Result>(r) != Result::SUCCESS) {
+ return AssertionFailure() << toString(static_cast<Result>(r));
+ }
+ return AssertionSuccess();
+}
+
+/**
+ * Test whether callbacks work. Tested functions are IHealth::registerCallback,
+ * unregisterCallback, and update.
+ */
+template <typename Callback>
+AssertionResult TestCallbacks(sp<IHealth> service) {
+ sp<Callback> first = new Callback();
+ sp<Callback> second = new Callback();
+
+ TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(first)));
+ TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(second)));
+
+ // registerCallback may or may not invoke the callback immediately, so the test needs
+ // to wait for the invocation. If the implementation chooses not to invoke the callback
+ // immediately, just wait for some time.
+ first->waitInvoke(200ms);
+ second->waitInvoke(200ms);
+
+ // assert that the first callback is invoked when update is called.
+ TEST_AND_RETURN(ResultIsSuccess(service->update()));
+
+ TEST_AND_RETURN_FAILURE(first->waitInvoke(1s));
+ TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
+
+ TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(first)));
+
+ // clear any potentially pending callbacks result from wakealarm / kernel events
+ // If there is none, just wait for some time.
+ first->waitInvoke(200ms);
+ second->waitInvoke(200ms);
+
+ // assert that the second callback is still invoked even though the first is unregistered.
+ TEST_AND_RETURN(ResultIsSuccess(service->update()));
+
+ TEST_AND_RETURN_FAILURE(!first->waitInvoke(200ms));
+ TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
+
+ TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(second)));
+ return AssertionSuccess();
+}
+
+TEST_P(HealthHidlTest, Callbacks_2_0) {
+ EXPECT_TRUE(TestCallbacks<Callback_2_0>(service_));
+}
+
+TEST_P(HealthHidlTest, Callbacks_2_1) {
+ EXPECT_TRUE(TestCallbacks<Callback_2_1>(service_));
+}
+
+template <typename Callback>
+AssertionResult TestUnregisterNonExistentCallback(sp<IHealth> service) {
+ sp<Callback> callback = new Callback();
+ auto ret = service->unregisterCallback(callback);
+ TEST_AND_RETURN(IsOk(ret));
+ if (static_cast<Result>(ret) != Result::NOT_FOUND) {
+ return AssertionFailure()
+ << "Unregistering non-existent callback should return NOT_FOUND, but returned "
+ << static_cast<Result>(ret);
+ }
+ return AssertionSuccess();
+}
+
+TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_0) {
+ EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_0>(service_));
+}
+
+TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_1) {
+ EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_1>(service_));
+}
+
+template <typename T>
+AssertionResult IsEnum(T value) {
+ for (auto it : hidl_enum_range<T>()) {
+ if (it == value) {
+ return AssertionSuccess();
+ }
+ }
+
+ return AssertionFailure() << static_cast<std::underlying_type_t<T>>(value) << " is not valid";
+}
+
+/*
+ * Tests the values returned by getHealthInfo() from interface IHealth.
+ */
+TEST_P(HealthHidlTest, getHealthInfo_2_1) {
+ EXPECT_TRUE(IsOk(service_->getHealthInfo_2_1([](auto result, const auto& value) {
+ if (result == Result::NOT_SUPPORTED) {
+ return;
+ }
+ ASSERT_EQ(Result::SUCCESS, result);
+ const auto& legacy = value.legacy.legacy;
+
+ EXPECT_TRUE(IsEnum(value.batteryCapacityLevel)) << " BatteryCapacityLevel";
+ EXPECT_GE(value.batteryChargeTimeToFullNowSeconds, 0);
+
+ EXPECT_GE(value.batteryFullCapacityUah, 0) << "batteryFullCapacityUah is unknown";
+ EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
+ EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
+ })));
+}
+
+TEST_P(HealthHidlTest, getHealthConfig) {
+ EXPECT_TRUE(IsOk(service_->getHealthConfig([](auto result, const auto&) {
+ EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
+ })));
+}
+
+TEST_P(HealthHidlTest, shouldKeepScreenOn) {
+ EXPECT_TRUE(IsOk(service_->shouldKeepScreenOn([](auto result, const auto&) {
+ EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
+ })));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ , HealthHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/health/utils/libhealthloop/Android.bp b/health/utils/libhealthloop/Android.bp
new file mode 100644
index 0000000..de0f24f
--- /dev/null
+++ b/health/utils/libhealthloop/Android.bp
@@ -0,0 +1,35 @@
+// 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: "libhealthloop",
+ vendor_available: true,
+ recovery_available: true,
+ srcs: [
+ "HealthLoop.cpp",
+ "utils.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libbase",
+ ],
+ header_libs: [
+ "libbatteryservice_headers",
+ "libhealthd_headers",
+ "libutils_headers",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
new file mode 100644
index 0000000..3f4b5bc
--- /dev/null
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "HealthLoop"
+#define KLOG_LEVEL 6
+
+#include <health/HealthLoop.h>
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <healthd/healthd.h>
+#include <utils/Errors.h>
+
+#include <health/utils.h>
+
+using namespace android;
+using namespace std::chrono_literals;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+namespace android {
+namespace hardware {
+namespace health {
+
+HealthLoop::HealthLoop() {
+ InitHealthdConfig(&healthd_config_);
+ awake_poll_interval_ = -1;
+ wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
+}
+
+HealthLoop::~HealthLoop() {
+ LOG(FATAL) << "HealthLoop cannot be destroyed";
+}
+
+int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
+ CHECK(!reject_event_register_);
+
+ auto* event_handler =
+ event_handlers_
+ .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
+ .get();
+
+ struct epoll_event ev;
+
+ ev.events = EPOLLIN;
+
+ if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
+
+ ev.data.ptr = reinterpret_cast<void*>(event_handler);
+
+ if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+void HealthLoop::WakeAlarmSetInterval(int interval) {
+ struct itimerspec itval;
+
+ if (wakealarm_fd_ == -1) return;
+
+ wakealarm_wake_interval_ = interval;
+
+ if (interval == -1) interval = 0;
+
+ itval.it_interval.tv_sec = interval;
+ itval.it_interval.tv_nsec = 0;
+ itval.it_value.tv_sec = interval;
+ itval.it_value.tv_nsec = 0;
+
+ if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
+ KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
+ // Fast wake interval when on charger (watch for overheat);
+ // slow wake interval when on battery (watch for drained battery).
+
+ int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
+ : healthd_config_.periodic_chores_interval_slow;
+
+ if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
+
+ // During awake periods poll at fast rate. If wake alarm is set at fast
+ // rate then just use the alarm; if wake alarm is set at slow rate then
+ // poll at fast rate while awake and let alarm wake up at slow rate when
+ // asleep.
+
+ if (healthd_config_.periodic_chores_interval_fast == -1)
+ awake_poll_interval_ = -1;
+ else
+ awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
+ ? -1
+ : healthd_config_.periodic_chores_interval_fast * 1000;
+}
+
+void HealthLoop::PeriodicChores() {
+ ScheduleBatteryUpdate();
+}
+
+// TODO(b/140330870): Use BPF instead.
+#define UEVENT_MSG_LEN 2048
+void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
+ // No need to lock because uevent_fd_ is guaranteed to be initialized.
+
+ char msg[UEVENT_MSG_LEN + 2];
+ char* cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
+ if (n <= 0) return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n + 1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+ ScheduleBatteryUpdate();
+ break;
+ }
+
+ /* advance to after the next \0 */
+ while (*cp++)
+ ;
+ }
+}
+
+void HealthLoop::UeventInit(void) {
+ uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
+
+ if (uevent_fd_ < 0) {
+ KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+ return;
+ }
+
+ fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
+ if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
+}
+
+void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
+ // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
+
+ unsigned long long wakeups;
+
+ if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+ return;
+ }
+
+ PeriodicChores();
+}
+
+void HealthLoop::WakeAlarmInit(void) {
+ wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
+ if (wakealarm_fd_ == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+ return;
+ }
+
+ if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
+
+ WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
+}
+
+void HealthLoop::MainLoop(void) {
+ int nevents = 0;
+ while (1) {
+ reject_event_register_ = true;
+ size_t eventct = event_handlers_.size();
+ struct epoll_event events[eventct];
+ int timeout = awake_poll_interval_;
+
+ int mode_timeout;
+
+ /* Don't wait for first timer timeout to run periodic chores */
+ if (!nevents) PeriodicChores();
+
+ Heartbeat();
+
+ mode_timeout = PrepareToWait();
+ if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
+ nevents = epoll_wait(epollfd_, events, eventct, timeout);
+ if (nevents == -1) {
+ if (errno == EINTR) continue;
+ KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr) {
+ auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
+ event_handler->func(event_handler->object, events[n].events);
+ }
+ }
+ }
+
+ return;
+}
+
+int HealthLoop::InitInternal() {
+ epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
+ if (epollfd_ == -1) {
+ KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ // Call subclass's init for any additional init steps.
+ // Note that healthd_config_ is initialized before wakealarm_fd_; see
+ // AdjustUeventWakealarmPeriods().
+ Init(&healthd_config_);
+
+ WakeAlarmInit();
+ UeventInit();
+
+ return 0;
+}
+
+int HealthLoop::StartLoop() {
+ int ret;
+
+ klog_set_level(KLOG_LEVEL);
+
+ ret = InitInternal();
+ if (ret) {
+ KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
+ return 2;
+ }
+
+ MainLoop();
+ KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
+ return 3;
+}
+
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealthloop/include/health/HealthLoop.h b/health/utils/libhealthloop/include/health/HealthLoop.h
new file mode 100644
index 0000000..693e6cb
--- /dev/null
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -0,0 +1,108 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <healthd/healthd.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+
+class HealthLoop {
+ public:
+ HealthLoop();
+
+ // Client is responsible for holding this forever. Process will exit
+ // when this is destroyed.
+ virtual ~HealthLoop();
+
+ // Initialize and start the main loop. This function does not exit unless
+ // the process is interrupted.
+ // Once the loop is started, event handlers are no longer allowed to be
+ // registered.
+ int StartLoop();
+
+ protected:
+ // healthd_mode_ops overrides. Note that healthd_mode_ops->battery_update
+ // is missing because it is only used by BatteryMonitor.
+ // Init is called right after epollfd_ is initialized (so RegisterEvent
+ // is allowed) but before other things are initialized (so SetChargerOnline
+ // is not allowed.)
+ virtual void Init(healthd_config* config) = 0;
+ virtual void Heartbeat() = 0;
+ virtual int PrepareToWait() = 0;
+
+ // Note that this is NOT healthd_mode_ops->battery_update(BatteryProperties*),
+ // which is called by BatteryMonitor after values are fetched. This is the
+ // implementation of healthd_battery_update(), which calls
+ // the correct IHealth::update(),
+ // which calls BatteryMonitor::update(), which calls
+ // healthd_mode_ops->battery_update(BatteryProperties*).
+ virtual void ScheduleBatteryUpdate() = 0;
+
+ // Register an epoll event. When there is an event, |func| will be
+ // called with |this| as the first argument and |epevents| as the second.
+ // This may be called in a different thread from where StartLoop is called
+ // (for obvious reasons; StartLoop never ends).
+ // Once the loop is started, event handlers are no longer allowed to be
+ // registered.
+ using BoundFunction = std::function<void(HealthLoop*, uint32_t /* epevents */)>;
+ int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup);
+
+ // Helper for implementing ScheduleBatteryUpdate(). An implementation of
+ // ScheduleBatteryUpdate should get charger_online from BatteryMonitor::update(),
+ // then reset wake alarm interval by calling AdjustWakealarmPeriods.
+ void AdjustWakealarmPeriods(bool charger_online);
+
+ private:
+ struct EventHandler {
+ HealthLoop* object = nullptr;
+ int fd;
+ BoundFunction func;
+ };
+
+ int InitInternal();
+ void MainLoop();
+ void WakeAlarmInit();
+ void WakeAlarmEvent(uint32_t);
+ void UeventInit();
+ void UeventEvent(uint32_t);
+ void WakeAlarmSetInterval(int interval);
+ void PeriodicChores();
+
+ // These are fixed after InitInternal() is called.
+ struct healthd_config healthd_config_;
+ android::base::unique_fd wakealarm_fd_;
+ android::base::unique_fd uevent_fd_;
+
+ android::base::unique_fd epollfd_;
+ std::vector<std::unique_ptr<EventHandler>> event_handlers_;
+ int awake_poll_interval_; // -1 for no epoll timeout
+ int wakealarm_wake_interval_;
+
+ // If set to true, future RegisterEvent() will be rejected. This is to ensure all
+ // events are registered before StartLoop().
+ bool reject_event_register_ = false;
+};
+
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealthloop/include/health/utils.h b/health/utils/libhealthloop/include/health/utils.h
new file mode 100644
index 0000000..e46771c
--- /dev/null
+++ b/health/utils/libhealthloop/include/health/utils.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <healthd/healthd.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+
+void InitHealthdConfig(struct healthd_config* healthd_config);
+
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp
new file mode 100644
index 0000000..b0d153f
--- /dev/null
+++ b/health/utils/libhealthloop/utils.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 <health/utils.h>
+namespace android {
+namespace hardware {
+namespace health {
+
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+
+void InitHealthdConfig(struct healthd_config* healthd_config) {
+ *healthd_config = {
+ .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+ .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+ .batteryStatusPath = String8(String8::kEmptyString),
+ .batteryHealthPath = String8(String8::kEmptyString),
+ .batteryPresentPath = String8(String8::kEmptyString),
+ .batteryCapacityPath = String8(String8::kEmptyString),
+ .batteryVoltagePath = String8(String8::kEmptyString),
+ .batteryTemperaturePath = String8(String8::kEmptyString),
+ .batteryTechnologyPath = String8(String8::kEmptyString),
+ .batteryCurrentNowPath = String8(String8::kEmptyString),
+ .batteryCurrentAvgPath = String8(String8::kEmptyString),
+ .batteryChargeCounterPath = String8(String8::kEmptyString),
+ .batteryFullChargePath = String8(String8::kEmptyString),
+ .batteryCycleCountPath = String8(String8::kEmptyString),
+ .energyCounter = NULL,
+ .boot_min_cap = 0,
+ .screen_on = NULL,
+ };
+}
+
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
index 376c12b..abfb2e0 100644
--- a/keymaster/4.0/vts/OWNERS
+++ b/keymaster/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
+jbires@google.com
jdanis@google.com
swillden@google.com
yim@google.com
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 0ac7e48..c5acf8c 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -4413,6 +4413,35 @@
}
/*
+ * AttestationTest.AttestationApplicationIDLengthProperlyEncoded
+ *
+ * Verifies that the Attestation Application ID software enforced tag has a proper length encoding.
+ * Some implementations break strict encoding rules by encoding a length between 127 and 256 in one
+ * byte. Proper DER encoding specifies that for lengths greather than 127, one byte should be used
+ * to specify how many following bytes will be used to encode the length.
+ */
+TEST_F(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
+ auto creation_time = std::chrono::system_clock::now();
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ const string app_id(143, 'a');
+ ASSERT_EQ(ErrorCode::OK,
+ AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id)),
+ &cert_chain));
+ EXPECT_GE(cert_chain.size(), 2U);
+
+ EXPECT_TRUE(verify_attestation_record("challenge", app_id, //
+ key_characteristics_.softwareEnforced, //
+ key_characteristics_.hardwareEnforced, //
+ SecLevel(), cert_chain[0], creation_time));
+}
+/*
* AttestationTest.AesAttestation
*
* Verifies that attesting to AES keys fails in the expected way.
diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp
index d682e0b..9e5cf6d 100644
--- a/memtrack/1.0/vts/functional/Android.bp
+++ b/memtrack/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"],
static_libs: ["android.hardware.memtrack@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
index 691ecca..cccedca 100644
--- a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
+++ b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
@@ -20,8 +20,9 @@
#include <android/hardware/memtrack/1.0/IMemtrack.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <fcntl.h>
#include <algorithm>
@@ -39,23 +40,10 @@
using std::vector;
using std::count_if;
-// Test environment for Memtrack HIDL HAL.
-class MemtrackHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static MemtrackHidlEnvironment* Instance() {
- static MemtrackHidlEnvironment* instance = new MemtrackHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMemtrack>(); }
-};
-
-class MemtrackHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MemtrackHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- memtrack = ::testing::VtsHalHidlTargetTestBase::getService<IMemtrack>(
- MemtrackHidlEnvironment::Instance()->getServiceName<IMemtrack>());
+ memtrack = IMemtrack::getService(GetParam());
ASSERT_NE(memtrack, nullptr);
}
@@ -93,7 +81,7 @@
/* Sanity check results when getMemory() is passed a negative PID
*/
-TEST_F(MemtrackHidlTest, BadPidTest) {
+TEST_P(MemtrackHidlTest, BadPidTest) {
MemtrackStatus s;
hidl_vec<MemtrackRecord> v;
auto cb = generate_cb(&s, &v);
@@ -108,7 +96,7 @@
/* Sanity check results when getMemory() is passed a bad memory usage type
*/
-TEST_F(MemtrackHidlTest, BadTypeTest) {
+TEST_P(MemtrackHidlTest, BadTypeTest) {
MemtrackStatus s;
hidl_vec<MemtrackRecord> v;
auto cb = generate_cb(&s, &v);
@@ -121,7 +109,7 @@
* for all memory types, including valid flag combinations for every
* MemtrackRecord returned.
*/
-TEST_F(MemtrackHidlTest, GetMemoryTest) {
+TEST_P(MemtrackHidlTest, GetMemoryTest) {
/* Opening this device causes the kernel to provide memtrack with memory
* info for this process.
*/
@@ -172,11 +160,7 @@
static_cast<uint32_t>(MemtrackType::NUM_TYPES));
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(MemtrackHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- MemtrackHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MemtrackHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMemtrack::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/nfc/1.0/vts/functional/Android.bp b/nfc/1.0/vts/functional/Android.bp
index c2e365e..40b82bb 100644
--- a/nfc/1.0/vts/functional/Android.bp
+++ b/nfc/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
static_libs: [
"android.hardware.nfc@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/nfc/1.0/vts/functional/AndroidTest.xml b/nfc/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..364672b
--- /dev/null
+++ b/nfc/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalNfcV1_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalNfcV1_0TargetTest->/data/local/tmp/VtsHalNfcV1_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalNfcV1_0TargetTest" />
+ <option name="native-test-timeout" value="180000"/>
+ </test>
+</configuration>
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index e17c961..1feae9d 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -20,11 +20,12 @@
#include <android/hardware/nfc/1.0/INfc.h>
#include <android/hardware/nfc/1.0/INfcClientCallback.h>
#include <android/hardware/nfc/1.0/types.h>
+#include <gtest/gtest.h>
#include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::nfc::V1_0::INfc;
using ::android::hardware::nfc::V1_0::INfcClientCallback;
@@ -94,26 +95,11 @@
};
};
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static NfcHidlEnvironment* Instance() {
- static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<INfc>(); }
- private:
- NfcHidlEnvironment() {}
-};
-
// The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>(
- NfcHidlEnvironment::Instance()->getServiceName<INfc>());
+ nfc_ = INfc::getService(GetParam());
ASSERT_NE(nfc_, nullptr);
nfc_cb_ = new NfcClientCallback();
@@ -186,7 +172,7 @@
* Since open and close calls are a part of SetUp() and TearDown(),
* the function definition is intentionally kept empty
*/
-TEST_F(NfcHidlTest, OpenAndClose) {}
+TEST_P(NfcHidlTest, OpenAndClose) {}
/*
* WriteCoreReset:
@@ -194,7 +180,7 @@
* Waits for CORE_RESET_RSP
* Checks the status, version number and configuration status
*/
-TEST_F(NfcHidlTest, WriteCoreReset) {
+TEST_P(NfcHidlTest, WriteCoreReset) {
std::vector<uint8_t> cmd = CORE_RESET_CMD;
NfcData data = cmd;
EXPECT_EQ(data.size(), nfc_->write(data));
@@ -229,7 +215,7 @@
* Waits for CORE_RESET_RSP
* Checks the status, version number and configuration status
*/
-TEST_F(NfcHidlTest, WriteCoreResetConfigReset) {
+TEST_P(NfcHidlTest, WriteCoreResetConfigReset) {
std::vector<uint8_t> cmd = CORE_RESET_CMD_CONFIG_RESET;
NfcData data = cmd;
EXPECT_EQ(data.size(), nfc_->write(data));
@@ -264,7 +250,7 @@
* Waits for response
* Checks SYNTAX_ERROR status
*/
-TEST_F(NfcHidlTest, WriteInvalidCommand) {
+TEST_P(NfcHidlTest, WriteInvalidCommand) {
// Send an Error Command
std::vector<uint8_t> cmd = INVALID_COMMAND;
NfcData data = cmd;
@@ -285,7 +271,7 @@
* Send CORE_CONN_CREATE_CMD for loop-back mode
* Check the response
*/
-TEST_F(NfcHidlTest, WriteInvalidAndThenValidCommand) {
+TEST_P(NfcHidlTest, WriteInvalidAndThenValidCommand) {
std::vector<uint8_t> cmd = CORE_RESET_CMD;
NfcData data = cmd;
EXPECT_EQ(data.size(), nfc_->write(data));
@@ -349,7 +335,7 @@
* Checks the data received
* Repeat to send total of 1Mb data
*/
-TEST_F(NfcHidlTest, Bandwidth) {
+TEST_P(NfcHidlTest, Bandwidth) {
std::vector<uint8_t> cmd = CORE_RESET_CMD;
NfcData data = cmd;
EXPECT_EQ(data.size(), nfc_->write(data));
@@ -437,7 +423,7 @@
* Waits for NfcEvent.OPEN_CPLT
* Checks status
*/
-TEST_F(NfcHidlTest, PowerCycle) {
+TEST_P(NfcHidlTest, PowerCycle) {
EXPECT_EQ(NfcStatus::OK, nfc_->powerCycle());
// Wait for NfcEvent.OPEN_CPLT
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -451,7 +437,7 @@
* Calls powerCycle() after close()
* Checks status
*/
-TEST_F(NfcHidlTest, PowerCycleAfterClose) {
+TEST_P(NfcHidlTest, PowerCycleAfterClose) {
EXPECT_EQ(NfcStatus::OK, nfc_->close());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -474,7 +460,7 @@
* Calls coreInitialized() with different data
* Waits for NfcEvent.POST_INIT_CPLT
*/
-TEST_F(NfcHidlTest, CoreInitialized) {
+TEST_P(NfcHidlTest, CoreInitialized) {
NfcData data;
data.resize(1);
// These parameters might lead to device specific proprietary behavior
@@ -501,7 +487,7 @@
* Calls controlGranted()
* Checks the return value
*/
-TEST_F(NfcHidlTest, ControlGranted) {
+TEST_P(NfcHidlTest, ControlGranted) {
EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
}
@@ -510,7 +496,7 @@
* Call controlGranted() after close
* Checks the return value
*/
-TEST_F(NfcHidlTest, ControlGrantedAfterClose) {
+TEST_P(NfcHidlTest, ControlGrantedAfterClose) {
EXPECT_EQ(NfcStatus::OK, nfc_->close());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -532,7 +518,7 @@
* Calls prediscover()
* Checks the return value
*/
-TEST_F(NfcHidlTest, PreDiscover) {
+TEST_P(NfcHidlTest, PreDiscover) {
EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
}
@@ -541,7 +527,7 @@
* Call prediscover() after close
* Checks the return value
*/
-TEST_F(NfcHidlTest, PreDiscoverAfterClose) {
+TEST_P(NfcHidlTest, PreDiscoverAfterClose) {
EXPECT_EQ(NfcStatus::OK, nfc_->close());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -564,7 +550,7 @@
* Calls close() multiple times
* Checks status
*/
-TEST_F(NfcHidlTest, CloseAfterClose) {
+TEST_P(NfcHidlTest, CloseAfterClose) {
EXPECT_EQ(NfcStatus::OK, nfc_->close());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -587,15 +573,18 @@
* Calls open() multiple times
* Checks status
*/
-TEST_F(NfcHidlTest, OpenAfterOpen) {
+TEST_P(NfcHidlTest, OpenAfterOpen) {
EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, NfcHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- NfcHidlEnvironment::Instance()->init(&argc, argv);
std::system("svc nfc disable"); /* Turn off NFC */
sleep(5);
diff --git a/nfc/1.1/vts/functional/Android.bp b/nfc/1.1/vts/functional/Android.bp
index 6698c5a..8da0ce3 100644
--- a/nfc/1.1/vts/functional/Android.bp
+++ b/nfc/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
"android.hardware.nfc@1.0",
"android.hardware.nfc@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
index 0b7c88b..13537e4 100644
--- a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
+++ b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
@@ -21,11 +21,12 @@
#include <android/hardware/nfc/1.1/INfc.h>
#include <android/hardware/nfc/1.1/INfcClientCallback.h>
#include <android/hardware/nfc/1.1/types.h>
+#include <gtest/gtest.h>
#include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::nfc::V1_1::INfc;
using ::android::hardware::nfc::V1_1::INfcClientCallback;
@@ -83,25 +84,11 @@
};
};
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static NfcHidlEnvironment* Instance() {
- static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<INfc>(); }
- private:
- NfcHidlEnvironment() {}
-};
-
// The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+ nfc_ = INfc::getService(GetParam());
ASSERT_NE(nfc_, nullptr);
nfc_cb_ = new NfcClientCallback();
@@ -151,7 +138,7 @@
* calls factoryReset()
* checks status
*/
-TEST_F(NfcHidlTest, FactoryReset) {
+TEST_P(NfcHidlTest, FactoryReset) {
nfc_->factoryReset();
EXPECT_EQ(NfcStatus::OK, nfc_->close());
@@ -174,7 +161,7 @@
* Makes an open call, waits for NfcEvent.OPEN_CPLT
* Immediately calls closeforPowerOffCase() and waits for NfcEvent.CLOSE_CPLT
*/
-TEST_F(NfcHidlTest, OpenAndCloseForPowerOff) {
+TEST_P(NfcHidlTest, OpenAndCloseForPowerOff) {
EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -195,7 +182,7 @@
* Calls closeForPowerOffCase()
* Calls close() - checks failed status
*/
-TEST_F(NfcHidlTest, CloseForPowerCaseOffAfterClose) {
+TEST_P(NfcHidlTest, CloseForPowerCaseOffAfterClose) {
EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
// Wait for CLOSE_CPLT event
auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -218,16 +205,19 @@
* Calls getConfig()
* checks if fields in NfcConfig are populated correctly
*/
-TEST_F(NfcHidlTest, GetConfig) {
+TEST_P(NfcHidlTest, GetConfig) {
nfc_->getConfig([](NfcConfig config) {
EXPECT_GE(config.maxIsoDepTransceiveLength, MIN_ISO_DEP_TRANSCEIVE_LENGTH);
});
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, NfcHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- NfcHidlEnvironment::Instance()->init(&argc, argv);
std::system("svc nfc disable"); /* Turn off NFC */
sleep(5);
diff --git a/nfc/1.2/vts/functional/Android.bp b/nfc/1.2/vts/functional/Android.bp
index 13b254c..7b50a36 100644
--- a/nfc/1.2/vts/functional/Android.bp
+++ b/nfc/1.2/vts/functional/Android.bp
@@ -23,4 +23,5 @@
"android.hardware.nfc@1.1",
"android.hardware.nfc@1.2",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp b/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
index 54d3127..3ec088d 100644
--- a/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
+++ b/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
@@ -20,11 +20,12 @@
#include <android/hardware/nfc/1.1/INfcClientCallback.h>
#include <android/hardware/nfc/1.2/INfc.h>
#include <android/hardware/nfc/1.2/types.h>
+#include <gtest/gtest.h>
#include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::sp;
using ::android::hardware::hidl_vec;
@@ -83,26 +84,11 @@
};
};
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static NfcHidlEnvironment* Instance() {
- static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<INfc>(); }
-
- private:
- NfcHidlEnvironment() {}
-};
-
// The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+ nfc_ = INfc::getService(GetParam());
ASSERT_NE(nfc_, nullptr);
nfc_cb_ = new NfcClientCallback();
@@ -152,7 +138,7 @@
* Calls getConfig()
* checks if fields in NfcConfig are populated correctly
*/
-TEST_F(NfcHidlTest, GetExtendedConfig) {
+TEST_P(NfcHidlTest, GetExtendedConfig) {
nfc_->getConfig_1_2([](NfcConfig config) {
for (uint8_t uicc : config.offHostRouteUicc) {
EXPECT_GE(uicc, MIN_OFFHOST_ROUTE_ID);
@@ -169,10 +155,13 @@
});
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, NfcHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- NfcHidlEnvironment::Instance()->init(&argc, argv);
std::system("svc nfc disable"); /* Turn off NFC */
sleep(5);
diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp
index a716f02..5d5676d 100644
--- a/power/1.0/vts/functional/Android.bp
+++ b/power/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalPowerV1_0TargetTest.cpp"],
static_libs: ["android.hardware.power@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
index 999b2b4..ba08ee7 100644
--- a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
+++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
@@ -21,9 +21,9 @@
#include <android-base/unique_fd.h>
#include <android/hardware/power/1.0/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <fcntl.h>
#include <algorithm>
@@ -45,23 +45,10 @@
#define AVAILABLE_GOVERNORS_PATH \
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors"
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static PowerHidlEnvironment* Instance() {
- static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
- PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+ power = IPower::getService(GetParam());
ASSERT_NE(power, nullptr);
}
@@ -71,7 +58,7 @@
};
// Sanity check Power::setInteractive.
-TEST_F(PowerHidlTest, SetInteractive) {
+TEST_P(PowerHidlTest, SetInteractive) {
Return<void> ret;
ret = power->setInteractive(true);
@@ -83,7 +70,7 @@
// Test Power::setInteractive and Power::powerHint(Launch)
// with each available CPU governor, if available
-TEST_F(PowerHidlTest, TryDifferentGovernors) {
+TEST_P(PowerHidlTest, TryDifferentGovernors) {
Return<void> ret;
unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR));
@@ -125,7 +112,7 @@
}
// Sanity check Power::powerHint on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHint) {
+TEST_P(PowerHidlTest, PowerHint) {
PowerHint badHint = static_cast<PowerHint>(0xA);
auto hints = {PowerHint::VSYNC, PowerHint::INTERACTION,
PowerHint::VIDEO_ENCODE, PowerHint::VIDEO_DECODE,
@@ -163,7 +150,7 @@
}
// Sanity check Power::setFeature() on good and bad inputs.
-TEST_F(PowerHidlTest, SetFeature) {
+TEST_P(PowerHidlTest, SetFeature) {
Return<void> ret;
ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, true);
ASSERT_TRUE(ret.isOk());
@@ -178,7 +165,7 @@
}
// Sanity check Power::getPlatformLowPowerStats().
-TEST_F(PowerHidlTest, GetPlatformLowPowerStats) {
+TEST_P(PowerHidlTest, GetPlatformLowPowerStats) {
hidl_vec<PowerStatePlatformSleepState> vec;
Status s;
auto cb = [&vec, &s](hidl_vec<PowerStatePlatformSleepState> states,
@@ -191,11 +178,7 @@
ASSERT_TRUE(s == Status::SUCCESS || s == Status::FILESYSTEM_ERROR);
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- PowerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, PowerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/power/1.1/vts/functional/Android.bp b/power/1.1/vts/functional/Android.bp
index de75984..d9a32df 100644
--- a/power/1.1/vts/functional/Android.bp
+++ b/power/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
"android.hardware.power@1.0",
"android.hardware.power@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp b/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
index 4427b15..e9a722c 100644
--- a/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
+++ b/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "power_hidl_hal_test"
#include <android-base/logging.h>
#include <android/hardware/power/1.1/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::hardware::power::V1_1::IPower;
using ::android::hardware::power::V1_1::PowerStateSubsystem;
@@ -29,23 +29,10 @@
using ::android::hardware::Return;
using ::android::sp;
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static PowerHidlEnvironment* Instance() {
- static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
- PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+ power = IPower::getService(GetParam());
ASSERT_NE(power, nullptr);
}
@@ -55,7 +42,7 @@
};
// Sanity check Power::getSubsystemLowPowerStats().
-TEST_F(PowerHidlTest, GetSubsystemLowPowerStats) {
+TEST_P(PowerHidlTest, GetSubsystemLowPowerStats) {
hidl_vec<PowerStateSubsystem> vec;
Status s;
auto cb = [&vec, &s](hidl_vec<PowerStateSubsystem> subsystems,
@@ -70,7 +57,7 @@
}
// Sanity check Power::powerHintAsync on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHintAsync) {
+TEST_P(PowerHidlTest, PowerHintAsync) {
PowerHint badHint = static_cast<PowerHint>(0xA);
auto hints = {PowerHint::VSYNC, PowerHint::INTERACTION, PowerHint::VIDEO_ENCODE,
PowerHint::VIDEO_DECODE, PowerHint::LOW_POWER, PowerHint::SUSTAINED_PERFORMANCE,
@@ -104,11 +91,7 @@
} while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- PowerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, PowerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/power/1.2/vts/functional/Android.bp b/power/1.2/vts/functional/Android.bp
index f424bfa..5385faa 100644
--- a/power/1.2/vts/functional/Android.bp
+++ b/power/1.2/vts/functional/Android.bp
@@ -23,5 +23,5 @@
"android.hardware.power@1.1",
"android.hardware.power@1.2",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
index 5e92997..a5ecf5d 100644
--- a/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
+++ b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "power_hidl_hal_test"
#include <android-base/logging.h>
#include <android/hardware/power/1.2/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::sp;
using ::android::hardware::hidl_vec;
@@ -27,23 +27,10 @@
using ::android::hardware::power::V1_2::IPower;
using ::android::hardware::power::V1_2::PowerHint;
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static PowerHidlEnvironment* Instance() {
- static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
- PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+ power = IPower::getService(GetParam());
ASSERT_NE(power, nullptr);
}
@@ -51,7 +38,7 @@
};
// Sanity check Power::PowerHintAsync_1_2 on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHintAsync_1_2) {
+TEST_P(PowerHidlTest, PowerHintAsync_1_2) {
std::vector<PowerHint> hints;
for (uint32_t i = static_cast<uint32_t>(PowerHint::VSYNC);
i <= static_cast<uint32_t>(PowerHint::CAMERA_SHOT); ++i) {
@@ -89,11 +76,8 @@
} while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- PowerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, PowerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
diff --git a/power/1.3/vts/functional/Android.bp b/power/1.3/vts/functional/Android.bp
index 06f6e7a..77e8619 100644
--- a/power/1.3/vts/functional/Android.bp
+++ b/power/1.3/vts/functional/Android.bp
@@ -24,5 +24,5 @@
"android.hardware.power@1.2",
"android.hardware.power@1.3",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp b/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
index af1a1d8..3cf2adc 100644
--- a/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
+++ b/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "power_hidl_hal_test"
#include <android-base/logging.h>
#include <android/hardware/power/1.3/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::sp;
using ::android::hardware::hidl_vec;
@@ -27,38 +27,21 @@
using ::android::hardware::power::V1_3::IPower;
using ::android::hardware::power::V1_3::PowerHint;
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static PowerHidlEnvironment* Instance() {
- static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
- PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+ power = IPower::getService(GetParam());
ASSERT_NE(power, nullptr);
}
sp<IPower> power;
};
-TEST_F(PowerHidlTest, PowerHintAsync_1_3) {
+TEST_P(PowerHidlTest, PowerHintAsync_1_3) {
ASSERT_TRUE(power->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, 0).isOk());
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- PowerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, PowerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/power/stats/1.0/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp
index f564cbe..ab47061 100644
--- a/power/stats/1.0/vts/functional/Android.bp
+++ b/power/stats/1.0/vts/functional/Android.bp
@@ -33,4 +33,5 @@
"libfmq",
"libutils",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
index 835a47b..3359669 100644
--- a/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
+++ b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
@@ -16,13 +16,15 @@
#define LOG_TAG "android.power.stats.vts"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/power/stats/1.0/IPowerStats.h>
#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
#include <inttypes.h>
+
#include <algorithm>
#include <random>
#include <thread>
@@ -49,23 +51,11 @@
} // namespace
typedef hardware::MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
-// Test environment for Power HIDL HAL.
-class PowerStatsHidlEnv : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static PowerStatsHidlEnv* Instance() {
- static PowerStatsHidlEnv* instance = new PowerStatsHidlEnv;
- return instance;
- }
- virtual void registerTestServices() override { registerTestService<IPowerStats>(); }
-};
-
-class PowerStatsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerStatsHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- service_ = ::testing::VtsHalHidlTargetTestBase::getService<IPowerStats>(
- PowerStatsHidlEnv::Instance()->getServiceName<IPowerStats>());
+ service_ = IPowerStats::getService(GetParam());
ASSERT_NE(service_, nullptr);
}
@@ -157,7 +147,7 @@
}
// Each PowerEntity must have a valid name
-TEST_F(PowerStatsHidlTest, ValidatePowerEntityNames) {
+TEST_P(PowerStatsHidlTest, ValidatePowerEntityNames) {
hidl_vec<PowerEntityInfo> infos;
getInfos(infos);
for (auto info : infos) {
@@ -166,18 +156,18 @@
}
// Each PowerEntity must have a unique ID
-TEST_F(PowerStatsHidlTest, ValidatePowerEntityIds) {
+TEST_P(PowerStatsHidlTest, ValidatePowerEntityIds) {
hidl_vec<PowerEntityInfo> infos;
getInfos(infos);
- set<uint32_t> ids;
+ std::set<uint32_t> ids;
for (auto info : infos) {
ASSERT_TRUE(ids.insert(info.powerEntityId).second);
}
}
// Each PowerEntityStateSpace must have an associated PowerEntityInfo
-TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociation) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoAssociation) {
hidl_vec<PowerEntityInfo> infos;
getInfos(infos);
@@ -195,7 +185,7 @@
}
// Each state must have a valid name
-TEST_F(PowerStatsHidlTest, ValidateStateNames) {
+TEST_P(PowerStatsHidlTest, ValidateStateNames) {
hidl_vec<PowerEntityStateSpace> stateSpaces;
getStateSpaces(stateSpaces);
@@ -207,12 +197,12 @@
}
// Each state must have an ID that is unique to the PowerEntityStateSpace
-TEST_F(PowerStatsHidlTest, ValidateStateUniqueIds) {
+TEST_P(PowerStatsHidlTest, ValidateStateUniqueIds) {
hidl_vec<PowerEntityStateSpace> stateSpaces;
getStateSpaces(stateSpaces);
for (auto stateSpace : stateSpaces) {
- set<uint32_t> stateIds;
+ std::set<uint32_t> stateIds;
for (auto state : stateSpace.states) {
ASSERT_TRUE(stateIds.insert(state.powerEntityStateId).second);
}
@@ -221,7 +211,7 @@
// getPowerEntityStateInfo must support passing in requested IDs
// Results must contain state space information for all requested IDs
-TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) {
std::vector<uint32_t> randomIds;
getRandomIds(randomIds);
@@ -244,7 +234,7 @@
}
// Requested state space info must match initially obtained stateinfos
-TEST_F(PowerStatsHidlTest, ValidateStateInfoSelect) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoSelect) {
hidl_vec<PowerEntityStateSpace> stateSpaces;
getStateSpaces(stateSpaces);
if (stateSpaces.size() == 0) {
@@ -279,7 +269,7 @@
// stateResidencyResults must contain results for every PowerEntityStateSpace
// returned by getPowerEntityStateInfo
-TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociation) {
+TEST_P(PowerStatsHidlTest, ValidateResidencyResultsAssociation) {
hidl_vec<PowerEntityStateSpace> stateSpaces;
getStateSpaces(stateSpaces);
@@ -311,7 +301,7 @@
// getPowerEntityStateResidencyData must support passing in requested IDs
// stateResidencyResults must contain results for each PowerEntityStateSpace
// returned by getPowerEntityStateInfo
-TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) {
+TEST_P(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) {
std::vector<uint32_t> randomIds;
getRandomIds(randomIds);
if (randomIds.empty()) {
@@ -346,7 +336,7 @@
}
}
-TEST_F(PowerStatsHidlTest, ValidateRailInfo) {
+TEST_P(PowerStatsHidlTest, ValidateRailInfo) {
hidl_vec<RailInfo> rails[2];
Status s;
auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) {
@@ -359,7 +349,7 @@
/* Rails size should be non-zero on SUCCESS*/
ASSERT_NE(rails[0].size(), 0);
/* check if indices returned are unique*/
- set<uint32_t> ids;
+ std::set<uint32_t> ids;
for (auto rail : rails[0]) {
ASSERT_TRUE(ids.insert(rail.index).second);
}
@@ -402,7 +392,7 @@
}
}
-TEST_F(PowerStatsHidlTest, ValidateAllPowerData) {
+TEST_P(PowerStatsHidlTest, ValidateAllPowerData) {
hidl_vec<EnergyData> measurements[2];
Status s;
auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) {
@@ -451,7 +441,7 @@
}
}
-TEST_F(PowerStatsHidlTest, ValidateFilteredPowerData) {
+TEST_P(PowerStatsHidlTest, ValidateFilteredPowerData) {
hidl_vec<RailInfo> rails;
hidl_vec<EnergyData> measurements;
hidl_vec<uint32_t> indices;
@@ -559,23 +549,19 @@
}
}
-TEST_F(PowerStatsHidlTest, StreamEnergyData) {
+TEST_P(PowerStatsHidlTest, StreamEnergyData) {
std::time_t seed = std::time(nullptr);
std::srand(seed);
std::thread thread1 = std::thread(readEnergy, service_, std::rand() % 5000);
thread1.join();
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, PowerStatsHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPowerStats::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace vts
} // namespace stats
} // namespace power
} // namespace android
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(android::power::stats::vts::PowerStatsHidlEnv::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- android::power::stats::vts::PowerStatsHidlEnv::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp
new file mode 100644
index 0000000..06a2a6e
--- /dev/null
+++ b/radio/1.5/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.radio@1.5",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IRadio.hal",
+ "IRadioIndication.hal",
+ "IRadioResponse.hal",
+ ],
+ interfaces: [
+ "android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.3",
+ "android.hardware.radio@1.4",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
new file mode 100644
index 0000000..de20dd0
--- /dev/null
+++ b/radio/1.5/IRadio.hal
@@ -0,0 +1,30 @@
+/*
+ * 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.radio@1.5;
+
+import @1.4::IRadio;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication.
+ */
+interface IRadio extends @1.4::IRadio {
+};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
new file mode 100644
index 0000000..d488404
--- /dev/null
+++ b/radio/1.5/IRadioIndication.hal
@@ -0,0 +1,26 @@
+/*
+ * 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.radio@1.5;
+
+import @1.0::RadioIndicationType;
+import @1.4::IRadioIndication;
+
+/**
+ * Interface declaring unsolicited radio indications.
+ */
+interface IRadioIndication extends @1.4::IRadioIndication {
+};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
new file mode 100644
index 0000000..d4c4f76
--- /dev/null
+++ b/radio/1.5/IRadioResponse.hal
@@ -0,0 +1,26 @@
+/*
+ * 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.radio@1.5;
+
+import @1.0::RadioResponseInfo;
+import @1.4::IRadioResponse;
+
+/**
+ * Interface declaring response functions to solicited radio requests.
+ */
+interface IRadioResponse extends @1.4::IRadioResponse {
+};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
new file mode 100644
index 0000000..a639a8d
--- /dev/null
+++ b/radio/1.5/types.hal
@@ -0,0 +1,17 @@
+/*
+ * 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.radio@1.5;
diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS
new file mode 100644
index 0000000..3629a6c
--- /dev/null
+++ b/radio/1.5/vts/OWNERS
@@ -0,0 +1,10 @@
+# Telephony team
+refuhoo@google.com
+amitmahajan@google.com
+jackyu@google.com
+fionaxu@google.com
+# more to add
+
+# VTS team
+yuexima@google.com
+dshi@google.com
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
new file mode 100644
index 0000000..85c4f99
--- /dev/null
+++ b/radio/1.5/vts/functional/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalRadioV1_5TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "radio_hidl_hal_api.cpp",
+ "radio_hidl_hal_test.cpp",
+ "radio_response.cpp",
+ "radio_indication.cpp",
+ "VtsHalRadioV1_5TargetTest.cpp",
+ ],
+ static_libs: [
+ "RadioVtsTestUtilBase",
+ "android.hardware.radio@1.5",
+ "android.hardware.radio@1.4",
+ "android.hardware.radio@1.3",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.0",
+ "android.hardware.radio.config@1.0",
+ "android.hardware.radio.config@1.1",
+ ],
+ header_libs: ["radio.util.header@1.0"],
+ test_suites: ["general-tests"]
+}
diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
new file mode 100644
index 0000000..b72febd
--- /dev/null
+++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ RadioHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
new file mode 100644
index 0000000..b86fa5f
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
new file mode 100644
index 0000000..a5d236d
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+void RadioHidlTest_v1_5::SetUp() {
+ radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::V1_5::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ if (radio_v1_5 == NULL) {
+ sleep(60);
+ radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::V1_5::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ }
+ ASSERT_NE(nullptr, radio_v1_5.get());
+
+ radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this);
+ ASSERT_NE(nullptr, radioRsp_v1_5.get());
+
+ count_ = 0;
+
+ radioInd_v1_5 = new (std::nothrow) RadioIndication_v1_5(*this);
+ ASSERT_NE(nullptr, radioInd_v1_5.get());
+
+ radio_v1_5->setResponseFunctions(radioRsp_v1_5, radioInd_v1_5);
+
+ updateSimCardStatus();
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+ ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::config::V1_1::IRadioConfig>();
+
+ /* Enforce Vts tesing with RadioConfig is existed. */
+ ASSERT_NE(nullptr, radioConfig.get());
+
+ /* Enforce Vts Testing with Sim Status Present only. */
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioHidlTest_v1_5::notify(int receivedSerial) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ if (serial == receivedSerial) {
+ count_++;
+ cv_.notify_one();
+ }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioHidlTest_v1_5::wait() {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count_ == 0) {
+ status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ return status;
+ }
+ }
+ count_--;
+ return status;
+}
+
+void RadioHidlTest_v1_5::updateSimCardStatus() {
+ serial = GetRandomSerialNumber();
+ radio_v1_5->getIccCardStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
new file mode 100644
index 0000000..799702b
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -0,0 +1,760 @@
+/*
+ * 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 <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+
+#include <android/hardware/radio/1.5/IRadio.h>
+#include <android/hardware/radio/1.5/IRadioIndication.h>
+#include <android/hardware/radio/1.5/IRadioResponse.h>
+#include <android/hardware/radio/1.5/types.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::V1_5;
+using namespace ::android::hardware::radio::V1_4;
+using namespace ::android::hardware::radio::V1_3;
+using namespace ::android::hardware::radio::V1_2;
+using namespace ::android::hardware::radio::V1_1;
+using namespace ::android::hardware::radio::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 75
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioHidlTest_v1_5;
+extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+/* Callback class for radio respons v1_5 */
+class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
+ protected:
+ RadioHidlTest_v1_5& parent_v1_5;
+
+ public:
+ hidl_vec<RadioBandMode> radioBandModes;
+
+ RadioResponseInfo rspInfo;
+
+ // Call
+ hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+
+ // Modem
+ bool isModemEnabled;
+ bool enableModemResponseToggle;
+
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmapResponse;
+
+ // Data
+ ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp;
+
+ // SimLock status
+ ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp;
+ ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp;
+
+ RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+ virtual ~RadioResponse_v1_5() = default;
+
+ Return<void> getIccCardStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
+
+ Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPukForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> changeIccPinForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> changeIccPin2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> getCurrentCallsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
+
+ Return<void> dialResponse(const RadioResponseInfo& info);
+
+ Return<void> getIMSIForAppResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& imsi);
+
+ Return<void> hangupConnectionResponse(const RadioResponseInfo& info);
+
+ Return<void> hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info);
+
+ Return<void> hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info);
+
+ Return<void> switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info);
+
+ Return<void> conferenceResponse(const RadioResponseInfo& info);
+
+ Return<void> rejectCallResponse(const RadioResponseInfo& info);
+
+ Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
+ const LastCallFailCauseInfo& failCauseInfo);
+
+ Return<void> getSignalStrengthResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
+
+ Return<void> getVoiceRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
+
+ Return<void> getDataRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
+
+ Return<void> getOperatorResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& longName,
+ const ::android::hardware::hidl_string& shortName,
+ const ::android::hardware::hidl_string& numeric);
+
+ Return<void> setRadioPowerResponse(const RadioResponseInfo& info);
+
+ Return<void> sendDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> setupDataCallResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse);
+
+ Return<void> iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo);
+
+ Return<void> sendUssdResponse(const RadioResponseInfo& info);
+
+ Return<void> cancelPendingUssdResponse(const RadioResponseInfo& info);
+
+ Return<void> getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m);
+
+ Return<void> setClirResponse(const RadioResponseInfo& info);
+
+ Return<void> getCallForwardStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<CallForwardInfo>& call_forwardInfos);
+
+ Return<void> setCallForwardResponse(const RadioResponseInfo& info);
+
+ Return<void> getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
+ int32_t serviceClass);
+
+ Return<void> setCallWaitingResponse(const RadioResponseInfo& info);
+
+ Return<void> acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info);
+
+ Return<void> acceptCallResponse(const RadioResponseInfo& info);
+
+ Return<void> deactivateDataCallResponse(const RadioResponseInfo& info);
+
+ Return<void> getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response);
+
+ Return<void> setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry);
+
+ Return<void> setBarringPasswordResponse(const RadioResponseInfo& info);
+
+ Return<void> getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual);
+
+ Return<void> setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info);
+
+ Return<void> setNetworkSelectionModeManualResponse(const RadioResponseInfo& info);
+
+ Return<void> getAvailableNetworksResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos);
+
+ Return<void> startDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> stopDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> getBasebandVersionResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& version);
+
+ Return<void> separateConnectionResponse(const RadioResponseInfo& info);
+
+ Return<void> setMuteResponse(const RadioResponseInfo& info);
+
+ Return<void> getMuteResponse(const RadioResponseInfo& info, bool enable);
+
+ Return<void> getClipResponse(const RadioResponseInfo& info, ClipStatus status);
+
+ Return<void> getDataCallListResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse);
+
+ Return<void> sendOemRilRequestRawResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<uint8_t>& data);
+
+ Return<void> sendOemRilRequestStringsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
+
+ Return<void> setSuppServiceNotificationsResponse(const RadioResponseInfo& info);
+
+ Return<void> writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index);
+
+ Return<void> deleteSmsOnSimResponse(const RadioResponseInfo& info);
+
+ Return<void> setBandModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getAvailableBandModesResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<RadioBandMode>& bandModes);
+
+ Return<void> sendEnvelopeResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& commandResponse);
+
+ Return<void> sendTerminalResponseToSimResponse(const RadioResponseInfo& info);
+
+ Return<void> handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info);
+
+ Return<void> explicitCallTransferResponse(const RadioResponseInfo& info);
+
+ Return<void> setPreferredNetworkTypeResponse(const RadioResponseInfo& info);
+
+ Return<void> getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
+ PreferredNetworkType nwType);
+
+ Return<void> getNeighboringCidsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<NeighboringCell>& cells);
+
+ Return<void> setLocationUpdatesResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
+ CdmaRoamingType type);
+
+ Return<void> setTTYModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode);
+
+ Return<void> setPreferredVoicePrivacyResponse(const RadioResponseInfo& info);
+
+ Return<void> getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable);
+
+ Return<void> sendCDMAFeatureCodeResponse(const RadioResponseInfo& info);
+
+ Return<void> sendBurstDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
+
+ Return<void> getGsmBroadcastConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& configs);
+
+ Return<void> setGsmBroadcastConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setGsmBroadcastActivationResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaBroadcastConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& configs);
+
+ Return<void> setCdmaBroadcastConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaBroadcastActivationResponse(const RadioResponseInfo& info);
+
+ Return<void> getCDMASubscriptionResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& mdn,
+ const ::android::hardware::hidl_string& hSid,
+ const ::android::hardware::hidl_string& hNid,
+ const ::android::hardware::hidl_string& min,
+ const ::android::hardware::hidl_string& prl);
+
+ Return<void> writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index);
+
+ Return<void> deleteSmsOnRuimResponse(const RadioResponseInfo& info);
+
+ Return<void> getDeviceIdentityResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& imei,
+ const ::android::hardware::hidl_string& imeisv,
+ const ::android::hardware::hidl_string& esn,
+ const ::android::hardware::hidl_string& meid);
+
+ Return<void> exitEmergencyCallbackModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getSmscAddressResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& smsc);
+
+ Return<void> setSmscAddressResponse(const RadioResponseInfo& info);
+
+ Return<void> reportSmsMemoryStatusResponse(const RadioResponseInfo& info);
+
+ Return<void> reportStkServiceIsRunningResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
+ CdmaSubscriptionSource source);
+
+ Return<void> requestIsimAuthenticationResponse(
+ const RadioResponseInfo& info, const ::android::hardware::hidl_string& response);
+
+ Return<void> acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info);
+
+ Return<void> sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
+ const IccIoResult& iccIo);
+
+ Return<void> getVoiceRadioTechnologyResponse(
+ const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+ Return<void> getCellInfoListResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+ cellInfo);
+
+ Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
+
+ Return<void> setInitialAttachApnResponse(const RadioResponseInfo& info);
+
+ Return<void> getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered,
+ RadioTechnologyFamily ratFamily);
+
+ Return<void> sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> iccOpenLogicalChannelResponse(
+ const RadioResponseInfo& info, int32_t channelId,
+ const ::android::hardware::hidl_vec<int8_t>& selectResponse);
+
+ Return<void> iccCloseLogicalChannelResponse(const RadioResponseInfo& info);
+
+ Return<void> iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> nvReadItemResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& result);
+
+ Return<void> nvWriteItemResponse(const RadioResponseInfo& info);
+
+ Return<void> nvWriteCdmaPrlResponse(const RadioResponseInfo& info);
+
+ Return<void> nvResetConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setUiccSubscriptionResponse(const RadioResponseInfo& info);
+
+ Return<void> setDataAllowedResponse(const RadioResponseInfo& info);
+
+ Return<void> getHardwareConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<HardwareConfig>& config);
+
+ Return<void> requestIccSimAuthenticationResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> setDataProfileResponse(const RadioResponseInfo& info);
+
+ Return<void> requestShutdownResponse(const RadioResponseInfo& info);
+
+ Return<void> getRadioCapabilityResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> setRadioCapabilityResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> startLceServiceResponse(const RadioResponseInfo& info,
+ const LceStatusInfo& statusInfo);
+
+ Return<void> stopLceServiceResponse(const RadioResponseInfo& info,
+ const LceStatusInfo& statusInfo);
+
+ Return<void> pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo);
+
+ Return<void> getModemActivityInfoResponse(const RadioResponseInfo& info,
+ const ActivityStatsInfo& activityInfo);
+
+ Return<void> setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed);
+
+ Return<void> getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed,
+ const CarrierRestrictions& carriers);
+
+ Return<void> sendDeviceStateResponse(const RadioResponseInfo& info);
+
+ Return<void> setIndicationFilterResponse(const RadioResponseInfo& info);
+
+ Return<void> setSimCardPowerResponse(const RadioResponseInfo& info);
+
+ Return<void> acknowledgeRequest(int32_t serial);
+
+ /* 1.1 Api */
+ Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+
+ Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+
+ Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+
+ Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+
+ Return<void> startKeepaliveResponse(const RadioResponseInfo& info,
+ const KeepaliveStatus& status);
+
+ Return<void> stopKeepaliveResponse(const RadioResponseInfo& info);
+
+ /* 1.2 Api */
+ Return<void> setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info);
+
+ Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
+
+ Return<void> getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::CardStatus& card_status);
+
+ Return<void> getCurrentCallsResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
+
+ Return<void> getSignalStrengthResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
+
+ Return<void> getSignalStrengthResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::SignalStrength& sig_strength);
+
+ Return<void> getCellInfoListResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+ cellInfo);
+
+ Return<void> getVoiceRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
+
+ Return<void> getDataRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
+
+ /* 1.3 Api */
+ Return<void> setSystemSelectionChannelsResponse(const RadioResponseInfo& info);
+
+ Return<void> enableModemResponse(const RadioResponseInfo& info);
+
+ Return<void> getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled);
+
+ /* 1.4 Api */
+ Return<void> emergencyDialResponse(const RadioResponseInfo& info);
+
+ Return<void> startNetworkScanResponse_1_4(const RadioResponseInfo& info);
+
+ Return<void> getCellInfoListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+ cellInfo);
+
+ Return<void> getDataRegistrationStateResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse);
+
+ Return<void> getIccCardStatusResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::CardStatus& card_status);
+
+ Return<void> getPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmap);
+
+ Return<void> setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info);
+
+ Return<void> getDataCallListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse);
+
+ Return<void> setupDataCallResponse_1_4(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+
+ Return<void> setAllowedCarriersResponse_1_4(const RadioResponseInfo& info);
+
+ Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
+ const CarrierRestrictionsWithPriority& carriers,
+ SimLockMultiSimPolicy multiSimPolicy);
+};
+
+/* Callback class for radio indication */
+class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndication {
+ protected:
+ RadioHidlTest_v1_5& parent_v1_5;
+
+ public:
+ RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+ virtual ~RadioIndication_v1_5() = default;
+
+ /* 1.4 Api */
+ Return<void> currentEmergencyNumberList(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<EmergencyNumber>& emergencyNumberList);
+
+ Return<void> cellInfoList_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+ records);
+
+ Return<void> networkScanResult_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_4::NetworkScanResult& result);
+
+ Return<void> currentPhysicalChannelConfigs_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::PhysicalChannelConfig>& configs);
+
+ Return<void> dataCallListChanged_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_4::SetupDataCallResult>& dcList);
+
+ /* 1.2 Api */
+ Return<void> networkScanResult_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& result);
+
+ Return<void> cellInfoList_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+ records);
+
+ Return<void> currentLinkCapacityEstimate(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
+
+ Return<void> currentPhysicalChannelConfigs(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs);
+
+ Return<void> currentSignalStrength_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::SignalStrength& signalStrength);
+
+ Return<void> currentSignalStrength_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_4::SignalStrength& signalStrength);
+
+ /* 1.1 Api */
+ Return<void> carrierInfoForImsiEncryption(RadioIndicationType info);
+
+ Return<void> networkScanResult(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& result);
+
+ Return<void> keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status);
+
+ /* 1.0 Api */
+ Return<void> radioStateChanged(RadioIndicationType type, RadioState radioState);
+
+ Return<void> callStateChanged(RadioIndicationType type);
+
+ Return<void> networkStateChanged(RadioIndicationType type);
+
+ Return<void> newSms(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+ Return<void> newSmsStatusReport(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+ Return<void> newSmsOnSim(RadioIndicationType type, int32_t recordNumber);
+
+ Return<void> onUssd(RadioIndicationType type, UssdModeType modeType,
+ const ::android::hardware::hidl_string& msg);
+
+ Return<void> nitzTimeReceived(RadioIndicationType type,
+ const ::android::hardware::hidl_string& nitzTime,
+ uint64_t receivedTime);
+
+ Return<void> currentSignalStrength(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_0::SignalStrength& signalStrength);
+
+ Return<void> dataCallListChanged(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_0::SetupDataCallResult>& dcList);
+
+ Return<void> suppSvcNotify(RadioIndicationType type, const SuppSvcNotification& suppSvc);
+
+ Return<void> stkSessionEnd(RadioIndicationType type);
+
+ Return<void> stkProactiveCommand(RadioIndicationType type,
+ const ::android::hardware::hidl_string& cmd);
+
+ Return<void> stkEventNotify(RadioIndicationType type,
+ const ::android::hardware::hidl_string& cmd);
+
+ Return<void> stkCallSetup(RadioIndicationType type, int64_t timeout);
+
+ Return<void> simSmsStorageFull(RadioIndicationType type);
+
+ Return<void> simRefresh(RadioIndicationType type, const SimRefreshResult& refreshResult);
+
+ Return<void> callRing(RadioIndicationType type, bool isGsm, const CdmaSignalInfoRecord& record);
+
+ Return<void> simStatusChanged(RadioIndicationType type);
+
+ Return<void> cdmaNewSms(RadioIndicationType type, const CdmaSmsMessage& msg);
+
+ Return<void> newBroadcastSms(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& data);
+
+ Return<void> cdmaRuimSmsStorageFull(RadioIndicationType type);
+
+ Return<void> restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state);
+
+ Return<void> enterEmergencyCallbackMode(RadioIndicationType type);
+
+ Return<void> cdmaCallWaiting(RadioIndicationType type,
+ const CdmaCallWaiting& callWaitingRecord);
+
+ Return<void> cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status);
+
+ Return<void> cdmaInfoRec(RadioIndicationType type, const CdmaInformationRecords& records);
+
+ Return<void> indicateRingbackTone(RadioIndicationType type, bool start);
+
+ Return<void> resendIncallMute(RadioIndicationType type);
+
+ Return<void> cdmaSubscriptionSourceChanged(RadioIndicationType type,
+ CdmaSubscriptionSource cdmaSource);
+
+ Return<void> cdmaPrlChanged(RadioIndicationType type, int32_t version);
+
+ Return<void> exitEmergencyCallbackMode(RadioIndicationType type);
+
+ Return<void> rilConnected(RadioIndicationType type);
+
+ Return<void> voiceRadioTechChanged(RadioIndicationType type,
+ ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+ Return<void> cellInfoList(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+ records);
+
+ Return<void> imsNetworkStateChanged(RadioIndicationType type);
+
+ Return<void> subscriptionStatusChanged(RadioIndicationType type, bool activate);
+
+ Return<void> srvccStateNotify(RadioIndicationType type, SrvccState state);
+
+ Return<void> hardwareConfigChanged(
+ RadioIndicationType type, const ::android::hardware::hidl_vec<HardwareConfig>& configs);
+
+ Return<void> radioCapabilityIndication(
+ RadioIndicationType type, const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> onSupplementaryServiceIndication(RadioIndicationType type,
+ const StkCcUnsolSsResult& ss);
+
+ Return<void> stkCallControlAlphaNotify(RadioIndicationType type,
+ const ::android::hardware::hidl_string& alpha);
+
+ Return<void> lceData(RadioIndicationType type, const LceDataInfo& lce);
+
+ Return<void> pcoData(RadioIndicationType type, const PcoDataInfo& pco);
+
+ Return<void> modemReset(RadioIndicationType type,
+ const ::android::hardware::hidl_string& reason);
+};
+
+// Test environment for Radio HIDL HAL.
+class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static RadioHidlEnvironment* Instance() {
+ static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
+ return instance;
+ }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::radio::V1_5::IRadio>();
+ }
+
+ private:
+ RadioHidlEnvironment() {}
+};
+
+// The main test class for Radio HIDL.
+class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
+ /* Serial number for radio request */
+ int serial;
+
+ /* Clear Potential Established Calls */
+ void clearPotentialEstablishedCalls();
+
+ /* Update Sim Card Status */
+ void updateSimCardStatus();
+
+ public:
+ virtual void SetUp() override;
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ void notify(int receivedSerial);
+
+ /* Test code calls this function to wait for response */
+ std::cv_status wait();
+
+ /* radio service handle */
+ sp<::android::hardware::radio::V1_5::IRadio> radio_v1_5;
+
+ /* radio response handle */
+ sp<RadioResponse_v1_5> radioRsp_v1_5;
+
+ /* radio indication handle */
+ sp<RadioIndication_v1_5> radioInd_v1_5;
+};
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
new file mode 100644
index 0000000..b63b745
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.4 Apis */
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentEmergencyNumberList(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<EmergencyNumber>& /*emergencyNumberList*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_4::SetupDataCallResult>&
+ /*dcList*/) {
+ return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioIndication_v1_5::networkScanResult_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentLinkCapacityEstimate(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioIndication_v1_5::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::keepaliveStatus(RadioIndicationType /*type*/,
+ const KeepaliveStatus& /*status*/) {
+ return Void();
+}
+
+/* 1.0 Apis */
+Return<void> RadioIndication_v1_5::radioStateChanged(RadioIndicationType /*type*/,
+ RadioState /*radioState*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::callStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSms(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsStatusReport(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsOnSim(RadioIndicationType /*type*/,
+ int32_t /*recordNumber*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/,
+ const ::android::hardware::hidl_string& /*msg*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::nitzTimeReceived(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/,
+ uint64_t /*receivedTime*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+ /*dcList*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::suppSvcNotify(RadioIndicationType /*type*/,
+ const SuppSvcNotification& /*suppSvc*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkSessionEnd(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkProactiveCommand(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkEventNotify(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_string& /*cmd*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simSmsStorageFull(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simRefresh(RadioIndicationType /*type*/,
+ const SimRefreshResult& /*refreshResult*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::callRing(RadioIndicationType /*type*/, bool /*isGsm*/,
+ const CdmaSignalInfoRecord& /*record*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simStatusChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaNewSms(RadioIndicationType /*type*/,
+ const CdmaSmsMessage& /*msg*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newBroadcastSms(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::restrictedStateChanged(RadioIndicationType /*type*/,
+ PhoneRestrictedState /*state*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::enterEmergencyCallbackMode(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaCallWaiting(RadioIndicationType /*type*/,
+ const CdmaCallWaiting& /*callWaitingRecord*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaOtaProvisionStatus(RadioIndicationType /*type*/,
+ CdmaOtaProvisionStatus /*status*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaInfoRec(RadioIndicationType /*type*/,
+ const CdmaInformationRecords& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::indicateRingbackTone(RadioIndicationType /*type*/,
+ bool /*start*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::resendIncallMute(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaSubscriptionSourceChanged(
+ RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaPrlChanged(RadioIndicationType /*type*/,
+ int32_t /*version*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::exitEmergencyCallbackMode(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::rilConnected(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::voiceRadioTechChanged(
+ RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_0::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::imsNetworkStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::subscriptionStatusChanged(RadioIndicationType /*type*/,
+ bool /*activate*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::srvccStateNotify(RadioIndicationType /*type*/,
+ SrvccState /*state*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::hardwareConfigChanged(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::radioCapabilityIndication(
+ RadioIndicationType /*type*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::onSupplementaryServiceIndication(
+ RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallControlAlphaNotify(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::lceData(RadioIndicationType /*type*/,
+ const LceDataInfo& /*lce*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::pcoData(RadioIndicationType /*type*/,
+ const PcoDataInfo& /*pco*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_string& /*reason*/) {
+ return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
new file mode 100644
index 0000000..1e5cc47
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -0,0 +1,887 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyNetworkDepersonalizationResponse(
+ const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::dialResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIMSIForAppResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupConnectionResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupWaitingOrBackgroundResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupForegroundResumeBackgroundResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::switchWaitingOrHoldingAndActiveResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::conferenceResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getLastCallFailCauseResponse(
+ const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getOperatorResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/,
+ const ::android::hardware::hidl_string& /*shortName*/,
+ const ::android::hardware::hidl_string& /*numeric*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccIOForAppResponse(const RadioResponseInfo& /*info*/,
+ const IccIoResult& /*iccIo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/,
+ int32_t /*m*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setClirResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallForwardStatusResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>&
+ /*callForwardInfos*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/, int32_t /*serviceClass*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingGsmSmsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deactivateDataCallResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*response*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*retry*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/,
+ bool /*manual*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeAutomaticResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableNetworksResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getBasebandVersionResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::separateConnectionResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setMuteResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getMuteResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClipResponse(const RadioResponseInfo& /*info*/,
+ ClipStatus /*status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+ /*dcResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestRawResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestStringsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSuppServiceNotificationsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*index*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableBandModesResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
+ rspInfo = info;
+ radioBandModes = bandModes;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_string& /*commandResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendTerminalResponseToSimResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::handleStkCallSetupRequestFromSimResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/,
+ PreferredNetworkType /*nw_type*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNeighboringCidsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaSubscriptionSourceResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaRoamingPreferenceResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/,
+ CdmaRoamingType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setTTYModeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getTTYModeResponse(const RadioResponseInfo& /*info*/,
+ TtyMode /*mode*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredVoicePrivacyResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getGsmBroadcastConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastActivationResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaBroadcastConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastActivationResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCDMASubscriptionResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/,
+ const ::android::hardware::hidl_string& /*hSid*/,
+ const ::android::hardware::hidl_string& /*hNid*/,
+ const ::android::hardware::hidl_string& /*min*/,
+ const ::android::hardware::hidl_string& /*prl*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
+ uint32_t /*index*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDeviceIdentityResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/,
+ const ::android::hardware::hidl_string& /*imeisv*/,
+ const ::android::hardware::hidl_string& /*esn*/,
+ const ::android::hardware::hidl_string& /*meid*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::exitEmergencyCallbackModeResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSmscAddressResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportStkServiceIsRunningResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaSubscriptionSourceResponse(
+ const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIsimAuthenticationResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeIncomingGsmSmsWithPduResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/,
+ const IccIoResult& /*iccIo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRadioTechnologyResponse(
+ const RadioResponseInfo& /*info*/,
+ ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setInitialAttachApnResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getImsRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+ RadioTechnologyFamily /*ratFamily*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduBasicChannelResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccOpenLogicalChannelResponse(
+ const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+ const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduLogicalChannelResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvReadItemResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getHardwareConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIccSimAuthenticationResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataProfileResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getRadioCapabilityResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioCapabilityResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startLceServiceResponse(const RadioResponseInfo& /*info*/,
+ const LceStatusInfo& /*statusInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopLceServiceResponse(const RadioResponseInfo& /*info*/,
+ const LceStatusInfo& /*statusInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::pullLceDataResponse(const RadioResponseInfo& /*info*/,
+ const LceDataInfo& /*lceInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemActivityInfoResponse(
+ const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*numAllowed*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse(
+ const RadioResponseInfo& /*info*/, bool /*allAllowed*/,
+ const CarrierRestrictions& /*carriers*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setIndicationFilterResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeRequest(int32_t /*serial*/) {
+ return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioResponse_v1_5::setCarrierInfoForImsiEncryptionResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopNetworkScanResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
+ const KeepaliveStatus& /*status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
+ rspInfo = info;
+ currentCalls = calls;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
+ return Void();
+}
+
+/* 1.3 Apis */
+Return<void> RadioResponse_v1_5::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::enableModemResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemStackStatusResponse(const RadioResponseInfo& info,
+ const bool enabled) {
+ rspInfo = info;
+ isModemEnabled = enabled;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+/* 1.4 Apis */
+Return<void> RadioResponse_v1_5::emergencyDialResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse_1_4(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) {
+ rspInfo = info;
+ dataRegResp = dataRegResponse;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+ rspInfo = info;
+ cardStatus = card_status;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmap) {
+ rspInfo = info;
+ networkTypeBitmapResponse = networkTypeBitmap;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>&
+ /*dcResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse_1_4(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse_1_4(
+ const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers,
+ SimLockMultiSimPolicy multiSimPolicy) {
+ rspInfo = info;
+ carrierRestrictionsResp = carriers;
+ multiSimPolicyResp = multiSimPolicy;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
diff --git a/renderscript/1.0/default/Device.cpp b/renderscript/1.0/default/Device.cpp
index d603a12..9a6d7ba 100644
--- a/renderscript/1.0/default/Device.cpp
+++ b/renderscript/1.0/default/Device.cpp
@@ -86,150 +86,116 @@
}
dispatchTable dispatchHal = {
- .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
+ .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
- .Allocation1DData =
- (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
- .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
- .Allocation1DRead =
- (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
- .Allocation2DData =
- (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
- .Allocation2DRead =
- (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
- .Allocation3DData =
- (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
- .Allocation3DRead =
- (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
- .AllocationAdapterCreate = (AllocationAdapterCreateFnPtr)dlsym(
- handle, "rsAllocationAdapterCreate"),
- .AllocationAdapterOffset = (AllocationAdapterOffsetFnPtr)dlsym(
- handle, "rsAllocationAdapterOffset"),
- .AllocationCopy2DRange = (AllocationCopy2DRangeFnPtr)dlsym(
- handle, "rsAllocationCopy2DRange"),
- .AllocationCopy3DRange = (AllocationCopy3DRangeFnPtr)dlsym(
- handle, "rsAllocationCopy3DRange"),
- .AllocationCopyToBitmap = (AllocationCopyToBitmapFnPtr)dlsym(
- handle, "rsAllocationCopyToBitmap"),
- .AllocationCreateFromBitmap = (AllocationCreateFromBitmapFnPtr)dlsym(
- handle, "rsAllocationCreateFromBitmap"),
- .AllocationCreateStrided = (AllocationCreateStridedFnPtr)dlsym(
- handle, "rsAllocationCreateStrided"),
- .AllocationCreateTyped = (AllocationCreateTypedFnPtr)dlsym(
- handle, "rsAllocationCreateTyped"),
- .AllocationCubeCreateFromBitmap =
- (AllocationCubeCreateFromBitmapFnPtr)dlsym(
- handle, "rsAllocationCubeCreateFromBitmap"),
- .AllocationElementData = (AllocationElementDataFnPtr)dlsym(
- handle, "rsAllocationElementData"),
- .AllocationElementRead = (AllocationElementReadFnPtr)dlsym(
- handle, "rsAllocationElementRead"),
- .AllocationGenerateMipmaps = (AllocationGenerateMipmapsFnPtr)dlsym(
- handle, "rsAllocationGenerateMipmaps"),
- .AllocationGetPointer =
- (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
- .AllocationGetSurface =
- (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
- .AllocationGetType =
- (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
- .AllocationIoReceive =
- (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
- .AllocationIoSend =
- (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
- .AllocationRead =
- (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
- .AllocationResize1D =
- (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
- .AllocationSetSurface =
- (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
- .AllocationSetupBufferQueue = (AllocationSetupBufferQueueFnPtr)dlsym(
- handle, "rsAllocationSetupBufferQueue"),
- .AllocationShareBufferQueue = (AllocationShareBufferQueueFnPtr)dlsym(
- handle, "rsAllocationShareBufferQueue"),
- .AllocationSyncAll =
- (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
- .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
- .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
- .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
- .ClosureSetGlobal =
- (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
- .ContextCreateVendor =
- (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
- .ContextDeinitToClient = (ContextDeinitToClientFnPtr)dlsym(
- handle, "rsContextDeinitToClient"),
- .ContextDestroy =
- (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
- .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
- .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
- .ContextGetMessage =
- (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
- .ContextInitToClient =
- (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
- .ContextPeekMessage =
- (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
- .ContextSendMessage =
- (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
- .ContextSetCacheDir =
- (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
- .ContextSetPriority =
- (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
- .DeviceCreate = (DeviceCreateFnPtr) nullptr,
- .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
- .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
- .ElementCreate2 =
- (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
- .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
- .ElementGetNativeData =
- (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
- .ElementGetSubElements = (ElementGetSubElementsFnPtr)dlsym(
- handle, "rsaElementGetSubElements"),
- .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
- .InvokeClosureCreate =
- (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
- .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
- .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
- .ScriptBindAllocation =
- (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
- .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
- .ScriptFieldIDCreate =
- (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
- .ScriptForEach = (ScriptForEachFnPtr) nullptr,
- .ScriptForEachMulti =
- (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
- .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
- .ScriptGroup2Create =
- (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
- .ScriptGroupCreate =
- (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
- .ScriptGroupExecute =
- (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
- .ScriptGroupSetInput =
- (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
- .ScriptGroupSetOutput =
- (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
- .ScriptIntrinsicCreate = (ScriptIntrinsicCreateFnPtr)dlsym(
- handle, "rsScriptIntrinsicCreate"),
- .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
- .ScriptInvokeIDCreate =
- (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
- .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
- .ScriptKernelIDCreate =
- (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
- .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
- .ScriptSetTimeZone =
- (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
- .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
- .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
- .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
- .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
- .ScriptSetVarObj =
- (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
- .ScriptSetVarVE =
- (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
- .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
- .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
- .TypeGetNativeData =
- (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
+ .Allocation1DData = (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
+ .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
+ .Allocation1DRead = (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
+ .Allocation2DData = (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
+ .Allocation2DRead = (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
+ .Allocation3DData = (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
+ .Allocation3DRead = (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
+ .AllocationAdapterCreate =
+ (AllocationAdapterCreateFnPtr)dlsym(handle, "rsAllocationAdapterCreate"),
+ .AllocationAdapterOffset =
+ (AllocationAdapterOffsetFnPtr)dlsym(handle, "rsAllocationAdapterOffset"),
+ .AllocationCopy2DRange =
+ (AllocationCopy2DRangeFnPtr)dlsym(handle, "rsAllocationCopy2DRange"),
+ .AllocationCopy3DRange =
+ (AllocationCopy3DRangeFnPtr)dlsym(handle, "rsAllocationCopy3DRange"),
+ .AllocationCopyToBitmap =
+ (AllocationCopyToBitmapFnPtr)dlsym(handle, "rsAllocationCopyToBitmap"),
+ .AllocationCreateFromBitmap =
+ (AllocationCreateFromBitmapFnPtr)dlsym(handle, "rsAllocationCreateFromBitmap"),
+ .AllocationCreateStrided =
+ (AllocationCreateStridedFnPtr)dlsym(handle, "rsAllocationCreateStrided"),
+ .AllocationCreateTyped =
+ (AllocationCreateTypedFnPtr)dlsym(handle, "rsAllocationCreateTyped"),
+ .AllocationCubeCreateFromBitmap = (AllocationCubeCreateFromBitmapFnPtr)dlsym(
+ handle, "rsAllocationCubeCreateFromBitmap"),
+ .AllocationElementData =
+ (AllocationElementDataFnPtr)dlsym(handle, "rsAllocationElementData"),
+ .AllocationElementRead =
+ (AllocationElementReadFnPtr)dlsym(handle, "rsAllocationElementRead"),
+ .AllocationGenerateMipmaps =
+ (AllocationGenerateMipmapsFnPtr)dlsym(handle, "rsAllocationGenerateMipmaps"),
+ .AllocationGetPointer =
+ (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
+ .AllocationGetSurface =
+ (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
+ .AllocationGetType = (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
+ .AllocationIoReceive = (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
+ .AllocationIoSend = (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
+ .AllocationRead = (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
+ .AllocationResize1D = (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
+ .AllocationSetSurface =
+ (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
+ .AllocationSyncAll = (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
+ .AllocationSetupBufferQueue =
+ (AllocationSetupBufferQueueFnPtr)dlsym(handle, "rsAllocationSetupBufferQueue"),
+ .AllocationShareBufferQueue =
+ (AllocationShareBufferQueueFnPtr)dlsym(handle, "rsAllocationShareBufferQueue"),
+ .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
+ .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
+ .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
+ .ClosureSetGlobal = (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
+ .ContextCreateVendor = (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
+ .ContextDeinitToClient =
+ (ContextDeinitToClientFnPtr)dlsym(handle, "rsContextDeinitToClient"),
+ .ContextDestroy = (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
+ .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
+ .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
+ .ContextGetMessage = (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
+ .ContextInitToClient = (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
+ .ContextPeekMessage = (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
+ .ContextSendMessage = (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
+ .ContextSetPriority = (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
+ .ContextSetCacheDir = (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
+ .DeviceCreate = (DeviceCreateFnPtr) nullptr,
+ .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
+ .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
+ .ElementCreate2 = (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
+ .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
+ .ElementGetNativeData =
+ (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
+ .ElementGetSubElements =
+ (ElementGetSubElementsFnPtr)dlsym(handle, "rsaElementGetSubElements"),
+ .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
+ .InvokeClosureCreate = (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
+ .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
+ .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
+ .ScriptBindAllocation =
+ (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
+ .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
+ .ScriptFieldIDCreate = (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
+ .ScriptForEach = (ScriptForEachFnPtr) nullptr,
+ .ScriptForEachMulti = (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
+ .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
+ .ScriptGroup2Create = (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
+ .ScriptGroupCreate = (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
+ .ScriptGroupExecute = (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
+ .ScriptGroupSetInput = (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
+ .ScriptGroupSetOutput =
+ (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
+ .ScriptIntrinsicCreate =
+ (ScriptIntrinsicCreateFnPtr)dlsym(handle, "rsScriptIntrinsicCreate"),
+ .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
+ .ScriptInvokeIDCreate =
+ (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
+ .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
+ .ScriptKernelIDCreate =
+ (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
+ .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
+ .ScriptSetTimeZone = (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
+ .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
+ .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
+ .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
+ .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
+ .ScriptSetVarObj = (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
+ .ScriptSetVarVE = (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
+ .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
+ .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
+ .TypeGetNativeData = (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
};
return dispatchHal;
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 52f5e4f..53ceb0d 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -68,9 +68,9 @@
typedef ::android::hardware::sensors::V1_0::MetaDataEventType MetaDataEventType;
*dst = {
- .sensorHandle = src.sensor,
- .sensorType = (SensorType)src.type,
- .timestamp = src.timestamp
+ .timestamp = src.timestamp,
+ .sensorHandle = src.sensor,
+ .sensorType = (SensorType)src.type,
};
switch (dst->sensorType) {
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index 710835f..c13eaf2 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -21,6 +21,7 @@
shared_libs: [
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
+ "libbase",
"libcutils",
"libfmq",
"libhidlbase",
@@ -28,6 +29,7 @@
"libpower",
"libutils",
],
+ cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_binary {
@@ -45,7 +47,6 @@
],
init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
- cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_library_headers {
@@ -66,4 +67,7 @@
export_header_lib_headers: [
"android.hardware.sensors@2.0-multihal.header",
],
+ shared_libs: [
+ "libutils",
+ ],
}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 5aa3b3d..49c5a0d 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -20,10 +20,13 @@
#include <android/hardware/sensors/2.0/types.h>
+#include <android-base/file.h>
#include "hardware_legacy/power.h"
#include <dlfcn.h>
+#include <cinttypes>
+#include <cmath>
#include <fstream>
#include <functional>
#include <thread>
@@ -35,9 +38,14 @@
namespace implementation {
using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
/**
* Set the subhal index as first byte of sensor handle and return this modified version.
*
@@ -46,30 +54,45 @@
*
* @return The modified sensor handle.
*/
-uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) {
- return sensorHandle | (subHalIndex << 24);
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+ return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+/**
+ * Extract the subHalIndex from sensorHandle.
+ *
+ * @param sensorHandle The sensorHandle to extract from.
+ *
+ * @return The subhal index.
+ */
+size_t extractSubHalIndex(int32_t sensorHandle) {
+ return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
+}
+
+/**
+ * Convert nanoseconds to milliseconds.
+ *
+ * @param nanos The nanoseconds input.
+ *
+ * @return The milliseconds count.
+ */
+int64_t msFromNs(int64_t nanos) {
+ constexpr int64_t nanosecondsInAMillsecond = 1000000;
+ return nanos / nanosecondsInAMillsecond;
}
HalProxy::HalProxy() {
const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
initializeSubHalListFromConfigFile(kMultiHalConfigFile);
- initializeSubHalCallbacksAndSensorList();
+ init();
}
HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
- initializeSubHalCallbacksAndSensorList();
+ init();
}
HalProxy::~HalProxy() {
- {
- std::lock_guard<std::mutex> lockGuard(mEventQueueWriteMutex);
- mPendingWritesRun = false;
- mEventQueueWriteCV.notify_one();
- }
- if (mPendingWritesThread.joinable()) {
- mPendingWritesThread.join();
- }
- // TODO: Cleanup wakeup thread once it is implemented
+ stopThreads();
}
Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -105,6 +128,9 @@
}
Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
return getSubHalForSensorHandle(sensorHandle)
->activate(clearSubHalIndex(sensorHandle), enabled);
}
@@ -115,8 +141,18 @@
const sp<ISensorsCallback>& sensorsCallback) {
Result result = Result::OK;
- // TODO: clean up sensor requests, if not already done elsewhere through a death recipient, and
- // clean up any other resources that exist (FMQs, flags, threads, etc.)
+ stopThreads();
+ resetSharedWakelock();
+
+ // So that the pending write events queue can be cleared safely and when we start threads
+ // again we do not get new events until after initialize resets the subhals.
+ disableAllSensors();
+
+ // Clears the queue if any events were pending write before.
+ mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
+
+ // Clears previously connected dynamic sensors
+ mDynamicSensors.clear();
mDynamicSensorsCallback = sensorsCallback;
@@ -124,23 +160,31 @@
mEventQueue =
std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
- // Create the EventFlag that is used to signal to the framework that sensor events have been
- // written to the Event FMQ
- if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
- result = Result::BAD_VALUE;
- }
-
// Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
// events have been successfully read and handled by the framework.
mWakeLockQueue =
std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+ if (mEventQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ }
+ if (mWakelockQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mWakelockQueueFlag);
+ }
+ if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
+ if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
result = Result::BAD_VALUE;
}
+ mThreadsRun.store(true);
+
mPendingWritesThread = std::thread(startPendingWritesThread, this);
- // TODO: start threads to read wake locks.
+ mWakelockThread = std::thread(startWakelockThread, this);
for (size_t i = 0; i < mSubHalList.size(); i++) {
auto subHal = mSubHalList[i];
@@ -153,16 +197,24 @@
}
}
+ mCurrentOperationMode = OperationMode::NORMAL;
+
return result;
}
Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
int64_t maxReportLatencyNs) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
return getSubHalForSensorHandle(sensorHandle)
->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
}
Return<Result> HalProxy::flush(int32_t sensorHandle) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
}
@@ -176,6 +228,9 @@
}
if (result == Result::OK) {
Event subHalEvent = event;
+ if (!isSubHalIndexValid(event.sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
}
@@ -213,8 +268,43 @@
return Return<void>();
}
-Return<void> HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec<hidl_string>& /* args */) {
- // TODO: output debug information
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+ if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+ ALOGE("%s: missing fd for writing", __FUNCTION__);
+ return Void();
+ }
+
+ android::base::borrowed_fd writeFd = dup(fd->data[0]);
+
+ std::ostringstream stream;
+ stream << "===HalProxy===" << std::endl;
+ stream << "Internal values:" << std::endl;
+ stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
+ int64_t now = getTimeNow();
+ stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
+ << " ms ago" << std::endl;
+ stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
+ << " ms ago" << std::endl;
+ // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
+ stream << " Wakelock ref count: " << mWakelockRefCount << std::endl;
+ stream << " Size of pending write events queue: " << mPendingWriteEventsQueue.size()
+ << std::endl;
+ if (!mPendingWriteEventsQueue.empty()) {
+ stream << " Size of events list on front of pending writes queue: "
+ << mPendingWriteEventsQueue.front().first.size() << std::endl;
+ }
+ stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
+ stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
+ stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
+ for (ISensorsSubHal* subHal : mSubHalList) {
+ stream << " Name: " << subHal->getName() << std::endl;
+ stream << " Debug dump: " << std::endl;
+ android::base::WriteStringToFd(stream.str(), writeFd);
+ subHal->debug(fd, {});
+ stream.str("");
+ stream << std::endl;
+ }
+ android::base::WriteStringToFd(stream.str(), writeFd);
return Return<void>();
}
@@ -240,7 +330,7 @@
Return<void> HalProxy::onDynamicSensorsDisconnected(
const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
- // TODO: Block this call until all pending events are flushed from queue
+ // TODO(b/143302327): Block this call until all pending events are flushed from queue
std::vector<int32_t> sensorHandles;
{
std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
@@ -310,7 +400,7 @@
ALOGE("SubHal sensorHandle's first byte was not 0");
} else {
ALOGV("Loaded sensor: %s", sensor.name.c_str());
- sensor.sensorHandle |= (subHalIndex << 24);
+ sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
setDirectChannelFlags(&sensor, subHal);
mSensors[sensor.sensorHandle] = sensor;
}
@@ -322,41 +412,82 @@
}
}
-void HalProxy::initializeSubHalCallbacksAndSensorList() {
+void HalProxy::init() {
initializeSubHalCallbacks();
initializeSensorList();
}
+void HalProxy::stopThreads() {
+ mThreadsRun.store(false);
+ if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
+ size_t numToRead = mEventQueue->availableToRead();
+ std::vector<Event> events(numToRead);
+ mEventQueue->read(events.data(), numToRead);
+ mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
+ }
+ if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
+ uint32_t kZero = 0;
+ mWakeLockQueue->write(&kZero);
+ mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+ }
+ mWakelockCV.notify_one();
+ mEventQueueWriteCV.notify_one();
+ if (mPendingWritesThread.joinable()) {
+ mPendingWritesThread.join();
+ }
+ if (mWakelockThread.joinable()) {
+ mWakelockThread.join();
+ }
+}
+
+void HalProxy::disableAllSensors() {
+ for (const auto& sensorEntry : mSensors) {
+ int32_t sensorHandle = sensorEntry.first;
+ activate(sensorHandle, false /* enabled */);
+ }
+ std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
+ for (const auto& sensorEntry : mDynamicSensors) {
+ int32_t sensorHandle = sensorEntry.first;
+ activate(sensorHandle, false /* enabled */);
+ }
+}
+
void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
halProxy->handlePendingWrites();
}
void HalProxy::handlePendingWrites() {
- // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one.
+ // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
+ // one.
std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
- while (mPendingWritesRun) {
+ while (mThreadsRun.load()) {
mEventQueueWriteCV.wait(
- lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; });
- if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) {
- std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front();
+ lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+ size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
size_t eventQueueSize = mEventQueue->getQuantumCount();
size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
lock.unlock();
- // TODO: Find a way to interrup writeBlocking if the thread should exit
- // so we don't have to wait for timeout on framework restarts.
if (!mEventQueue->writeBlocking(
pendingWriteEvents.data(), numToWrite,
static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
- kWakelockTimeoutNs, mEventQueueFlag)) {
+ kPendingWriteTimeoutNs, mEventQueueFlag)) {
ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
- } else {
- mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+ if (numWakeupEvents > 0) {
+ if (pendingWriteEvents.size() > eventQueueSize) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+ } else {
+ decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+ }
+ }
}
lock.lock();
if (pendingWriteEvents.size() > eventQueueSize) {
- // TODO: Check if this erase operation is too inefficient. It will copy all the
- // events ahead of it down to fill gap off array at front after the erase.
+ // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
+ // all the events ahead of it down to fill gap off array at front after the erase.
pendingWriteEvents.erase(pendingWriteEvents.begin(),
pendingWriteEvents.begin() + eventQueueSize);
} else {
@@ -366,15 +497,66 @@
}
}
-void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) {
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+ halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+ std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+ while (mThreadsRun.load()) {
+ mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ int64_t timeLeft;
+ if (sharedWakelockDidTimeout(&timeLeft)) {
+ resetSharedWakelock();
+ } else {
+ uint32_t numWakeLocksProcessed;
+ lock.unlock();
+ bool success = mWakeLockQueue->readBlocking(
+ &numWakeLocksProcessed, 1, 0,
+ static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+ lock.lock();
+ if (success) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ static_cast<size_t>(numWakeLocksProcessed));
+ }
+ }
+ }
+ }
+ resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+ bool didTimeout;
+ int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+ if (duration > kWakelockTimeoutNs) {
+ didTimeout = true;
+ } else {
+ didTimeout = false;
+ *timeLeft = kWakelockTimeoutNs - duration;
+ }
+ return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+ mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock) {
size_t numToWrite = 0;
std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+ if (wakelock.isLocked()) {
+ incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+ }
if (mPendingWriteEventsQueue.empty()) {
numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
if (numToWrite > 0) {
if (mEventQueue->write(events.data(), numToWrite)) {
- // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more
- // writes immediately
+ // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
+ // in more writes immediately
mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
} else {
numToWrite = 0;
@@ -382,30 +564,39 @@
}
}
if (numToWrite < events.size()) {
- // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework
- // stalls
- mPendingWriteEventsQueue.push(
- std::vector<Event>(events.begin() + numToWrite, events.end()));
+ // TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if
+ // framework stalls
+ std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+ mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
mEventQueueWriteCV.notify_one();
}
}
-// TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal
-// index for better tracking.
-
-void HalProxy::incrementRefCountAndMaybeAcquireWakelock() {
- std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex);
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart /* = nullptr */) {
+ if (!mThreadsRun.load()) return false;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
if (mWakelockRefCount == 0) {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+ mWakelockCV.notify_one();
}
- mWakelockRefCount++;
+ mWakelockTimeoutStartTime = getTimeNow();
+ mWakelockRefCount += delta;
+ if (timeoutStart != nullptr) {
+ *timeoutStart = mWakelockTimeoutStartTime;
+ }
+ return true;
}
-void HalProxy::decrementRefCountAndMaybeReleaseWakelock() {
- std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex);
- mWakelockRefCount--;
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart /* = -1 */) {
+ if (!mThreadsRun.load()) return;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+ if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+ mWakelockRefCount -= std::min(mWakelockRefCount, delta);
if (mWakelockRefCount == 0) {
- release_wake_lock(kWakeLockName);
+ release_wake_lock(kWakelockName);
}
}
@@ -423,20 +614,35 @@
}
}
-ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) {
- return mSubHalList[static_cast<size_t>(sensorHandle >> 24)];
+ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
+ return mSubHalList[extractSubHalIndex(sensorHandle)];
}
-uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) {
+bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
+ return extractSubHalIndex(sensorHandle) < mSubHalList.size();
+}
+
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+ size_t numWakeupEvents = 0;
+ for (size_t i = 0; i < n; i++) {
+ int32_t sensorHandle = events[i].sensorHandle;
+ if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+ numWakeupEvents++;
+ }
+ }
+ return numWakeupEvents;
+}
+
+int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
return sensorHandle & (~kSensorHandleSubHalIndexMask);
}
-bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) {
+bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
}
void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
- (void)wakelock;
+ if (events.empty() || !mHalProxy->areThreadsRunning()) return;
size_t numWakeupEvents;
std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
if (numWakeupEvents > 0) {
@@ -450,8 +656,7 @@
" w/ index %zu.",
mSubHalIndex);
}
-
- mHalProxy->postEventsToMessageQueue(processedEvents);
+ mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
}
ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
@@ -461,13 +666,13 @@
std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
size_t* numWakeupEvents) const {
- std::vector<Event> eventsOut;
*numWakeupEvents = 0;
+ std::vector<Event> eventsOut;
for (Event event : events) {
event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
eventsOut.push_back(event);
- if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) !=
- 0) {
+ const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
+ if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
(*numWakeupEvents)++;
}
}
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
index 0430fa3..d85d4a7 100644
--- a/sensors/2.0/multihal/ScopedWakelock.cpp
+++ b/sensors/2.0/multihal/ScopedWakelock.cpp
@@ -22,18 +22,22 @@
namespace V2_0 {
namespace implementation {
+int64_t getTimeNow() {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+}
+
ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
: mRefCounter(refCounter), mLocked(locked) {
- // TODO: Move this implementation into HalProxy object instead
if (mLocked) {
- mRefCounter->incrementRefCountAndMaybeAcquireWakelock();
+ mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
}
}
ScopedWakelock::~ScopedWakelock() {
- // TODO: Move this implementation into HalProxy object instead
if (mLocked) {
- mRefCounter->decrementRefCountAndMaybeReleaseWakelock();
+ mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
}
}
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
index 1671689..a4da3b0 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -1,6 +1,7 @@
service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
class hal
user system
- group system
+ group system wakelock
+ writepid /dev/cpuset/system-background/tasks
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index 47571a6..b1dd737 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -16,9 +16,11 @@
#pragma once
+#include "ScopedWakelock.h"
#include "SubHal.h"
#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
#include <fmq/MessageQueue.h>
#include <hardware_legacy/power.h>
#include <hidl/MQDescriptor.h>
@@ -30,6 +32,7 @@
#include <mutex>
#include <queue>
#include <thread>
+#include <utility>
namespace android {
namespace hardware {
@@ -100,45 +103,41 @@
Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
int32_t subHalIndex);
- // Below methods follow IScopedWakelockRefCounter
-
- /**
- * Increment ref count and maybe acquire wakelock.
- */
- void incrementRefCountAndMaybeAcquireWakelock() override;
-
- /**
- * Decrement ref count and maybe release wakelock.
- */
- void decrementRefCountAndMaybeReleaseWakelock() override;
-
// Below methods are for HalProxyCallback
/**
* Post events to the event message queue if there is room to write them. Otherwise post the
- * remaining events to a background thread for a blocking write with a 5 second timeout.
+ * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+ * timeout.
*
* @param events The list of events to post to the message queue.
+ * @param numWakeupEvents The number of wakeup events in events.
+ * @param wakelock The wakelock associated with this post of events.
*/
- void postEventsToMessageQueue(const std::vector<Event>& events);
+ void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock);
/**
- * Get the SensorInfo object associated with the sensorHandle.
+ * Get the sensor info associated with that sensorHandle.
*
- * @param sensorHandle The sensorHandle for the sensor.
+ * @param sensorHandle The sensor handle.
*
- * @return The sensor info for the sensor.
+ * @return The sensor info object in the mapping.
*/
- const SensorInfo& getSensorInfo(uint32_t sensorHandle) const {
- return mSensors.at(sensorHandle);
- }
+ const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
+
+ bool areThreadsRunning() { return mThreadsRun.load(); }
+
+ // Below methods are from IScopedWakelockRefCounter interface
+ bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) override;
+
+ void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
private:
using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
- const char* kWakeLockName = "SensorsHAL_WAKEUP";
-
/**
* The Event FMQ where sensor events are written
*/
@@ -150,9 +149,13 @@
std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
/**
- * Event Flag to signal to the framework when sensor events are available to be read
+ * Event Flag to signal to the framework when sensor events are available to be read and to
+ * interrupt event queue blocking write.
*/
- EventFlag* mEventQueueFlag;
+ EventFlag* mEventQueueFlag = nullptr;
+
+ //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
+ EventFlag* mWakelockQueueFlag = nullptr;
/**
* Callback to the sensors framework to inform it that new sensors have been added or removed.
@@ -174,10 +177,10 @@
* The subhal index is encoded in the first byte of the sensor handle and the remaining
* bytes are generated by the subhal to identify the sensor.
*/
- std::map<uint32_t, SensorInfo> mSensors;
+ std::map<int32_t, SensorInfo> mSensors;
//! Map of the dynamic sensors that have been added to halproxy.
- std::map<uint32_t, SensorInfo> mDynamicSensors;
+ std::map<int32_t, SensorInfo> mDynamicSensors;
//! The current operation mode for all subhals.
OperationMode mCurrentOperationMode = OperationMode::NORMAL;
@@ -185,23 +188,17 @@
//! The single subHal that supports directChannel reporting.
ISensorsSubHal* mDirectChannelSubHal = nullptr;
- //! The mutex for the event queue.
- std::mutex mEventQueueMutex;
-
//! The timeout for each pending write on background thread for events.
- static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
-
- //! The scoped wakelock ref count.
- size_t mWakelockRefCount = 0;
-
- //! The mutex guarding the mWakelockRefCount variable
- std::mutex mWakelockRefCountMutex;
+ static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
//! The bit mask used to get the subhal index from a sensor handle.
- static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+ static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
- //! The events that were not able to be written to fmq right away
- std::queue<std::vector<Event>> mPendingWriteEventsQueue;
+ /**
+ * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+ * which are waiting to be written to the events fmq in the background thread.
+ */
+ std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
//! The mutex protecting writing to the fmq and the pending events queue
std::mutex mEventQueueWriteMutex;
@@ -212,12 +209,32 @@
//! The thread object ptr that handles pending writes
std::thread mPendingWritesThread;
- //! The bool indicating whether to end the pending writes background thread or not
- bool mPendingWritesRun = true;
+ //! The thread object that handles wakelocks
+ std::thread mWakelockThread;
+
+ //! The bool indicating whether to end the threads started in initialize
+ std::atomic_bool mThreadsRun = true;
//! The mutex protecting access to the dynamic sensors added and removed methods.
std::mutex mDynamicSensorsMutex;
+ // WakelockRefCount membar vars below
+
+ //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+ //! acquisitions
+ std::recursive_mutex mWakelockMutex;
+
+ std::condition_variable_any mWakelockCV;
+
+ //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+ size_t mWakelockRefCount = 0;
+
+ int64_t mWakelockTimeoutStartTime = getTimeNow();
+
+ int64_t mWakelockTimeoutResetTime = getTimeNow();
+
+ const char* kWakelockName = "SensorsHAL_WAKEUP";
+
/**
* Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
* listed in a config file.
@@ -236,9 +253,19 @@
void initializeSensorList();
/**
- * Calls the above two helper methods which are shared in both ctors.
+ * Calls the helper methods that all ctors use.
*/
- void initializeSubHalCallbacksAndSensorList();
+ void init();
+
+ /**
+ * Stops all threads by setting the threads running flag to false and joining to them.
+ */
+ void stopThreads();
+
+ /**
+ * Disable all the sensors observed by the HalProxy.
+ */
+ void disableAllSensors();
/**
* Starts the thread that handles pending writes to event fmq.
@@ -251,6 +278,31 @@
void handlePendingWrites();
/**
+ * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+ * framework and timing out wakelocks.
+ *
+ * @param halProxy The HalProxy object pointer.
+ */
+ static void startWakelockThread(HalProxy* halProxy);
+
+ //! Handles the wakelocks.
+ void handleWakelocks();
+
+ /**
+ * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+ * unmodified if timeout occurred.
+ *
+ * @return true if the shared wakelock has been held passed the timeout and should be released
+ */
+ bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+ /**
+ * Reset all the member variables associated with the wakelock ref count and maybe release
+ * the shared wakelock.
+ */
+ void resetSharedWakelock();
+
+ /**
* Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
* subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
* direct channel enabled sensor seen.
@@ -267,7 +319,26 @@
*
* @param sensorHandle The handle used to identify a sensor in one of the subhals.
*/
- ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle);
+ ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
+
+ /**
+ * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
+ *
+ * @param sensorHandle The sensor handle to check.
+ *
+ * @return true if sensorHandles's subhal index byte is valid.
+ */
+ bool isSubHalIndexValid(int32_t sensorHandle);
+
+ /**
+ * Count the number of wakeup events in the first n events of the vector.
+ *
+ * @param events The vector of Event objects.
+ * @param n The end index not inclusive of events to consider.
+ *
+ * @return The number of wakeup events of the considered events.
+ */
+ size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
/*
* Clear out the subhal index bytes from a sensorHandle.
@@ -276,14 +347,14 @@
*
* @return The modified version of the sensor handle.
*/
- static uint32_t clearSubHalIndex(uint32_t sensorHandle);
+ static int32_t clearSubHalIndex(int32_t sensorHandle);
/**
* @param sensorHandle The sensor handle to modify.
*
* @return true if subHalIndex byte of sensorHandle is zeroed.
*/
- static bool subHalIndexIsClear(uint32_t sensorHandle);
+ static bool subHalIndexIsClear(int32_t sensorHandle);
};
/**
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
index a151f15..aa6d9db 100644
--- a/sensors/2.0/multihal/include/ScopedWakelock.h
+++ b/sensors/2.0/multihal/include/ScopedWakelock.h
@@ -16,7 +16,7 @@
#pragma once
-#include <mutex>
+#include <android/hardware/sensors/2.0/types.h>
namespace android {
namespace hardware {
@@ -24,10 +24,36 @@
namespace V2_0 {
namespace implementation {
-class IScopedWakelockRefCounter {
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+ static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
public:
- virtual void incrementRefCountAndMaybeAcquireWakelock() = 0;
- virtual void decrementRefCountAndMaybeReleaseWakelock() = 0;
+ /**
+ * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+ * from 0 then return the time of incrementing back to caller.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+ * set in the function or nullptr if not specified.
+ *
+ * @return true if successfully incremented the wakelock ref count.
+ */
+ virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) = 0;
+ /**
+ * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The timestamp in ns that the calling context kept track of when
+ * incrementing the ref count or -1 by default
+ */
+ virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart = -1) = 0;
// Virtual dtor needed for compilation success
virtual ~IScopedWakelockRefCounter(){};
};
@@ -64,6 +90,7 @@
private:
friend class HalProxyCallback;
IScopedWakelockRefCounter* mRefCounter;
+ int64_t mCreatedAtTimeNs;
bool mLocked;
ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
ScopedWakelock(const ScopedWakelock&) = delete;
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
index e7eedaa..92ae3a6 100644
--- a/sensors/2.0/multihal/include/SubHal.h
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -130,11 +130,13 @@
virtual const std::string getName() = 0;
/**
- * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the
- * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in
- * order to communicate with the HalProxy. Method will be called anytime the sensors framework
- * restarts. Therefore, this method will be responsible for reseting the state of the subhal and
- * cleaning up and reallocating any previously allocated data.
+ * This is the first method invoked on the sub-HAL after it's allocated through
+ * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+ * retain the callback given in order to communicate with the HalProxy. Method will be called
+ * anytime the sensors framework restarts. Therefore, this method will be responsible for
+ * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+ * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+ * as well.
*
* @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
* changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index aa44687..e7f9499 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -27,6 +27,7 @@
"android.hardware.sensors@2.0",
"libcutils",
"libfmq",
+ "libhardware",
"libhidlbase",
"liblog",
"libpower",
@@ -35,6 +36,9 @@
static_libs: [
"android.hardware.sensors@2.0-HalProxy",
],
+ cflags: [
+ "-DLOG_TAG=\"FakeSubHal\""
+ ],
}
cc_library {
@@ -79,12 +83,17 @@
shared_libs: [
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
+ "libbase",
"libcutils",
"libfmq",
+ "libhardware",
"libhidlbase",
"liblog",
"libpower",
"libutils",
],
test_suites: ["device-tests"],
+ cflags: [
+ "-DLOG_TAG=\"HalProxyUnitTests\"",
+ ],
}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
index c8fbb73..1fd35d1 100644
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -29,6 +29,7 @@
namespace {
+using ::android::hardware::EventFlag;
using ::android::hardware::hidl_vec;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
@@ -36,7 +37,9 @@
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
using ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::HalProxy;
using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
@@ -123,6 +126,16 @@
void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
size_t enabledSubHalIndex);
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
/**
* Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
* which is a wakeup type sensor.
@@ -269,10 +282,8 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -288,10 +299,8 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -306,17 +315,24 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
std::vector<Event> events{makeProximityEvent()};
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+ readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostMultipleWakeupEvents) {
@@ -325,17 +341,24 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+ readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostEventsMultipleSubhals) {
@@ -344,10 +367,8 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -367,27 +388,26 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal1.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
- Event eventOut;
- // writeblock 1 event out of queue, timeout for half a second
- EXPECT_TRUE(eventQueue->readBlocking(&eventOut, 1, 500000000));
+ // readblock a full queue size worth of events out of queue, timeout for half a second
+ EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
- // Sleep for a half second so that blocking write has time complete in background thread
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ // proxy background thread should have wrote remaining events when it saw space
+ EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
- // proxy background thread should have wrote last event when it saw space
- EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+ EXPECT_EQ(eventQueue->availableToRead(), 0);
}
TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
@@ -396,10 +416,8 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -414,16 +432,14 @@
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
}
-TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) {
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 6;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -431,13 +447,145 @@
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal.postEvents(events, false /* wakeup */);
- // Sleep for a half second so that background thread has time to attempt it's blocking write
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ // Destructing HalProxy object with events on the background thread
+}
- // Should see a 5 second wait for blocking write timeout here
+TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
- // Should be one events left on pending writes queue here and proxy will destruct
- // If this TEST completes then it was a success, if it hangs we will see a crash
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events{makeProximityEvent()};
+ subHal.postEvents(events, true /* wakeup */);
+
+ // Not sending any acks back through wakeLockQueue
+
+ // Destructing HalProxy object with unacked wakeup events posted
+}
+
+TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 10;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal.postEvents(events, false /* wakeup */);
+
+ eventQueue = makeEventFMQ(kQueueSize);
+ wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+ // Small sleep so that pending writes thread has a change to hit writeBlocking call.
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ Event eventOut;
+ EXPECT_FALSE(eventQueue->read(&eventOut));
+}
+
+TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events{makeProximityEvent()};
+ subHal.postEvents(events, true /* wakeup */);
+
+ // Not sending any acks back through wakeLockQueue
+
+ eventQueue = makeEventFMQ(kQueueSize);
+ wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+}
+
+TEST(HalProxyTest, InitializeManyTimesInARow) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumTimesToInit = 100;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+
+ for (size_t i = 0; i < kNumTimesToInit; i++) {
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+ }
+}
+
+TEST(HalProxyTest, OperationModeResetOnInitialize) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.setOperationMode(OperationMode::DATA_INJECTION);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ Event event = makeAccelerometerEvent();
+ // Should not be able to inject a non AdditionInfo type event because operation mode should
+ // have been reset to NORMAL
+ EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumSensors = 5;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ HalProxy proxy(subHals);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToAttemptToRemove;
+ makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+ sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> nonDynamicSensorHandles;
+ for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+ nonDynamicSensorHandles.push_back(sensorHandle);
+ }
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
+
+ // Should not have received the sensorHandles for any dynamic sensors that were removed since
+ // all of them should have been removed in the second initialize call.
+ EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
}
TEST(HalProxyTest, DynamicSensorsConnectedTest) {
@@ -445,9 +593,8 @@
AddAndRemoveDynamicSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue = std::make_unique<EventMessageQueue>(0, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(0, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
std::vector<SensorInfo> sensorsToConnect;
std::vector<int32_t> sensorHandlesToExpect;
@@ -474,9 +621,8 @@
AddAndRemoveDynamicSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue = std::make_unique<EventMessageQueue>(0, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(0, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
std::vector<SensorInfo> sensorsToConnect;
std::vector<int32_t> sensorHandlesToExpect;
@@ -517,6 +663,67 @@
}
}
+TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
+ constexpr size_t kNumSubHals = 3;
+ constexpr size_t kQueueSize = 5;
+ int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
+ std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
+ std::vector<ISensorsSubHal*> subHals;
+ for (const auto& subHal : subHalObjs) {
+ subHals.push_back((ISensorsSubHal*)(&subHal));
+ }
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ // Initialize for the injectSensorData call so callback postEvents is valid
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ // For testing proxy.injectSensorData properly
+ proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
+ EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
+ EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
+ EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
+ Event event;
+ event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
+ EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
+ constexpr size_t kQueueSize = 5;
+ constexpr int32_t subhal1Index = 0;
+ constexpr int32_t subhal2Index = 1;
+ AllSensorsSubHal subhal1;
+ AllSensorsSubHal subhal2;
+ std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ int32_t sensorHandleToPost = 0x00000001;
+ Event eventIn = makeAccelerometerEvent();
+ eventIn.sensorHandle = sensorHandleToPost;
+ std::vector<Event> eventsToPost{eventIn};
+ subhal1.postEvents(eventsToPost, false);
+
+ Event eventOut;
+ EXPECT_TRUE(eventQueue->read(&eventOut));
+
+ EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
+
+ subhal2.postEvents(eventsToPost, false);
+
+ EXPECT_TRUE(eventQueue->read(&eventOut));
+
+ EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
+}
+
// Helper implementations follow
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
const std::vector<SensorInfo>& subHalSensorsList) {
@@ -548,6 +755,31 @@
}
}
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag) {
+ uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+ wakelockQueue->write(&numEventsUInt32);
+ wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag) {
+ constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+ std::vector<Event> events(numEvents);
+ return eventQueue->readBlocking(events.data(), numEvents,
+ static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+ static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+ kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
+ return std::make_unique<EventMessageQueue>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+ return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
Event makeProximityEvent() {
Event event;
event.timestamp = 0xFF00FF00;
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
index 4d53665..de89a00 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
@@ -16,6 +16,7 @@
#include "Sensor.h"
+#include <hardware/sensors.h>
#include <utils/SystemClock.h>
#include <cmath>
@@ -31,14 +32,21 @@
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorStatus;
-static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
-
-Sensor::Sensor(ISensorsEventCallback* callback)
+Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: mIsEnabled(false),
mSamplingPeriodNs(0),
mLastSampleTimeNs(0),
mCallback(callback),
mMode(OperationMode::NORMAL) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ constexpr float kDefaultMaxDelayUs = 1000 * 1000;
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
mRunThread = std::thread(startThread, this);
}
@@ -171,8 +179,10 @@
return result;
}
-OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
- : Sensor(callback), mPreviousEventSet(false) {}
+OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
+ mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
+}
void OnChangeSensor::activate(bool enable) {
Sensor::activate(enable);
@@ -196,175 +206,139 @@
return outputEvents;
}
-AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(sensorHandle, callback) {
+ mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Accel Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::ACCELEROMETER;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
mSensorInfo.maxRange = 78.4f; // +/- 8g
mSensorInfo.resolution = 1.52e-5;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 20 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
-};
+ mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
+}
+
+std::vector<Event> AccelSensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = -9.815;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : Sensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Pressure Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::PRESSURE;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
mSensorInfo.maxRange = 1100.0f; // hPa
mSensorInfo.resolution = 0.005f; // hPa
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 100 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = 0;
-};
+}
MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : Sensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Magnetic Field Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::MAGNETIC_FIELD;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
mSensorInfo.maxRange = 1300.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 20 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = 0;
-};
+}
LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Light Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::LIGHT;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
mSensorInfo.maxRange = 43000.0f;
mSensorInfo.resolution = 10.0f;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 200 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-};
+}
ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Proximity Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::PROXIMITY;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
mSensorInfo.maxRange = 5.0f;
mSensorInfo.resolution = 1.0f;
mSensorInfo.power = 0.012f; // mA
mSensorInfo.minDelay = 200 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags =
- static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP);
-};
+ mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+}
-GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Gyro Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::GYROSCOPE;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 2.5f * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = 0;
-};
+}
+
+std::vector<Event> GyroSensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = 0;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Ambient Temp Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
mSensorInfo.maxRange = 80.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-};
+}
DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Device Temp Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::TEMPERATURE;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
mSensorInfo.maxRange = 80.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
}
RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
ISensorsEventCallback* callback)
- : OnChangeSensor(callback) {
- mSensorInfo.sensorHandle = sensorHandle;
+ : OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Relative Humidity Sensor";
- mSensorInfo.vendor = "Vendor String";
- mSensorInfo.version = 1;
mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
- mSensorInfo.typeAsString = "";
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
mSensorInfo.maxRange = 100.0f;
mSensorInfo.resolution = 0.1f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
- mSensorInfo.maxDelay = kDefaultMaxDelayUs;
- mSensorInfo.fifoReservedEventCount = 0;
- mSensorInfo.fifoMaxEventCount = 0;
- mSensorInfo.requiredPermission = "";
- mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
}
} // namespace implementation
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
index 980ea54..60f5d3d 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
@@ -45,7 +45,7 @@
class Sensor {
public:
- Sensor(ISensorsEventCallback* callback);
+ Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
virtual ~Sensor();
const SensorInfo& getSensorInfo() const;
@@ -81,7 +81,7 @@
class OnChangeSensor : public Sensor {
public:
- OnChangeSensor(ISensorsEventCallback* callback);
+ OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
virtual void activate(bool enable) override;
@@ -93,14 +93,40 @@
bool mPreviousEventSet;
};
-class AccelSensor : public Sensor {
+class ContinuousSensor : public Sensor {
public:
- AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+ ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
-class GyroSensor : public Sensor {
+class AccelSensor : public ContinuousSensor {
+ public:
+ AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ std::vector<Event> readEvents() override;
+};
+
+class GyroSensor : public ContinuousSensor {
public:
GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ std::vector<Event> readEvents() override;
+};
+
+class DeviceTempSensor : public ContinuousSensor {
+ public:
+ DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public ContinuousSensor {
+ public:
+ PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public ContinuousSensor {
+ public:
+ MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class AmbientTempSensor : public OnChangeSensor {
@@ -108,21 +134,6 @@
AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
-class DeviceTempSensor : public OnChangeSensor {
- public:
- DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class PressureSensor : public Sensor {
- public:
- PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class MagnetometerSensor : public Sensor {
- public:
- MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
class LightSensor : public OnChangeSensor {
public:
LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
index cf3ae75..ff5ff38 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -158,6 +158,7 @@
Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
mCallback = halProxyCallback;
+ setOperationMode(OperationMode::NORMAL);
return Result::OK;
}
@@ -171,11 +172,11 @@
AddSensor<GyroSensor>();
AddSensor<MagnetometerSensor>();
AddSensor<PressureSensor>();
+ AddSensor<DeviceTempSensor>();
}
OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
AddSensor<AmbientTempSensor>();
- AddSensor<DeviceTempSensor>();
AddSensor<LightSensor>();
AddSensor<ProximitySensor>();
AddSensor<RelativeHumiditySensor>();
@@ -186,8 +187,8 @@
AddSensor<GyroSensor>();
AddSensor<MagnetometerSensor>();
AddSensor<PressureSensor>();
- AddSensor<AmbientTempSensor>();
AddSensor<DeviceTempSensor>();
+ AddSensor<AmbientTempSensor>();
AddSensor<LightSensor>();
AddSensor<ProximitySensor>();
AddSensor<RelativeHumiditySensor>();
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 1cad913..e63faa2 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -147,8 +147,8 @@
.width = size,
.height = 1,
.layerCount = 1,
- .usage = kBufferUsage,
.format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
+ .usage = kBufferUsage,
};
BufferDescriptor descriptor;
diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp
index 6bda558..d183bd8 100644
--- a/thermal/1.0/vts/functional/Android.bp
+++ b/thermal/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalThermalV1_0TargetTest.cpp"],
static_libs: ["android.hardware.thermal@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
index 6f059ef..aa1c0ce 100644
--- a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
+++ b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
@@ -21,11 +21,12 @@
#define LOG_TAG "thermal_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/thermal/1.0/IThermal.h>
#include <android/hardware/thermal/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unistd.h>
using ::android::hardware::hidl_string;
@@ -46,26 +47,11 @@
#define MAX_DEVICE_TEMPERATURE 200
#define MAX_FAN_SPEED 20000
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ThermalHidlEnvironment* Instance() {
- static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IThermal>(); }
- private:
- ThermalHidlEnvironment() {}
-};
-
// The main test class for THERMAL HIDL HAL.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
- ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+ thermal_ = IThermal::getService(GetParam());
ASSERT_NE(thermal_, nullptr);
baseSize_ = 0;
names_.clear();
@@ -178,7 +164,7 @@
};
// Sanity test for Thermal::getTemperatures().
-TEST_F(ThermalHidlTest, TemperatureTest) {
+TEST_P(ThermalHidlTest, TemperatureTest) {
hidl_vec<Temperature> passed;
for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
thermal_->getTemperatures(
@@ -193,7 +179,7 @@
}
// Sanity test for Thermal::getCpuUsages().
-TEST_F(ThermalHidlTest, CpuUsageTest) {
+TEST_P(ThermalHidlTest, CpuUsageTest) {
hidl_vec<CpuUsage> passed;
for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
thermal_->getCpuUsages(
@@ -208,7 +194,7 @@
}
// Sanity test for Thermal::getCoolingDevices().
-TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+TEST_P(ThermalHidlTest, CoolingDeviceTest) {
hidl_vec<CoolingDevice> passed;
for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
thermal_->getCoolingDevices([&passed](
@@ -222,11 +208,7 @@
}
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ThermalHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ThermalHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/thermal/1.1/vts/functional/Android.bp b/thermal/1.1/vts/functional/Android.bp
index 9a16c30..2c43d79 100644
--- a/thermal/1.1/vts/functional/Android.bp
+++ b/thermal/1.1/vts/functional/Android.bp
@@ -22,6 +22,5 @@
"android.hardware.thermal@1.0",
"android.hardware.thermal@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
-
diff --git a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
index 91c8b6e..bc7b2ee 100644
--- a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
+++ b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
@@ -17,10 +17,11 @@
#include <android/hardware/thermal/1.1/IThermal.h>
#include <android/hardware/thermal/1.1/IThermalCallback.h>
#include <android/hardware/thermal/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::thermal::V1_0::Temperature;
using ::android::hardware::thermal::V1_0::TemperatureType;
@@ -63,26 +64,11 @@
}
};
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ThermalHidlEnvironment* Instance() {
- static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IThermal>(); }
- private:
- ThermalHidlEnvironment() {}
-};
-
// The main test class for THERMAL HIDL HAL 1.1.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
- ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+ mThermal = IThermal::getService(GetParam());
ASSERT_NE(mThermal, nullptr);
mThermalCallback = new(std::nothrow) ThermalCallback();
ASSERT_NE(mThermalCallback, nullptr);
@@ -104,7 +90,7 @@
// This just calls into and back from our local ThermalCallback impl.
// Note: a real thermal throttling event from the Thermal HAL could be
// inadvertently received here.
-TEST_F(ThermalHidlTest, NotifyThrottlingTest) {
+TEST_P(ThermalHidlTest, NotifyThrottlingTest) {
auto ret = mThermalCallback->notifyThrottling(true, kThrottleTemp);
ASSERT_TRUE(ret.isOk());
auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
@@ -114,11 +100,7 @@
EXPECT_EQ(kThrottleTemp, res.args->temperature);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ThermalHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- cout << "Test result = " << status << std::endl;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ThermalHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp
index f4e95f8..0940576 100644
--- a/thermal/2.0/vts/functional/Android.bp
+++ b/thermal/2.0/vts/functional/Android.bp
@@ -22,5 +22,6 @@
"android.hardware.thermal@1.0",
"android.hardware.thermal@2.0",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
index d0f2e84..75536a6 100644
--- a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
+++ b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
@@ -18,9 +18,11 @@
#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
#include <android/hardware/thermal/2.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::sp;
using ::android::hardware::hidl_enum_range;
@@ -63,27 +65,11 @@
}
};
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ThermalHidlEnvironment* Instance() {
- static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
- return instance;
- }
-
- void registerTestServices() override { registerTestService<IThermal>(); }
-
- private:
- ThermalHidlEnvironment() {}
-};
-
// The main test class for THERMAL HIDL HAL 2.0.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
- ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+ mThermal = IThermal::getService(GetParam());
ASSERT_NE(mThermal, nullptr);
mThermalCallback = new (std::nothrow) ThermalCallback();
ASSERT_NE(mThermalCallback, nullptr);
@@ -119,7 +105,7 @@
// This just calls into and back from our local ThermalChangedCallback impl.
// Note: a real thermal throttling event from the Thermal HAL could be
// inadvertently received here.
-TEST_F(ThermalHidlTest, NotifyThrottlingTest) {
+TEST_P(ThermalHidlTest, NotifyThrottlingTest) {
auto ret = mThermalCallback->notifyThrottling(kThrottleTemp);
ASSERT_TRUE(ret.isOk());
auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
@@ -129,7 +115,7 @@
}
// Test Thermal->registerThermalChangedCallback.
-TEST_F(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
+TEST_P(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
// Expect to fail with same callback
auto ret = mThermal->registerThermalChangedCallback(
mThermalCallback, false, TemperatureType::SKIN,
@@ -159,7 +145,7 @@
}
// Test Thermal->unregisterThermalChangedCallback.
-TEST_F(ThermalHidlTest, UnregisterThermalChangedCallbackTest) {
+TEST_P(ThermalHidlTest, UnregisterThermalChangedCallbackTest) {
sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
// Expect to fail as the callback was not registered before
auto ret = mThermal->unregisterThermalChangedCallback(
@@ -184,7 +170,7 @@
}
// Sanity test for Thermal::getCurrentTemperatures().
-TEST_F(ThermalHidlTest, TemperatureTest) {
+TEST_P(ThermalHidlTest, TemperatureTest) {
mThermal->getCurrentTemperatures(false, TemperatureType::SKIN,
[](ThermalStatus status, hidl_vec<Temperature> temperatures) {
if (temperatures.size()) {
@@ -214,7 +200,7 @@
}
// Sanity test for Thermal::getTemperatureThresholds().
-TEST_F(ThermalHidlTest, TemperatureThresholdTest) {
+TEST_P(ThermalHidlTest, TemperatureThresholdTest) {
mThermal->getTemperatureThresholds(
false, TemperatureType::SKIN,
[](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
@@ -242,7 +228,7 @@
}
// Sanity test for Thermal::getCurrentCoolingDevices().
-TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+TEST_P(ThermalHidlTest, CoolingDeviceTest) {
mThermal->getCurrentCoolingDevices(
false, CoolingType::CPU, [](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
if (cooling_devices.size()) {
@@ -271,11 +257,7 @@
}
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ThermalHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- cout << "Test result = " << status << std::endl;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ThermalHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index 09265f7..d78f3f2 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -9,15 +9,21 @@
srcs: [
"types.hal",
"IDemux.hal",
- "IDemuxCallback.hal",
"IDescrambler.hal",
+ "IDvr.hal",
+ "IDvrCallback.hal",
+ "IFilter.hal",
+ "IFilterCallback.hal",
"IFrontend.hal",
"IFrontendCallback.hal",
"ILnb.hal",
+ "ILnbCallback.hal",
+ "ITimeFilter.hal",
"ITuner.hal",
],
interfaces: [
"android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
],
gen_java: false,
gen_java_constants: true,
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
index 7fd7e26..9e799b4 100644
--- a/tv/tuner/1.0/IDemux.hal
+++ b/tv/tuner/1.0/IDemux.hal
@@ -16,7 +16,11 @@
package android.hardware.tv.tuner@1.0;
-import IDemuxCallback;
+import IDvr;
+import IDvrCallback;
+import IFilter;
+import IFilterCallback;
+import ITimeFilter;
/**
* Demultiplexer(Demux) takes a single multiplexed input and splits it into
@@ -24,7 +28,6 @@
*
*/
interface IDemux {
-
/**
* Set a frontend resource as data input of the demux
*
@@ -39,134 +42,51 @@
setFrontendDataSource(FrontendId frontendId) generates (Result result);
/**
- * Add a filter to the demux
+ * Open a new filter in the demux
*
- * It is used by the client to add a filter to the demux.
+ * It is used by the client to open a filter in the demux.
*
* @param type the type of the filter to be added.
- * @param bufferSize the buffer size of the filter to be added. It's used to
- * create a FMQ(Fast Message Queue) to hold data output from the filter.
+ * @param bufferSize the buffer size of the filter to be opened. It's used
+ * to create a FMQ(Fast Message Queue) to hold data output from the filter.
* @param cb the callback for the filter to be used to send notifications
* back to the client.
* @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 ID of the newly added filter.
+ * @return filter the filter instance of the newly added.
*/
- addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb)
- generates (Result result, DemuxFilterId filterId);
+ openFilter(DemuxFilterType type, uint32_t bufferSize, IFilterCallback cb)
+ generates (Result result, IFilter filter);
/**
- * Get the descriptor of the filter's FMQ
+ * Open time filter of the demux
*
- * It is used by the client to get the descriptor of the filter's Fast
- * Message Queue. The data in FMQ is filtered out from MPEG transport
- * stream. The data is organized to data blocks which may have
- * different length. The length's information of one or multiple data blocks
- * is sent to client through DemuxFilterEvent.
+ * It is used by the client to open time filter of the demux.
*
- * @param filterId the ID of the filter.
* @return result Result status of the operation.
* SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
+ * UNAVAILABLE if time filter is not supported.
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
- * @return queue the descriptor of the filter's FMQ
+ * @return timeFilter the time filter instance of the newly added.
*/
- getFilterQueueDesc(DemuxFilterId filterId)
- generates (Result result, fmq_sync<uint8_t> queue);
-
- /**
- * Configure the filter.
- *
- * It is used by the client to configure the filter so that it can filter out
- * intended data.
- *
- * @param filterId the ID of the filter.
- * @param settings the settings of the filter.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings)
- generates(Result result);
-
- /**
- * Start the filter.
- *
- * It is used by the client to ask the filter to start filtering data.
- *
- * @param filterId the ID of the filter.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- startFilter(DemuxFilterId filterId) generates (Result result);
-
- /**
- * Stop the filter.
- *
- * It is used by the client to ask the filter to stop filterring data.
- * It won't discard the data already filtered out by the filter. The filter
- * will be stopped and removed automatically if the demux is closed.
- *
- * @param filterId the ID of the filter.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- stopFilter(DemuxFilterId filterId) generates (Result result);
-
- /**
- * Flush the filter.
- *
- * It is used by the client to ask the filter to flush the data which is
- * already produced but not consumed yet.
- *
- * @param filterId the ID of the filter.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- flushFilter(DemuxFilterId filterId) generates (Result result);
-
- /**
- * Remove a filter from the demux
- *
- * It is used by the client to remove a filter from the demux.
- *
- * @param filterId the ID of the removed filter.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_ARGUMENT if failed for wrong filter ID.
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- removeFilter(DemuxFilterId filterId) generates (Result result);
+ openTimeFilter() generates (Result result, ITimeFilter timeFilter);
/**
* Get hardware sync ID for audio and video.
*
* It is used by the client to get the hardware sync ID for audio and video.
*
- * @param filterId the ID of the filter.
+ * @param filter the filter instance.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_ARGUMENT if failed for a wrong filter ID.
* UNKNOWN_ERROR if failed for other reasons.
* @return avSyncHwId the id of hardware A/V sync.
*/
- getAvSyncHwId(DemuxFilterId filterId)
- generates (Result result, AvSyncHwId avSyncHwId);
+ getAvSyncHwId(IFilter filter) generates (Result result, AvSyncHwId avSyncHwId);
/**
* Get current time stamp to use for A/V sync
@@ -182,8 +102,7 @@
* @return time the current time stamp of hardware A/V sync. The time stamp
* based on 90KHz has the same format as PTS (Presentation Time Stamp).
*/
- getAvSyncTime(AvSyncHwId avSyncHwId)
- generates (Result result, uint64_t time);
+ getAvSyncTime(AvSyncHwId avSyncHwId) generates (Result result, uint64_t time);
/**
* Close the Demux instance
@@ -198,218 +117,21 @@
close() generates (Result result);
/**
- * Add output to the demux
+ * Open a DVR (Digital Video Record) instance in the demux
*
- * It is used by the client to record output data from selected filters.
+ * It is used by the client to record and playback.
*
+ * @param type specify which kind of DVR to open.
* @param bufferSize the buffer size of the output to be added. It's used to
* create a FMQ(Fast Message Queue) to hold data from selected filters.
- * @param cb the callback for the demux to be used to send notifications
+ * @param cb the callback for the DVR to be used to send notifications
* back to the client.
* @return result Result status of the operation.
* SUCCESS if successful,
* OUT_OF_MEMORY if failed for not enough memory.
* UNKNOWN_ERROR if failed for other reasons.
+ * @return dvr a DVR instance.
*/
- addOutput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result);
-
- /**
- * Get the descriptor of the output's FMQ
- *
- * It is used by the client to get the descriptor of the output's Fast
- * Message Queue. The data in FMQ is muxed packets output from selected
- * filters. The packet's format is specified by DemuxDataFormat in
- * DemuxOutputSettings.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * UNKNOWN_ERROR if failed for other reasons.
- * @return queue the descriptor of the output's FMQ
- */
- getOutputQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
-
- /**
- * Configure the demux's output.
- *
- * It is used by the client to configure the demux's output for recording.
- *
- * @param settings the settings of the demux's output.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- configureOutput(DemuxOutputSettings settings) generates (Result result);
-
- /**
- * Attach one filter to the demux's output.
- *
- * It is used by the client to mux one filter's output to demux's output.
- *
- * @param filterId the ID of the attached 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.
- */
- attachOutputFilter(DemuxFilterId filterId) generates (Result result);
-
- /**
- * Detach one filter from the demux's output.
- *
- * It is used by the client to remove one filter's output from demux's
- * output.
- *
- * @param filterId the ID of the detached 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.
- */
- detachOutputFilter(DemuxFilterId filterId) generates (Result result);
-
- /**
- * Start to take data to the demux's output.
- *
- * It is used by the client to ask the output to start to take data from
- * attached filters.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- startOutput() generates (Result result);
-
- /**
- * Stop to take data to the demux's output.
- *
- * It is used by the client to ask the output to stop to take data from
- * attached filters.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- stopOutput() generates (Result result);
-
- /**
- * Flush unconsumed data in the demux's output.
- *
- * It is used by the client to ask the demux to flush the data which is
- * already produced but not consumed yet in the demux's output.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- flushOutput() generates (Result result);
-
- /**
- * Remove the demux's output.
- *
- * It is used by the client to remove the demux's output.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- removeOutput() generates (Result result);
-
- /**
- * Add input to the demux
- *
- * It is used by the client to add the demux's input for playback content.
- *
- * @param bufferSize the buffer size of the demux's input to be added.
- * It's used to create a FMQ(Fast Message Queue) to hold input data.
- * @param cb the callback for the demux to be used to send notifications
- * back to the client.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * OUT_OF_MEMORY if failed for not enough memory.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- addInput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result);
-
- /**
- * Get the descriptor of the input's FMQ
- *
- * It is used by the client to get the descriptor of the input's Fast
- * Message Queue. The data in FMQ is fed by client. Data format is specifed
- * by DemuxDataFormat in DemuxInputSettings.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * UNKNOWN_ERROR if failed for other reasons.
- * @return queue the descriptor of the output's FMQ
- */
- getInputQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
-
- /**
- * Configure the demux's input.
- *
- * It is used by the client to configure the demux's input for playback.
- *
- * @param settings the settings of the demux's input.
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- configureInput(DemuxInputSettings settings) generates (Result result);
-
- /**
- * Start to consume the data from the demux's input.
- *
- * It is used by the client to ask the demux to start to consume data from
- * the demux's input.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- startInput() generates (Result result);
-
- /**
- * Stop to consume the data from the demux's input.
- *
- * It is used by the client to ask the demux to stop to consume data from
- * the demux's input.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- stopInput() generates (Result result);
-
- /**
- * Flush unconsumed data in the demux's input.
- *
- * It is used by the client to ask the demux to flush the data which is
- * already produced but not consumed yet in the demux's input.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- flushInput() generates (Result result);
-
- /**
- * Remove the demux's input.
- *
- * It is used by the client to remove the demux's input.
- *
- * @return result Result status of the operation.
- * SUCCESS if successful,
- * INVALID_STATE if failed for wrong state.
- * UNKNOWN_ERROR if failed for other reasons.
- */
- removeInput() generates (Result result);
+ openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb)
+ generates (Result result, IDvr dvr);
};
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
deleted file mode 100644
index 7bce9ef..0000000
--- a/tv/tuner/1.0/IDemuxCallback.hal
+++ /dev/null
@@ -1,49 +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.
- */
-
-package android.hardware.tv.tuner@1.0;
-
-interface IDemuxCallback {
- /**
- * Notify the client that a new filter event happened.
- *
- * @param filterEvent a demux filter event.
- */
- oneway onFilterEvent(DemuxFilterEvent filterEvent);
-
- /**
- * Notify the client a new status of a demux filter.
- *
- * @param filterId the demux filter ID.
- * @param status a new status of the demux filter.
- */
- oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status);
-
- /**
- * Notify the client a new status of the demux's output.
- *
- * @param status a new status of the demux's output.
- */
- oneway onOutputStatus(DemuxOutputStatus status);
-
- /**
- * Notify the client a new status of the demux's input.
- *
- * @param status a new status of the demux's input.
- */
- oneway onInputStatus(DemuxInputStatus status);
-};
-
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
index 61ff1df..7f98865 100644
--- a/tv/tuner/1.0/IDescrambler.hal
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -15,6 +15,9 @@
*/
package android.hardware.tv.tuner@1.0;
+
+import IFilter;
+
/**
* Descrambler is used to descramble input data.
*
@@ -59,12 +62,13 @@
* packets from different PIDs.
*
* @param pid the PID of packets to start to be descrambled.
+ * @param filter an optional filter instance to identify upper stream.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
*/
- addPid(DemuxTpid pid) generates (Result result);
+ addPid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
/**
* Remove packets' PID from the descrambler
@@ -73,12 +77,13 @@
* descrambler stop to descramble.
*
* @param pid the PID of packets to stop to be descrambled.
+ * @param filter an optional filter instance to identify upper stream.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
*/
- removePid(DemuxTpid pid) generates (Result result);
+ removePid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
/**
* Release the descrambler instance
@@ -92,4 +97,3 @@
*/
close() generates (Result result);
};
-
diff --git a/tv/tuner/1.0/IDvr.hal b/tv/tuner/1.0/IDvr.hal
new file mode 100644
index 0000000..f57e4b6
--- /dev/null
+++ b/tv/tuner/1.0/IDvr.hal
@@ -0,0 +1,133 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFilter;
+
+/**
+ * Digtal Video Record (DVR) interface provides record control on Demux's
+ * output buffer and playback control on Demux's input buffer.
+ */
+interface IDvr {
+ /**
+ * Get the descriptor of the DVR's FMQ
+ *
+ * It is used by the client to get the descriptor of the DVR's Fast
+ * Message Queue. The FMQ is used to transfer record or playback data
+ * between the client and the HAL.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ * @return queue the descriptor of the DVR's FMQ
+ */
+ getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+ /**
+ * Configure the DVR.
+ *
+ * It is used by the client to configure the DVR interface.
+ *
+ * @param settings the settings of the DVR interface.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ configure(DvrSettings settings) generates (Result result);
+
+ /**
+ * Attach one filter to DVR interface for recording.
+ *
+ * It is used by the client to add the data filtered out from the filter
+ * to record.
+ *
+ * @param filter the instance of the attached 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.
+ */
+ attachFilter(IFilter filter) generates (Result result);
+
+ /**
+ * Detach one filter from the DVR's recording.
+ *
+ * It is used by the client to remove the data of the filter from DVR's
+ * recording.
+ *
+ * @param filter the instance of the detached 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.
+ */
+ detachFilter(IFilter filter) generates (Result result);
+
+ /**
+ * Start DVR.
+ *
+ * It is used by the client to ask the DVR to start consuming playback data
+ * or producing data for record.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ start() generates (Result result);
+
+ /**
+ * Stop DVR.
+ *
+ * It is used by the client to ask the DVR to stop consuming playback data
+ * or producing data for record.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ stop() generates (Result result);
+
+ /**
+ * Flush DVR data.
+ *
+ * It is used by the client to ask the DVR to flush the data which is
+ * not consumed by HAL for playback or the client for record yet.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ flush() generates (Result result);
+
+ /**
+ * close the DVR instance to release resource for DVR.
+ *
+ * It is used by the client to close the DVR instance, and HAL clears
+ * underneath resource for this DVR instance. Client mustn't access the
+ * instance any more and all methods should return a failure.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IDvrCallback.hal b/tv/tuner/1.0/IDvrCallback.hal
new file mode 100644
index 0000000..337eddc
--- /dev/null
+++ b/tv/tuner/1.0/IDvrCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.tv.tuner@1.0;
+
+interface IDvrCallback {
+ /**
+ * Notify the client a new status of the demux's record.
+ *
+ * @param status a new status of the demux's record.
+ */
+ oneway onRecordStatus(RecordStatus status);
+
+ /**
+ * Notify the client a new status of the demux's playback.
+ *
+ * @param status a new status of the demux's playback.
+ */
+ oneway onPlaybackStatus(PlaybackStatus status);
+};
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
new file mode 100644
index 0000000..deaf3d4
--- /dev/null
+++ b/tv/tuner/1.0/IFilter.hal
@@ -0,0 +1,143 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFilterCallback;
+
+/**
+ * The Filter is used to filter wanted data according to the filter's
+ * configuration.
+ */
+interface IFilter {
+ /**
+ * Get the descriptor of the filter's FMQ
+ *
+ * It is used by the client to get the descriptor of the filter's Fast
+ * Message Queue. The data in FMQ is filtered out from demux input or upper
+ * stream's filter. The data is origanized to data blocks which may have
+ * different length. The length's information of one or multiple data blocks
+ * is sent to client through DemuxFilterEvent. The data in each block
+ * follows the stardard specified by filter's type.
+ * E.X. one data block from the filter with Main_Type==TS and Sub_Type==PES
+ * is Packetized Elementary Stream from Transport Stream according to
+ * ISO/IEC 13818-1.
+ *
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNAVAILABLE if the filter doesn't have FMQ.
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ * @return queue the descriptor of the filter's FMQ
+ */
+ getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+ /**
+ * Configure the filter.
+ *
+ * It is used by the client to configure the filter so that it can filter out
+ * intended data.
+ *
+ * @param settings the settings of 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.
+ */
+ configure(DemuxFilterSettings settings) generates (Result result);
+
+ /**
+ * Start the filter.
+ *
+ * It is used by the client to ask the filter to start filterring data.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ start() generates (Result result);
+
+ /**
+ * Stop the filter.
+ *
+ * It is used by the client to ask the filter to stop filterring data.
+ * It won't discard the data already filtered out by the filter. The filter
+ * will be stopped and removed automatically if the demux is closed.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ stop() generates (Result result);
+
+ /**
+ * Flush the filter.
+ *
+ * It is used by the client to ask the filter to flush the data which is
+ * already produced but not consumed yet.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ flush() generates (Result result);
+
+ /**
+ * Get the filter Id.
+ *
+ * It is used by the client to ask the hardware resource id for the filter.
+ *
+ * @param filterId 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.
+ */
+ getId() generates (Result result, uint32_t filterId);
+
+ /**
+ * Set the filter's data source.
+ *
+ * A filter uses demux as data source by default. If the data was packetized
+ * by multiple protocols, multiple filters may need to work together to
+ * extract all protocols' header. Then a filter's data source can be output
+ * from another filter.
+ *
+ * @param filter the filter instance which provides data input. Switch to
+ * use demux as data source if the filter instance is NULL.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setDataSource(IFilter filter) generates (Result result);
+
+ /**
+ * Release the Filter instance
+ *
+ * It is used by the client to release the Filter instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IFilterCallback.hal b/tv/tuner/1.0/IFilterCallback.hal
new file mode 100644
index 0000000..a0ff62e
--- /dev/null
+++ b/tv/tuner/1.0/IFilterCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.tv.tuner@1.0;
+
+interface IFilterCallback {
+ /**
+ * Notify the client that a new filter event happened.
+ *
+ * @param filterEvent a filter event.
+ */
+ oneway onFilterEvent(DemuxFilterEvent filterEvent);
+
+ /**
+ * Notify the client a new status of a filter.
+ *
+ * @param status a new status of the filter.
+ */
+ oneway onFilterStatus(DemuxFilterStatus status);
+};
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index 83e390d..756ab46 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.hardware.tv.tuner@1.0;
import IFrontendCallback;
@@ -128,7 +129,8 @@
* @return statuses an array of statuses which response the caller's
* request.
*/
- getStatus(vec<FrontendStatusType> statusTypes) generates (Result result, vec<FrontendStatus> statuses);
+ getStatus(vec<FrontendStatusType> statusTypes)
+ generates (Result result, vec<FrontendStatus> statuses);
/**
* Sets Low-Noise Block downconverter (LNB) for satellite frontend.
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
index 8896a09..88b96c4 100644
--- a/tv/tuner/1.0/IFrontendCallback.hal
+++ b/tv/tuner/1.0/IFrontendCallback.hal
@@ -26,16 +26,6 @@
/**
* The callback function that must be called by HAL implementation to notify
- * the client of new DiSEqC message.
- *
- * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
- * Equipment Control) message which is specified by EUTELSAT Bus Functional
- * Specification Version 4.2.
- */
- oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
-
- /**
- * The callback function that must be called by HAL implementation to notify
* the client of scan messages.
*
* @param type the type of scan message.
diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal
index 6b7119e..5070519 100644
--- a/tv/tuner/1.0/ILnb.hal
+++ b/tv/tuner/1.0/ILnb.hal
@@ -13,8 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.hardware.tv.tuner@1.0;
+import ILnbCallback;
+
/**
* A Tuner LNB (low-noise block downconverter) is used by satellite frontend
* to receive the microwave signal from the satellite, amplify it, and
@@ -22,6 +25,23 @@
*/
interface ILnb {
/**
+ * Set the lnb callback.
+ *
+ * ILnbCallback is used by the client to receive events from the Lnb.
+ * Only one callback per ILnb instance is supported. The callback
+ * will be replaced if it's set again.
+ *
+ * @param callback Callback object to pass Lnb events to the system.
+ * The previously registered callback must be replaced with this one.
+ * It can be null.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if callback can't be set at current stage,
+ * UNKNOWN_ERROR if callback setting failed for other reasons.
+ */
+ setCallback(ILnbCallback callback) generates (Result result);
+
+ /**
* Set the lnb's power voltage.
*
* @param voltage the power's voltage the Lnb to use.
@@ -30,7 +50,7 @@
* INVALID_ARGUMENT if the selected voltage isn't allowed,
* UNKNOWN_ERROR if failed for other reasons.
*/
- setVoltage(FrontendLnbVoltage voltage) generates (Result result);
+ setVoltage(LnbVoltage voltage) generates (Result result);
/**
* Set the lnb's tone mode.
@@ -41,7 +61,7 @@
* INVALID_ARGUMENT if the selected tone mode isn't allowed,
* UNKNOWN_ERROR if failed for other reasons.
*/
- setTone(FrontendLnbTone tone) generates (Result result);
+ setTone(LnbTone tone) generates (Result result);
/**
* Select the lnb's position.
@@ -52,7 +72,7 @@
* INVALID_ARGUMENT if the selected position isn't allowed,
* UNKNOWN_ERROR if failed for other reasons.
*/
- setSatellitePosition(FrontendLnbPosition position) generates (Result result);
+ setSatellitePosition(LnbPosition position) generates (Result result);
/**
* Sends DiSEqC (Digital Satellite Equipment Control) message.
diff --git a/tv/tuner/1.0/ILnbCallback.hal b/tv/tuner/1.0/ILnbCallback.hal
new file mode 100644
index 0000000..68e9c35
--- /dev/null
+++ b/tv/tuner/1.0/ILnbCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * 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.tv.tuner@1.0;
+
+interface ILnbCallback {
+ /**
+ * Notify the client that a new event happened on the Lnb.
+ *
+ * @param LnbEventType the event type.
+ */
+ oneway onEvent(LnbEventType lnbEventType);
+
+ /**
+ * The callback function that must be called by HAL implementation to notify
+ * the client of new DiSEqC message.
+ *
+ * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
+ * Equipment Control) message which is specified by EUTELSAT Bus Functional
+ * Specification Version 4.2.
+ */
+ oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
+};
diff --git a/tv/tuner/1.0/ITimeFilter.hal b/tv/tuner/1.0/ITimeFilter.hal
new file mode 100644
index 0000000..ce285db
--- /dev/null
+++ b/tv/tuner/1.0/ITimeFilter.hal
@@ -0,0 +1,88 @@
+/*
+ * 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.tv.tuner@1.0;
+
+/**
+ * Timer Filter is used by Demux to filter data based on time stamp.
+ */
+interface ITimeFilter {
+ /**
+ * Set time stamp for time based filter.
+ *
+ * It is used by the client to set initial time stamp and enable time
+ * filtering. The time will be incremented locally. The demux discards
+ * the content which time stamp is older than the time in the time filter.
+ *
+ * @param timeStamp initial time stamp for the time filter. It based on
+ * 90KHz has the same format as PTS (Presentation Time Stamp).
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setTimeStamp(uint64_t timeStamp) generates (Result result);
+
+ /**
+ * Clear the time stamp in the time filter.
+ *
+ * It is used by the client to clear the time value of the time filter,
+ * then disable time filter.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ clearTimeStamp() generates (Result result);
+
+ /**
+ * Get the current time in the time filter.
+ *
+ * It is used by the client to inquiry current time in the time 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 timeStamp current time stamp in the time filter.
+ */
+ getTimeStamp() generates (Result result, uint64_t timeStamp);
+
+ /**
+ * Get the time from the beginning of current data source.
+ *
+ * It is used by the client to inquiry the time stamp from the beginning
+ * of current data source.
+ *
+ * @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 timeStamp time stamp from the beginning of current data source.
+ */
+ getSourceTime() generates (Result result, uint64_t timeStamp);
+
+ /**
+ * Close the Time Filter instance
+ *
+ * It is used by the client to release the demux instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 1cf0e38..2712c13 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -23,7 +23,7 @@
/**
* Top level interface to manage Frontend, Demux and Decrambler hardware
- * resources which are needed for Android TV.
+ * resouces which are needed for Android TV.
*/
interface ITuner {
/**
@@ -50,8 +50,7 @@
* UNKNOWN_ERROR if creation failed for other reasons.
* @return frontend the newly created frontend interface.
*/
- openFrontendById(FrontendId frontendId)
- generates (Result result, IFrontend frontend);
+ openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend);
/**
* Create a new instance of Demux.
@@ -64,8 +63,7 @@
* @return demuxId newly created demux id.
* @return demux the newly created demux interface.
*/
- openDemux()
- generates (Result result, DemuxId demuxId, IDemux demux);
+ openDemux() generates (Result result, DemuxId demuxId, IDemux demux);
/**
* Retrieve the Demux's Capabilities.
@@ -87,8 +85,7 @@
* UNKNOWN_ERROR if creation failed for other reasons.
* @return descrambler the newly created descrambler interface.
*/
- openDescrambler()
- generates (Result result, IDescrambler descrambler);
+ openDescrambler() generates (Result result, IDescrambler descrambler);
/**
* Retrieve the frontend's information.
@@ -99,8 +96,7 @@
* UNKNOWN_ERROR if the inquiry failed for other reasons.
* @return info the frontend's information.
*/
- getFrontendInfo(FrontendId frontendId)
- generates (Result result, FrontendInfo info);
+ getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info);
/**
* Get low-noise block downconverter (LNB) IDs.
@@ -126,7 +122,5 @@
* UNKNOWN_ERROR if creation failed for other reasons.
* @return lnb the newly created Lnb interface.
*/
- openLnbById(LnbId lnbId)
- generates (Result result, ILnb lnb);
+ openLnbById(LnbId lnbId) generates (Result result, ILnb lnb);
};
-
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
index 0ae8bcd..989e25c 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -4,9 +4,12 @@
vendor: true,
relative_install_path: "hw",
srcs: [
+ "Filter.cpp",
"Frontend.cpp",
"Descrambler.cpp",
"Demux.cpp",
+ "Dvr.cpp",
+ "TimeFilter.cpp",
"Tuner.cpp",
"Lnb.cpp",
"service.cpp",
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index b18d4df..c5921f7 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -28,45 +28,6 @@
#define WAIT_TIMEOUT 3000000000
-const std::vector<uint8_t> fakeDataInputBuffer{
- 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
- 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
- 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
- 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
- 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
- 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
- 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
- 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
- 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
- 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
- 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
- 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
- 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
- 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
- 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
- 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
- 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
- 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
- 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
- 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
- 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
- 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
- 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
- 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
- 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
- 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
- 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
- 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
- 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
- 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
- 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
- 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
- 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
- 0x73, 0x63, 0x65, 0x6e, 0x65,
-};
-
Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
mDemuxId = demuxId;
mTunerService = tuner;
@@ -93,8 +54,8 @@
return startBroadcastInputLoop();
}
-Return<void> Demux::addFilter(DemuxFilterType type, uint32_t bufferSize,
- const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) {
+Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
uint32_t filterId;
@@ -105,137 +66,39 @@
mUnusedFilterIds.erase(filterId);
} else {
filterId = ++mLastUsedFilterId;
-
- mFilterCallbacks.resize(filterId + 1);
- mFilterMQs.resize(filterId + 1);
- mFilterEvents.resize(filterId + 1);
- mFilterEventFlags.resize(filterId + 1);
- mFilterThreadRunning.resize(filterId + 1);
- mFilterThreads.resize(filterId + 1);
- mFilterPids.resize(filterId + 1);
- mFilterOutputs.resize(filterId + 1);
- mFilterStatus.resize(filterId + 1);
}
mUsedFilterIds.insert(filterId);
- if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) {
+ if (cb == nullptr) {
ALOGW("callback can't be null");
- _hidl_cb(Result::INVALID_ARGUMENT, filterId);
+ _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
return Void();
}
- // Add callback
- mFilterCallbacks[filterId] = cb;
+ sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
- // Mapping from the filter ID to the filter event
- DemuxFilterEvent event{
- .filterId = filterId,
- .filterType = type,
- };
- mFilterEvents[filterId] = event;
-
- if (!createFilterMQ(bufferSize, filterId)) {
- _hidl_cb(Result::UNKNOWN_ERROR, -1);
+ if (!filter->createFilterMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, filter);
return Void();
}
- _hidl_cb(Result::SUCCESS, filterId);
+ mFilters[filterId] = filter;
+
+ _hidl_cb(Result::SUCCESS, filter);
return Void();
}
-Return<void> Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) {
+Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
- if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) {
- ALOGW("No filter with id: %d exists to get desc", filterId);
- _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor());
- return Void();
- }
+ sp<TimeFilter> timeFilter = new TimeFilter(this);
- _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc());
+ _hidl_cb(Result::SUCCESS, timeFilter);
return Void();
}
-Return<Result> Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) {
- ALOGV("%s", __FUNCTION__);
-
- switch (mFilterEvents[filterId].filterType) {
- case DemuxFilterType::SECTION:
- mFilterPids[filterId] = settings.section().tpid;
- break;
- case DemuxFilterType::PES:
- mFilterPids[filterId] = settings.pesData().tpid;
- break;
- case DemuxFilterType::TS:
- mFilterPids[filterId] = settings.ts().tpid;
- break;
- case DemuxFilterType::AUDIO:
- mFilterPids[filterId] = settings.audio().tpid;
- break;
- case DemuxFilterType::VIDEO:
- mFilterPids[filterId] = settings.video().tpid;
- break;
- case DemuxFilterType::RECORD:
- mFilterPids[filterId] = settings.record().tpid;
- break;
- case DemuxFilterType::PCR:
- mFilterPids[filterId] = settings.pcr().tpid;
- break;
- default:
- return Result::UNKNOWN_ERROR;
- }
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::startFilter(uint32_t filterId) {
- ALOGV("%s", __FUNCTION__);
- Result result;
-
- if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) {
- ALOGW("No filter with id: %d exists to start filter", filterId);
- return Result::INVALID_ARGUMENT;
- }
-
- result = startFilterLoop(filterId);
-
- return result;
-}
-
-Return<Result> Demux::stopFilter(uint32_t filterId) {
- ALOGV("%s", __FUNCTION__);
-
- mFilterThreadRunning[filterId] = false;
-
- std::lock_guard<std::mutex> lock(mFilterThreadLock);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushFilter(uint32_t filterId) {
- ALOGV("%s", __FUNCTION__);
-
- // temp implementation to flush the FMQ
- int size = mFilterMQs[filterId]->availableToRead();
- char* buffer = new char[size];
- mOutputMQ->read((unsigned char*)&buffer[0], size);
- delete[] buffer;
- mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeFilter(uint32_t filterId) {
- ALOGV("%s", __FUNCTION__);
-
- // resetFilterRecords(filterId);
- mUsedFilterIds.erase(filterId);
- mUnusedFilterIds.insert(filterId);
-
- return Result::SUCCESS;
-}
-
-Return<void> Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) {
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& /* filter */, getAvSyncHwId_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
AvSyncHwId avSyncHwId = 0;
@@ -256,587 +119,81 @@
Return<Result> Demux::close() {
ALOGV("%s", __FUNCTION__);
- set<uint32_t>::iterator it;
- mInputThread = 0;
- mOutputThread = 0;
- mFilterThreads.clear();
mUnusedFilterIds.clear();
mUsedFilterIds.clear();
- mFilterCallbacks.clear();
- mFilterMQs.clear();
- mFilterEvents.clear();
- mFilterEventFlags.clear();
- mFilterOutputs.clear();
- mFilterPids.clear();
mLastUsedFilterId = -1;
return Result::SUCCESS;
}
-Return<Result> Demux::addOutput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) {
+Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+ openDvr_cb _hidl_cb) {
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(bufferSize, true));
- if (!tmpFilterMQ->isValid()) {
- ALOGW("Failed to create output FMQ");
- return Result::UNKNOWN_ERROR;
- }
-
- mOutputMQ = std::move(tmpFilterMQ);
-
- if (EventFlag::createEventFlag(mOutputMQ->getEventFlagWord(), &mOutputEventFlag) != OK) {
- return Result::UNKNOWN_ERROR;
- }
-
- mOutputCallback = cb;
-
- return Result::SUCCESS;
-}
-
-Return<void> Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) {
- ALOGV("%s", __FUNCTION__);
-
- if (!mOutputMQ) {
- _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor());
+ if (cb == nullptr) {
+ ALOGW("DVR callback can't be null");
+ _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
return Void();
}
- _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc());
- return Void();
-}
+ sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
-Return<Result> Demux::configureOutput(const DemuxOutputSettings& settings) {
- ALOGV("%s", __FUNCTION__);
-
- mOutputConfigured = true;
- mOutputSettings = settings;
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::attachOutputFilter(uint32_t /*filterId*/) {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::detachOutputFilter(uint32_t /* filterId */) {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::startOutput() {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::stopOutput() {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushOutput() {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeOutput() {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::addInput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) {
- ALOGV("%s", __FUNCTION__);
-
- // Create a synchronized FMQ that supports blocking read/write
- std::unique_ptr<FilterMQ> tmpInputMQ =
- std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(bufferSize, true));
- if (!tmpInputMQ->isValid()) {
- ALOGW("Failed to create input FMQ");
- return Result::UNKNOWN_ERROR;
- }
-
- mInputMQ = std::move(tmpInputMQ);
-
- if (EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputEventFlag) != OK) {
- return Result::UNKNOWN_ERROR;
- }
-
- mInputCallback = cb;
-
- return Result::SUCCESS;
-}
-
-Return<void> Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) {
- ALOGV("%s", __FUNCTION__);
-
- if (!mInputMQ) {
- _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor());
+ if (!dvr->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, dvr);
return Void();
}
- _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc());
+ _hidl_cb(Result::SUCCESS, dvr);
return Void();
}
-Return<Result> Demux::configureInput(const DemuxInputSettings& settings) {
+Result Demux::removeFilter(uint32_t filterId) {
ALOGV("%s", __FUNCTION__);
- mInputConfigured = true;
- mInputSettings = settings;
+ // resetFilterRecords(filterId);
+ mUsedFilterIds.erase(filterId);
+ mUnusedFilterIds.insert(filterId);
+ mFilters.erase(filterId);
return Result::SUCCESS;
}
-Return<Result> Demux::startInput() {
- ALOGV("%s", __FUNCTION__);
-
- if (!mInputCallback) {
- return Result::NOT_INITIALIZED;
- }
-
- if (!mInputConfigured) {
- return Result::INVALID_STATE;
- }
-
- pthread_create(&mInputThread, NULL, __threadLoopInput, this);
- pthread_setname_np(mInputThread, "demux_input_waiting_loop");
-
- // TODO start another thread to send filter status callback to the framework
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::stopInput() {
- ALOGV("%s", __FUNCTION__);
-
- mInputThreadRunning = false;
-
- std::lock_guard<std::mutex> lock(mInputThreadLock);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushInput() {
- ALOGV("%s", __FUNCTION__);
-
- return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeInput() {
- ALOGV("%s", __FUNCTION__);
-
- mInputMQ = nullptr;
-
- return Result::SUCCESS;
-}
-
-Result Demux::startFilterLoop(uint32_t filterId) {
- struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
- threadArgs->user = this;
- threadArgs->filterId = filterId;
-
- pthread_t mFilterThread;
- pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
- mFilterThreads[filterId] = mFilterThread;
- pthread_setname_np(mFilterThread, "demux_filter_waiting_loop");
-
- return Result::SUCCESS;
-}
-
-Result Demux::startSectionFilterHandler(uint32_t filterId) {
- if (mFilterOutputs[filterId].empty()) {
- return Result::SUCCESS;
- }
- if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) {
- ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
- return Result::UNKNOWN_ERROR;
- }
-
- mFilterOutputs[filterId].clear();
-
- return Result::SUCCESS;
-}
-
-Result Demux::startPesFilterHandler(uint32_t filterId) {
- std::lock_guard<std::mutex> lock(mFilterEventLock);
- if (mFilterOutputs[filterId].empty()) {
- return Result::SUCCESS;
- }
-
- for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) {
- if (mPesSizeLeft == 0) {
- uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) |
- (mFilterOutputs[filterId][i + 5] << 8) |
- mFilterOutputs[filterId][i + 6];
- ALOGD("[Demux] prefix %d", prefix);
- if (prefix == 0x000001) {
- // TODO handle mulptiple Pes filters
- mPesSizeLeft =
- (mFilterOutputs[filterId][i + 7] << 8) | mFilterOutputs[filterId][i + 8];
- ALOGD("[Demux] pes data length %d", mPesSizeLeft);
- } else {
- continue;
- }
- }
-
- int endPoint = min(184, mPesSizeLeft);
- // append data and check size
- vector<uint8_t>::const_iterator first = mFilterOutputs[filterId].begin() + i + 4;
- vector<uint8_t>::const_iterator last = mFilterOutputs[filterId].begin() + i + 3 + endPoint;
- mPesOutput.insert(mPesOutput.end(), first, last);
- // size does not match then continue
- mPesSizeLeft -= endPoint;
- if (mPesSizeLeft > 0) {
- continue;
- }
- // size match then create event
- if (!writeDataToFilterMQ(mPesOutput, filterId)) {
- mFilterOutputs[filterId].clear();
- return Result::INVALID_STATE;
- }
- maySendFilterStatusCallback(filterId);
- DemuxFilterPesEvent pesEvent;
- pesEvent = {
- // temp dump meta data
- .streamId = mPesOutput[3],
- .dataLength = static_cast<uint16_t>(mPesOutput.size()),
- };
- ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength);
-
- int size = mFilterEvents[filterId].events.size();
- mFilterEvents[filterId].events.resize(size + 1);
- mFilterEvents[filterId].events[size].pes(pesEvent);
- mPesOutput.clear();
- }
-
- mFilterOutputs[filterId].clear();
-
- return Result::SUCCESS;
-}
-
-Result Demux::startTsFilterHandler() {
- // TODO handle starting TS filter
- return Result::SUCCESS;
-}
-
-Result Demux::startMediaFilterHandler(uint32_t filterId) {
- DemuxFilterMediaEvent mediaEvent;
- mediaEvent = {
- // temp dump meta data
- .pts = 0,
- .dataLength = 530,
- .secureMemory = nullptr,
- };
- mFilterEvents[filterId].events.resize(1);
- mFilterEvents[filterId].events[0].media() = mediaEvent;
-
- mFilterOutputs[filterId].clear();
- // TODO handle write FQM for media stream
- return Result::SUCCESS;
-}
-
-Result Demux::startRecordFilterHandler(uint32_t filterId) {
- DemuxFilterRecordEvent recordEvent;
- recordEvent = {
- // temp dump meta data
- .tpid = 0,
- .packetNum = 0,
- };
- recordEvent.indexMask.tsIndexMask() = 0x01;
- mFilterEvents[filterId].events.resize(1);
- mFilterEvents[filterId].events[0].ts() = recordEvent;
-
- mFilterOutputs[filterId].clear();
- return Result::SUCCESS;
-}
-
-Result Demux::startPcrFilterHandler() {
- // TODO handle starting PCR filter
- return Result::SUCCESS;
-}
-
-bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) {
- 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(bufferSize, true));
- if (!tmpFilterMQ->isValid()) {
- ALOGW("Failed to create FMQ of filter with id: %d", filterId);
- return false;
- }
-
- mFilterMQs[filterId] = std::move(tmpFilterMQ);
-
- EventFlag* filterEventFlag;
- if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &filterEventFlag) !=
- OK) {
- return false;
- }
- mFilterEventFlags[filterId] = filterEventFlag;
-
- return true;
-}
-
-bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data) {
- // TODO check how many sections has been read
- std::lock_guard<std::mutex> lock(mFilterEventLock);
- if (!writeDataToFilterMQ(data, filterId)) {
- return false;
- }
- int size = mFilterEvents[filterId].events.size();
- mFilterEvents[filterId].events.resize(size + 1);
- DemuxFilterSectionEvent secEvent;
- secEvent = {
- // temp dump meta data
- .tableId = 0,
- .version = 1,
- .sectionNum = 1,
- .dataLength = static_cast<uint16_t>(data.size()),
- };
- mFilterEvents[filterId].events[size].section(secEvent);
- return true;
-}
-
-bool Demux::writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId) {
- std::lock_guard<std::mutex> lock(mWriteLock);
- if (mFilterMQs[filterId]->write(data.data(), data.size())) {
- return true;
- }
- return false;
-}
-
-bool Demux::readInputFMQ() {
- // Read input data from the input FMQ
- int size = mInputMQ->availableToRead();
- int inputPacketSize = mInputSettings.packetSize;
- vector<uint8_t> dataOutputBuffer;
- dataOutputBuffer.resize(inputPacketSize);
-
- // Dispatch the packet to the PID matching filter output buffer
- for (int i = 0; i < size / inputPacketSize; i++) {
- if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) {
- return false;
- }
- startTsFilter(dataOutputBuffer);
- }
-
- return true;
-}
-
void Demux::startTsFilter(vector<uint8_t> data) {
set<uint32_t>::iterator it;
for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
- ALOGW("start ts filter pid: %d", pid);
- if (pid == mFilterPids[*it]) {
- mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end());
+ if (DEBUG_FILTER) {
+ ALOGW("start ts filter pid: %d", pid);
+ }
+ if (pid == mFilters[*it]->getTpid()) {
+ mFilters[*it]->updateFilterOutput(data);
}
}
}
bool Demux::startFilterDispatcher() {
- Result result;
set<uint32_t>::iterator it;
// Handle the output data per filter type
for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
- switch (mFilterEvents[*it].filterType) {
- case DemuxFilterType::SECTION:
- result = startSectionFilterHandler(*it);
- break;
- case DemuxFilterType::PES:
- result = startPesFilterHandler(*it);
- break;
- case DemuxFilterType::TS:
- result = startTsFilterHandler();
- break;
- case DemuxFilterType::AUDIO:
- case DemuxFilterType::VIDEO:
- result = startMediaFilterHandler(*it);
- break;
- case DemuxFilterType::RECORD:
- result = startRecordFilterHandler(*it);
- break;
- case DemuxFilterType::PCR:
- result = startPcrFilterHandler();
- break;
- default:
- return false;
+ if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
+ return false;
}
}
- return result == Result::SUCCESS;
+ return true;
}
-void* Demux::__threadLoopFilter(void* threadArg) {
- Demux* const self = static_cast<Demux*>(((struct ThreadArgs*)threadArg)->user);
- self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId);
- return 0;
+Result Demux::startFilterHandler(uint32_t filterId) {
+ return mFilters[filterId]->startFilterHandler();
}
-void* Demux::__threadLoopInput(void* user) {
- Demux* const self = static_cast<Demux*>(user);
- self->inputThreadLoop();
- return 0;
+void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
+ mFilters[filterId]->updateFilterOutput(data);
}
-void Demux::filterThreadLoop(uint32_t filterId) {
- ALOGD("[Demux] filter %d threadLoop start.", filterId);
- std::lock_guard<std::mutex> lock(mFilterThreadLock);
- mFilterThreadRunning[filterId] = 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[filterId]) {
- if (mFilterEvents[filterId].events.size() == 0) {
- ALOGD("[Demux] wait for filter data output.");
- usleep(1000 * 1000);
- continue;
- }
- // After successfully write, send a callback and wait for the read to be done
- mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
- mFilterEvents[filterId].events.resize(0);
- mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
- mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]);
- break;
- }
-
- while (mFilterThreadRunning[filterId]) {
- uint32_t efState = 0;
- // We do not wait for the last round of writen 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[filterId]) {
- status_t status = mFilterEventFlags[filterId]->wait(
- static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
- WAIT_TIMEOUT, true /* retry on spurious wake */);
- if (status != OK) {
- ALOGD("[Demux] wait for data consumed");
- continue;
- }
- break;
- }
-
- if (mFilterCallbacks[filterId] == nullptr) {
- ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
- break;
- }
-
- maySendFilterStatusCallback(filterId);
-
- while (mFilterThreadRunning[filterId]) {
- std::lock_guard<std::mutex> lock(mFilterEventLock);
- if (mFilterEvents[filterId].events.size() == 0) {
- continue;
- }
- // After successfully write, send a callback and wait for the read to be done
- mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
- mFilterEvents[filterId].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("[Demux] filter %d writing done. Ending thread", filterId);
- break;
- }
- }
- mFilterThreadRunning[filterId] = false;
- }
-
- ALOGD("[Demux] filter thread ended.");
-}
-
-void Demux::inputThreadLoop() {
- ALOGD("[Demux] input threadLoop start.");
- std::lock_guard<std::mutex> lock(mInputThreadLock);
- mInputThreadRunning = true;
-
- while (mInputThreadRunning) {
- uint32_t efState = 0;
- status_t status =
- mInputEventFlag->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 input 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 (!readInputFMQ() || !startFilterDispatcher()) {
- ALOGD("[Demux] input data failed to be filtered. Ending thread");
- break;
- }
-
- maySendInputStatusCallback();
- }
-
- mInputThreadRunning = false;
- ALOGD("[Demux] input thread ended.");
-}
-
-void Demux::maySendInputStatusCallback() {
- std::lock_guard<std::mutex> lock(mInputStatusLock);
- int availableToRead = mInputMQ->availableToRead();
- int availableToWrite = mInputMQ->availableToWrite();
-
- DemuxInputStatus newStatus =
- checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold,
- mInputSettings.lowThreshold);
- if (mIntputStatus != newStatus) {
- mInputCallback->onInputStatus(newStatus);
- mIntputStatus = newStatus;
- }
-}
-
-void Demux::maySendFilterStatusCallback(uint32_t filterId) {
- std::lock_guard<std::mutex> lock(mFilterStatusLock);
- int availableToRead = mFilterMQs[filterId]->availableToRead();
- int availableToWrite = mInputMQ->availableToWrite();
- int fmqSize = mFilterMQs[filterId]->getQuantumCount();
-
- DemuxFilterStatus newStatus =
- checkFilterStatusChange(filterId, availableToWrite, availableToRead,
- ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
- if (mFilterStatus[filterId] != newStatus) {
- mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus);
- mFilterStatus[filterId] = newStatus;
- }
-}
-
-DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
- uint32_t highThreshold, uint32_t lowThreshold) {
- if (availableToWrite == 0) {
- return DemuxInputStatus::SPACE_FULL;
- } else if (availableToRead > highThreshold) {
- return DemuxInputStatus::SPACE_ALMOST_FULL;
- } else if (availableToRead < lowThreshold) {
- return DemuxInputStatus::SPACE_ALMOST_EMPTY;
- } else if (availableToRead == 0) {
- return DemuxInputStatus::SPACE_EMPTY;
- }
- return mIntputStatus;
-}
-
-DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, 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[filterId];
+uint16_t Demux::getFilterTpid(uint32_t filterId) {
+ return mFilters[filterId]->getTpid();
}
Result Demux::startBroadcastInputLoop() {
@@ -875,6 +232,7 @@
for (int i = 0; i < writePacketAmount; i++) {
inputData.read(buffer, packetSize);
if (!inputData) {
+ mKeepFetchingDataFromFrontend = false;
mBroadcastInputThreadRunning = false;
break;
}
@@ -885,10 +243,9 @@
byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
}
startTsFilter(byteBuffer);
- inputData.seekg(packetSize, inputData.cur);
}
startFilterDispatcher();
- sleep(1);
+ usleep(100);
}
}
@@ -898,6 +255,7 @@
}
void Demux::stopBroadcastInput() {
+ ALOGD("[Demux] stop frontend on demux");
mKeepFetchingDataFromFrontend = false;
mBroadcastInputThreadRunning = false;
std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index ba0b9b0..a9756cc 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -21,7 +21,10 @@
#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;
@@ -38,13 +41,17 @@
using ::android::hardware::MessageQueue;
using ::android::hardware::MQDescriptorSync;
using ::android::hardware::tv::tuner::V1_0::IDemux;
-using ::android::hardware::tv::tuner::V1_0::IDemuxCallback;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
using ::android::hardware::tv::tuner::V1_0::Result;
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-class Tuner;
+class Dvr;
+class Filter;
class Frontend;
+class TimeFilter;
+class Tuner;
class Demux : public IDemux {
public:
@@ -54,63 +61,27 @@
virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
- virtual Return<Result> close() override;
+ virtual Return<void> openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) override;
- virtual Return<void> addFilter(DemuxFilterType type, uint32_t bufferSize,
- const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) override;
+ virtual Return<void> openTimeFilter(openTimeFilter_cb _hidl_cb) override;
- virtual Return<void> getFilterQueueDesc(uint32_t filterId,
- getFilterQueueDesc_cb _hidl_cb) override;
-
- virtual Return<Result> configureFilter(uint32_t filterId,
- const DemuxFilterSettings& settings) override;
-
- virtual Return<Result> startFilter(uint32_t filterId) override;
-
- virtual Return<Result> stopFilter(uint32_t filterId) override;
-
- virtual Return<Result> flushFilter(uint32_t filterId) override;
-
- virtual Return<Result> removeFilter(uint32_t filterId) override;
-
- virtual Return<void> getAvSyncHwId(uint32_t filterId, getAvSyncHwId_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> addInput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) override;
+ virtual Return<Result> close() override;
- virtual Return<void> getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) override;
-
- virtual Return<Result> configureInput(const DemuxInputSettings& settings) override;
-
- virtual Return<Result> startInput() override;
-
- virtual Return<Result> stopInput() override;
-
- virtual Return<Result> flushInput() override;
-
- virtual Return<Result> removeInput() override;
-
- virtual Return<Result> addOutput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) override;
-
- virtual Return<void> getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) override;
-
- virtual Return<Result> configureOutput(const DemuxOutputSettings& settings) override;
-
- virtual Return<Result> attachOutputFilter(uint32_t filterId) override;
-
- virtual Return<Result> detachOutputFilter(uint32_t filterId) override;
-
- virtual Return<Result> startOutput() override;
-
- virtual Return<Result> stopOutput() override;
-
- virtual Return<Result> flushOutput() override;
-
- virtual Return<Result> removeOutput() override;
+ virtual Return<void> openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+ openDvr_cb _hidl_cb) override;
// Functions interacts with Tuner Service
void stopBroadcastInput();
+ Result removeFilter(uint32_t filterId);
+ Result startFilterHandler(uint32_t filterId);
+ void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
+ uint16_t getFilterTpid(uint32_t filterId);
private:
// Tuner service
@@ -126,19 +97,9 @@
uint32_t filterId;
};
- /**
- * 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(uint32_t filterId);
- Result startPesFilterHandler(uint32_t filterId);
- Result startTsFilterHandler();
- Result startMediaFilterHandler(uint32_t filterId);
- Result startRecordFilterHandler(uint32_t filterId);
- Result startPcrFilterHandler();
- Result startFilterLoop(uint32_t filterId);
Result startBroadcastInputLoop();
+ static void* __threadLoopBroadcast(void* user);
+ void broadcastInputThreadLoop();
/**
* To create a FilterMQ with the the next available Filter ID.
@@ -147,32 +108,14 @@
*
* Return false is any of the above processes fails.
*/
- bool createFilterMQ(uint32_t bufferSize, uint32_t filterId);
- bool createMQ(FilterMQ* queue, EventFlag* eventFlag, uint32_t bufferSize);
void deleteEventFlag();
- bool writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId);
bool readDataFromMQ();
- bool writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data);
- void maySendInputStatusCallback();
- void maySendFilterStatusCallback(uint32_t filterId);
- DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
- uint32_t highThreshold, uint32_t lowThreshold);
- DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, 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.
*/
- bool readInputFMQ();
- void startTsFilter(vector<uint8_t> data);
bool startFilterDispatcher();
- static void* __threadLoopFilter(void* data);
- static void* __threadLoopInput(void* user);
- static void* __threadLoopBroadcast(void* user);
- void filterThreadLoop(uint32_t filterId);
- void inputThreadLoop();
- void broadcastInputThreadLoop();
+ void startTsFilter(vector<uint8_t> data);
uint32_t mDemuxId;
/**
@@ -196,40 +139,13 @@
* A list of created FilterMQ ptrs.
* The array number is the filter ID.
*/
- vector<uint16_t> mFilterPids;
- vector<vector<uint8_t>> mFilterOutputs;
- vector<unique_ptr<FilterMQ>> mFilterMQs;
- vector<EventFlag*> mFilterEventFlags;
- vector<DemuxFilterEvent> mFilterEvents;
- unique_ptr<FilterMQ> mInputMQ;
- unique_ptr<FilterMQ> mOutputMQ;
- EventFlag* mInputEventFlag;
- EventFlag* mOutputEventFlag;
- /**
- * Demux callbacks used on filter events or IO buffer status
- */
- vector<sp<IDemuxCallback>> mFilterCallbacks;
- sp<IDemuxCallback> mInputCallback;
- sp<IDemuxCallback> mOutputCallback;
- bool mInputConfigured = false;
- bool mOutputConfigured = false;
- DemuxInputSettings mInputSettings;
- DemuxOutputSettings mOutputSettings;
+ std::map<uint32_t, sp<Filter>> mFilters;
// Thread handlers
- pthread_t mInputThread;
- pthread_t mOutputThread;
pthread_t mBroadcastInputThread;
- vector<pthread_t> mFilterThreads;
-
- // FMQ status local records
- DemuxInputStatus mIntputStatus;
- vector<DemuxFilterStatus> mFilterStatus;
/**
* If a specific filter's writing loop is still running
*/
- vector<bool> mFilterThreadRunning;
- bool mInputThreadRunning;
bool mBroadcastInputThreadRunning;
bool mKeepFetchingDataFromFrontend;
/**
@@ -237,28 +153,16 @@
*/
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 mInputStatusLock;
- std::mutex mFilterStatusLock;
std::mutex mBroadcastInputThreadLock;
- std::mutex mFilterThreadLock;
- std::mutex mInputThreadLock;
- /**
- * How many times a filter should write
- * TODO make this dynamic/random/can take as a parameter
- */
- const uint16_t SECTION_WRITE_COUNT = 10;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
int mPesSizeLeft = 0;
vector<uint8_t> mPesOutput;
+
+ const bool DEBUG_FILTER = false;
};
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp
index 085f2c8..e3f5b22 100644
--- a/tv/tuner/1.0/default/Descrambler.cpp
+++ b/tv/tuner/1.0/default/Descrambler.cpp
@@ -50,13 +50,15 @@
return Result::SUCCESS;
}
-Return<Result> Descrambler::addPid(uint16_t /* pid */) {
+Return<Result> Descrambler::addPid(const DemuxPid& /* pid */,
+ const sp<IFilter>& /* optionalSourceFilter */) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
}
-Return<Result> Descrambler::removePid(uint16_t /* pid */) {
+Return<Result> Descrambler::removePid(const DemuxPid& /* pid */,
+ const sp<IFilter>& /* optionalSourceFilter */) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h
index 436adcf..c889820 100644
--- a/tv/tuner/1.0/default/Descrambler.h
+++ b/tv/tuner/1.0/default/Descrambler.h
@@ -40,9 +40,11 @@
virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
- virtual Return<Result> addPid(uint16_t pid) override;
+ virtual Return<Result> addPid(const DemuxPid& pid,
+ const sp<IFilter>& optionalSourceFilter) override;
- virtual Return<Result> removePid(uint16_t pid) override;
+ virtual Return<Result> removePid(const DemuxPid& pid,
+ const sp<IFilter>& optionalSourceFilter) override;
virtual Return<Result> close() override;
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
new file mode 100644
index 0000000..eb38f90
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-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<IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint32_t filterId;
+ Result status;
+
+ filter->getId([&](Result result, uint32_t id) {
+ filterId = id;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return status;
+ }
+
+ mFilters[filterId] = filter;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint32_t filterId;
+ Result status;
+
+ filter->getId([&](Result result, uint32_t id) {
+ filterId = id;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return status;
+ }
+
+ std::map<uint32_t, sp<IFilter>>::iterator it;
+
+ it = mFilters.find(filterId);
+ if (it != mFilters.end()) {
+ mFilters.erase(filterId);
+ }
+
+ 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) {
+ /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
+ pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+ }
+
+ // TODO start another thread to send filter status callback to the framework
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::stop() {
+ ALOGV("%s", __FUNCTION__);
+
+ mDvrThreadRunning = false;
+
+ std::lock_guard<std::mutex> lock(mDvrThreadLock);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Dvr::flush() {
+ ALOGV("%s", __FUNCTION__);
+
+ 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
+ std::unique_ptr<DvrMQ> tmpDvrMQ =
+ std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
+ if (!tmpDvrMQ->isValid()) {
+ ALOGW("Failed to create FMQ of DVR");
+ return false;
+ }
+
+ mDvrMQ = std::move(tmpDvrMQ);
+
+ if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
+ return false;
+ }
+
+ return true;
+}
+
+void* Dvr::__threadLoopPlayback(void* user) {
+ Dvr* const self = static_cast<Dvr*>(user);
+ self->playbackThreadLoop();
+ return 0;
+}
+
+void Dvr::playbackThreadLoop() {
+ ALOGD("[Dvr] playback threadLoop start.");
+ std::lock_guard<std::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;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ immediately
+ // after the DATA_READY from the VTS/framework
+ if (!readPlaybackFMQ() || !startFilterDispatcher()) {
+ ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
+ break;
+ }
+
+ maySendPlaybackStatusCallback();
+ }
+
+ mDvrThreadRunning = false;
+ ALOGD("[Dvr] playback thread ended.");
+}
+
+void Dvr::maySendPlaybackStatusCallback() {
+ std::lock_guard<std::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() {
+ // 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;
+ }
+ startTpidFilter(dataOutputBuffer);
+ }
+
+ return true;
+}
+
+void Dvr::startTpidFilter(vector<uint8_t> data) {
+ std::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) {
+ ALOGW("[Dvr] start ts filter pid: %d", pid);
+ }
+ if (pid == mDemux->getFilterTpid(it->first)) {
+ mDemux->updateFilterOutput(it->first, data);
+ }
+ }
+}
+
+bool Dvr::startFilterDispatcher() {
+ std::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) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // 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.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
new file mode 100644
index 0000000..fbb778c
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
+
+#include <android/hardware/tv/tuner/1.0/IDvr.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 ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+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();
+
+ private:
+ // Demux service
+ sp<Demux> mDemux;
+
+ DvrType mType;
+ uint32_t mBufferSize;
+ sp<IDvrCallback> mCallback;
+ std::map<uint32_t, sp<IFilter>> mFilters;
+
+ void deleteEventFlag();
+ bool readDataFromMQ();
+ void maySendPlaybackStatusCallback();
+ void maySendRecordStatusCallback();
+ PlaybackStatus checkPlaybackStatusChange(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.
+ */
+ bool readPlaybackFMQ();
+ void startTpidFilter(vector<uint8_t> data);
+ bool startFilterDispatcher();
+ static void* __threadLoopPlayback(void* user);
+ static void* __threadLoopBroadcast(void* user);
+ void playbackThreadLoop();
+ void broadcastInputThreadLoop();
+
+ 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;
+ pthread_t mBroadcastInputThread;
+
+ // FMQ status local records
+ PlaybackStatus mPlaybackStatus;
+ /**
+ * If a specific filter's writing loop is still running
+ */
+ bool mDvrThreadRunning;
+ bool mBroadcastInputThreadRunning;
+ 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 mBroadcastInputThreadLock;
+ std::mutex mDvrThreadLock;
+
+ const bool DEBUG_DVR = false;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
new file mode 100644
index 0000000..3d8a977
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -0,0 +1,456 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-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, uint32_t filterId, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, sp<Demux> demux) {
+ mType = type;
+ mFilterId = filterId;
+ mBufferSize = bufferSize;
+ mCallback = cb;
+ mDemux = demux;
+}
+
+Filter::~Filter() {}
+
+Return<void> Filter::getId(getId_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ _hidl_cb(Result::SUCCESS, mFilterId);
+ return Void();
+}
+
+Return<Result> Filter::setDataSource(const sp<IFilter>& filter) {
+ ALOGV("%s", __FUNCTION__);
+
+ mDataSource = filter;
+ mIsDataSourceDemux = false;
+
+ return Result::SUCCESS;
+}
+
+Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ _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:
+ /*mmtpSettings*/
+ break;
+ case DemuxFilterMainType::IP:
+ /*ipSettings*/
+ break;
+ case DemuxFilterMainType::TLV:
+ /*tlvSettings*/
+ break;
+ case DemuxFilterMainType::ALP:
+ /*alpSettings*/
+ 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::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ return mDemux->removeFilter(mFilterId);
+}
+
+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("Failed to create FMQ of filter with id: %d", 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 %d 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) {
+ 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
+ mCallback->onFilterEvent(mFilterEvent);
+ mFilterEvent.events.resize(0);
+ mFilterStatus = DemuxFilterStatus::DATA_READY;
+ mCallback->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) {
+ 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;
+ }
+
+ if (mCallback == nullptr) {
+ ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
+ break;
+ }
+
+ maySendFilterStatusCallback();
+
+ while (mFilterThreadRunning) {
+ std::lock_guard<std::mutex> lock(mFilterEventLock);
+ if (mFilterEvent.events.size() == 0) {
+ continue;
+ }
+ // After successfully write, send a callback and wait for the read to be done
+ 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 %d writing done. Ending thread", mFilterId);
+ break;
+ }
+ }
+ mFilterThreadRunning = false;
+ }
+
+ ALOGD("[Filter] filter thread ended.");
+}
+
+void Filter::maySendFilterStatusCallback() {
+ 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) {
+ mCallback->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);
+ ALOGD("[Filter] handler output updated");
+ mFilterOutput.insert(mFilterOutput.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::RECORD:
+ startRecordFilterHandler();
+ 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 %d 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];
+ ALOGD("[Filter] prefix %d", prefix);
+ if (prefix == 0x000001) {
+ // TODO handle mulptiple Pes filters
+ mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+ mPesSizeLeft += 6;
+ 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;
+ 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()),
+ };
+ 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() {
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ // temp dump meta data
+ .pts = 0,
+ .dataLength = 530,
+ .avMemory = nullptr,
+ .isSecureMemory = false,
+ };
+ mFilterEvent.events.resize(1);
+ mFilterEvent.events[0].media(mediaEvent);
+
+ mFilterOutput.clear();
+ // TODO handle write FQM for media stream
+ return Result::SUCCESS;
+}
+
+Result Filter::startRecordFilterHandler() {
+ DemuxFilterTsRecordEvent tsRecordEvent;
+ tsRecordEvent.pid.tPid(0);
+ tsRecordEvent.indexMask.tsIndexMask(0x01);
+ mFilterEvent.events.resize(1);
+ mFilterEvent.events[0].tsRecord(tsRecordEvent);
+
+ mFilterOutput.clear();
+ return Result::SUCCESS;
+}
+
+Result Filter::startPcrFilterHandler() {
+ // TODO handle starting PCR filter
+ return Result::SUCCESS;
+}
+
+bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
+ // TODO check how many sections has been read
+ ALOGD("[Filter] section hander");
+ 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;
+}
+
+} // 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.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
new file mode 100644
index 0000000..21d4297
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.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 ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+
+class Filter : public IFilter {
+ public:
+ Filter();
+
+ Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize,
+ const sp<IFilterCallback>& cb, sp<Demux> demux);
+
+ ~Filter();
+
+ virtual Return<void> getId(getId_cb _hidl_cb) override;
+
+ virtual Return<Result> setDataSource(const sp<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> close() 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);
+ Result startFilterHandler();
+
+ private:
+ // Tuner service
+ sp<Demux> mDemux;
+ /**
+ * Filter callbacks used on filter events or FMQ status
+ */
+ sp<IFilterCallback> mCallback;
+
+ uint32_t mFilterId;
+ uint32_t mBufferSize;
+ DemuxFilterType mType;
+ DemuxFilterSettings mFilterSettings;
+
+ uint16_t mTpid;
+ sp<IFilter> mDataSource;
+ bool mIsDataSourceDemux = true;
+ vector<uint8_t> mFilterOutput;
+ unique_ptr<FilterMQ> mFilterMQ;
+ EventFlag* mFilterEventFlag;
+ DemuxFilterEvent mFilterEvent;
+
+ // 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;
+
+ /**
+ * 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 startRecordFilterHandler();
+ Result startPcrFilterHandler();
+ 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();
+
+ /**
+ * 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;
+
+ // temp handle single PES filter
+ // TODO handle mulptiple Pes filters
+ int mPesSizeLeft = 0;
+ vector<uint8_t> mPesOutput;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index 07fa7b9..eab43a3 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -75,7 +75,7 @@
FrontendType mType = FrontendType::UNDEFINED;
FrontendId mId = 0;
- const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts";
+ const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts";
string mSourceStreamFile;
std::ifstream mFrontendData;
};
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
index 1446f7f..51931d6 100644
--- a/tv/tuner/1.0/default/Lnb.cpp
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -30,19 +30,25 @@
Lnb::~Lnb() {}
-Return<Result> Lnb::setVoltage(FrontendLnbVoltage /* voltage */) {
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
}
-Return<Result> Lnb::setTone(FrontendLnbTone /* tone */) {
+Return<Result> Lnb::setVoltage(LnbVoltage /* voltage */) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
}
-Return<Result> Lnb::setSatellitePosition(FrontendLnbPosition /* position */) {
+Return<Result> Lnb::setTone(LnbTone /* tone */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(LnbPosition /* position */) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
index 4c251f7..f285cb9 100644
--- a/tv/tuner/1.0/default/Lnb.h
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -29,20 +29,23 @@
namespace V1_0 {
namespace implementation {
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbPosition;
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbTone;
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbVoltage;
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::LnbPosition;
+using ::android::hardware::tv::tuner::V1_0::LnbTone;
+using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
using ::android::hardware::tv::tuner::V1_0::Result;
class Lnb : public ILnb {
public:
Lnb();
- virtual Return<Result> setVoltage(FrontendLnbVoltage voltage) override;
+ virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
- virtual Return<Result> setTone(FrontendLnbTone tone) override;
+ virtual Return<Result> setVoltage(LnbVoltage voltage) override;
- virtual Return<Result> setSatellitePosition(FrontendLnbPosition position) 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;
diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp
new file mode 100644
index 0000000..0b1fd1c
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-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__);
+
+ return Result::SUCCESS;
+}
+
+Return<Result> TimeFilter::clearTimeStamp() {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+}
+
+Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ uint64_t timeStamp = 0;
+
+ _hidl_cb(Result::SUCCESS, timeStamp);
+ 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__);
+
+ 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.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h
new file mode 100644
index 0000000..7131df8
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include "Demux.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+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;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 890c1ed..fa00a6e 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -17,6 +17,7 @@
package android.hardware.tv.tuner@1.0;
import android.hidl.safe_union@1.0;
+import android.hidl.safe_union@1.0::Monostate;
@export
enum Result : int32_t {
@@ -41,9 +42,13 @@
enum FrontendType : uint32_t {
UNDEFINED = 0,
ANALOG,
- /* Advanced Television Systems Committee (ATSC) Standard A/72. */
+ /**
+ * Advanced Television Systems Committee (ATSC) Standard A/72.
+ */
ATSC,
- /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */
+ /**
+ * Advanced Television Systems Committee (ATSC 3.0) Standard A/300.
+ */
ATSC3,
/**
* Digital Video Broadcasting - Cable
@@ -62,15 +67,18 @@
* ETSI EN 302 755 V1.4.1.
*/
DVBT,
- /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+ /**
+ * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
* ARIB STD-B20 is technical document of ISDB-S.
*/
ISDBS,
- /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+ /**
+ * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
* ARIB STD-B44 is technical document of ISDB-S3.
*/
ISDBS3,
- /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
+ /**
+ * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
* ABNT NBR 15603 is technical document of ISDB-T.
*/
ISDBT,
@@ -82,79 +90,153 @@
*/
@export
enum FrontendInnerFec : uint64_t {
- /* Not defined */
+ /**
+ * Not defined
+ */
FEC_UNDEFINED = 0,
- /* hardware is able to detect and set FEC automatically */
+ /**
+ * hardware is able to detect and set FEC automatically
+ */
AUTO = 1 << 0,
- /* 1/2 conv. code rate */
+ /**
+ * 1/2 conv. code rate
+ */
FEC_1_2 = 1 << 1,
- /* 1/3 conv. code rate */
+ /**
+ * 1/3 conv. code rate
+ */
FEC_1_3 = 1 << 2,
- /* 1/4 conv. code rate */
+ /**
+ * 1/4 conv. code rate
+ */
FEC_1_4 = 1 << 3,
- /* 1/5 conv. code rate */
+ /**
+ * 1/5 conv. code rate
+ */
FEC_1_5 = 1 << 4,
- /* 2/3 conv. code rate */
+ /**
+ * 2/3 conv. code rate
+ */
FEC_2_3 = 1 << 5,
- /* 2/5 conv. code rate */
+ /**
+ * 2/5 conv. code rate
+ */
FEC_2_5 = 1 << 6,
- /* 2/9 conv. code rate */
+ /**
+ * 2/9 conv. code rate
+ */
FEC_2_9 = 1 << 7,
- /* 3/4 conv. code rate */
+ /**
+ * 3/4 conv. code rate
+ */
FEC_3_4 = 1 << 8,
- /* 3/5 conv. code rate */
+ /**
+ * 3/5 conv. code rate
+ */
FEC_3_5 = 1 << 9,
- /* 4/5 conv. code rate */
+ /**
+ * 4/5 conv. code rate
+ */
FEC_4_5 = 1 << 10,
- /* 4/15 conv. code rate */
+ /**
+ * 4/15 conv. code rate
+ */
FEC_4_15 = 1 << 11,
- /* 5/6 conv. code rate */
+ /**
+ * 5/6 conv. code rate
+ */
FEC_5_6 = 1 << 12,
- /* 5/9 conv. code rate */
+ /**
+ * 5/9 conv. code rate
+ */
FEC_5_9 = 1 << 13,
- /* 6/7 conv. code rate */
+ /**
+ * 6/7 conv. code rate
+ */
FEC_6_7 = 1 << 14,
- /* 7/8 conv. code rate */
+ /**
+ * 7/8 conv. code rate
+ */
FEC_7_8 = 1 << 15,
- /* 7/9 conv. code rate */
+ /**
+ * 7/9 conv. code rate
+ */
FEC_7_9 = 1 << 16,
- /* 7/15 conv. code rate */
+ /**
+ * 7/15 conv. code rate
+ */
FEC_7_15 = 1 << 17,
- /* 8/9 conv. code rate */
+ /**
+ * 8/9 conv. code rate
+ */
FEC_8_9 = 1 << 18,
- /* 8/15 conv. code rate */
+ /**
+ * 8/15 conv. code rate
+ */
FEC_8_15 = 1 << 19,
- /* 9/10 conv. code rate */
+ /**
+ * 9/10 conv. code rate
+ */
FEC_9_10 = 1 << 20,
- /* 9/20 conv. code rate */
+ /**
+ * 9/20 conv. code rate
+ */
FEC_9_20 = 1 << 21,
- /* 11/15 conv. code rate */
+ /**
+ * 11/15 conv. code rate
+ */
FEC_11_15 = 1 << 22,
- /* 11/20 conv. code rate */
+ /**
+ * 11/20 conv. code rate
+ */
FEC_11_20 = 1 << 23,
- /* 11/45 conv. code rate */
+ /**
+ * 11/45 conv. code rate
+ */
FEC_11_45 = 1 << 24,
- /* 13/18 conv. code rate */
+ /**
+ * 13/18 conv. code rate
+ */
FEC_13_18 = 1 << 25,
- /* 13/45 conv. code rate */
+ /**
+ * 13/45 conv. code rate
+ */
FEC_13_45 = 1 << 26,
- /* 14/45 conv. code rate */
+ /**
+ * 14/45 conv. code rate
+ */
FEC_14_45 = 1 << 27,
- /* 23/36 conv. code rate */
+ /**
+ * 23/36 conv. code rate
+ */
FEC_23_36 = 1 << 28,
- /* 25/36 conv. code rate */
+ /**
+ * 25/36 conv. code rate
+ */
FEC_25_36 = 1 << 29,
- /* 26/45 conv. code rate */
+ /**
+ * 26/45 conv. code rate
+ */
FEC_26_45 = 1 << 30,
- /* 28/45 conv. code rate */
+ /**
+ * 28/45 conv. code rate
+ */
FEC_28_45 = 1 << 31,
- /* 29/45 conv. code rate */
+ /**
+ * 29/45 conv. code rate
+ */
FEC_29_45 = 1 << 32,
- /* 31/45 conv. code rate */
+ /**
+ * 31/45 conv. code rate
+ */
FEC_31_45 = 1 << 33,
- /* 32/45 conv. code rate */
+ /**
+ * 32/45 conv. code rate
+ */
FEC_32_45 = 1 << 34,
- /* 77/90 conv. code rate */
+ /**
+ * 77/90 conv. code rate
+ */
FEC_77_90 = 1 << 35,
};
@@ -164,9 +246,11 @@
@export
enum FrontendAtscModulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set modulation automatically */
- AUTO = 1 << 0,
- MOD_8VSB = 1 << 2,
+ /**
+ * hardware is able to detect and set modulation automatically
+ */
+ AUTO = 1 << 0,
+ MOD_8VSB = 1 << 2,
MOD_16VSB = 1 << 3,
};
@@ -174,8 +258,11 @@
* Signal Settings for an ATSC Frontend.
*/
struct FrontendAtscSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendAtscModulation modulation;
};
@@ -183,7 +270,9 @@
* Capabilities for ATSC Frontend.
*/
struct FrontendAtscCapabilities {
- /** Modulation capability */
+ /**
+ * Modulation capability
+ */
bitfield<FrontendAtscModulation> modulationCap;
};
@@ -193,12 +282,14 @@
@export
enum FrontendAtsc3Modulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set modulation automatically */
- AUTO = 1 << 0,
- MOD_QPSK = 1 << 1,
- MOD_16QAM = 1 << 2,
- MOD_64QAM = 1 << 3,
- MOD_256QAM = 1 << 4,
+ /**
+ * hardware is able to detect and set modulation automatically
+ */
+ AUTO = 1 << 0,
+ MOD_QPSK = 1 << 1,
+ MOD_16QAM = 1 << 2,
+ MOD_64QAM = 1 << 3,
+ MOD_256QAM = 1 << 4,
MOD_1024QAM = 1 << 5,
MOD_4096QAM = 1 << 6,
};
@@ -209,7 +300,9 @@
@export
enum FrontendAtsc3Bandwidth : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set bandwidth automatically */
+ /**
+ * hardware is able to detect and set bandwidth automatically
+ */
AUTO = 1 << 0,
BANDWIDTH_6MHZ = 1 << 1,
BANDWIDTH_7MHZ = 1 << 2,
@@ -222,10 +315,12 @@
@export
enum FrontendAtsc3TimeInterleaveMode : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set TimeInterleaveMode automatically */
+ /**
+ * hardware is able to detect and set TimeInterleaveMode automatically
+ */
AUTO = 1 << 0,
- CTI = 1 << 1,
- HTI = 1 << 2,
+ CTI = 1 << 1,
+ HTI = 1 << 2,
};
/**
@@ -234,20 +329,22 @@
@export
enum FrontendAtsc3CodeRate : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Coderate automatically */
- AUTO = 1 << 0,
- CODERATE_2_15 = 1 << 1,
- CODERATE_3_15 = 1 << 2,
- CODERATE_4_15 = 1 << 3,
- CODERATE_5_15 = 1 << 4,
- CODERATE_6_15 = 1 << 5,
- CODERATE_7_15 = 1 << 6,
- CODERATE_8_15 = 1 << 7,
- CODERATE_9_15 = 1 << 8,
- CODERATE_10_15 = 1 << 9,
- CODERATE_11_15 = 1 << 10,
- CODERATE_12_15 = 1 << 11,
- CODERATE_13_15 = 1 << 12,
+ /**
+ * hardware is able to detect and set Coderate automatically
+ */
+ AUTO = 1 << 0,
+ CODERATE_2_15 = 1 << 1,
+ CODERATE_3_15 = 1 << 2,
+ CODERATE_4_15 = 1 << 3,
+ CODERATE_5_15 = 1 << 4,
+ CODERATE_6_15 = 1 << 5,
+ CODERATE_7_15 = 1 << 6,
+ CODERATE_8_15 = 1 << 7,
+ CODERATE_9_15 = 1 << 8,
+ CODERATE_10_15 = 1 << 9,
+ CODERATE_11_15 = 1 << 10,
+ CODERATE_12_15 = 1 << 11,
+ CODERATE_13_15 = 1 << 12,
};
/**
@@ -256,14 +353,16 @@
@export
enum FrontendAtsc3Fec : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set FEC automatically */
- AUTO = 1 << 0,
+ /**
+ * hardware is able to detect and set FEC automatically
+ */
+ AUTO = 1 << 0,
BCH_LDPC_16K = 1 << 1,
BCH_LDPC_64K = 1 << 2,
CRC_LDPC_16K = 1 << 3,
CRC_LDPC_64K = 1 << 4,
- LDPC_16K = 1 << 5,
- LDPC_64K = 1 << 6,
+ LDPC_16K = 1 << 5,
+ LDPC_64K = 1 << 6,
};
/**
@@ -271,12 +370,18 @@
*/
@export
enum FrontendAtsc3DemodOutputFormat : uint8_t {
- /** Dummy. Scan uses this. */
+ /**
+ * Dummy. Scan uses this.
+ */
UNDEFINED = 0,
- /** ALP format. Typically used in US region. */
+ /**
+ * ALP format. Typically used in US region.
+ */
ATSC3_LINKLAYER_PACKET = 1 << 0,
- /** BaseBand packet format. Typically used in Korea region. */
- BASEBAND_PACKET = 1 << 1,
+ /**
+ * BaseBand packet format. Typically used in Korea region.
+ */
+ BASEBAND_PACKET = 1 << 1,
};
/**
@@ -284,9 +389,13 @@
*/
struct FrontendAtsc3PlpSettings {
uint8_t plpId;
+
FrontendAtsc3Modulation modulation;
+
FrontendAtsc3TimeInterleaveMode interleaveMode;
+
FrontendAtsc3CodeRate codeRate;
+
FrontendAtsc3Fec fec;
};
@@ -294,11 +403,18 @@
* Signal Settings for an ATSC3 Frontend.
*/
struct FrontendAtsc3Settings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
- /** Bandwidth of tuning band. */
+
+ /**
+ * Bandwidth of tuning band.
+ */
FrontendAtsc3Bandwidth bandwidth;
+
FrontendAtsc3DemodOutputFormat demodOutputFormat;
+
vec<FrontendAtsc3PlpSettings> plpSettings;
};
@@ -306,17 +422,34 @@
* Capabilities for ATSC3 Frontend.
*/
struct FrontendAtsc3Capabilities {
- /** Bandwidth capability */
+ /**
+ * Bandwidth capability
+ */
bitfield<FrontendAtsc3Bandwidth> bandwidthCap;
- /** Modulation capability */
+
+ /**
+ * Modulation capability
+ */
bitfield<FrontendAtsc3Modulation> modulationCap;
- /** TimeInterleaveMode capability */
+
+ /**
+ * TimeInterleaveMode capability
+ */
bitfield<FrontendAtsc3TimeInterleaveMode> timeInterleaveModeCap;
- /** CodeRate capability */
+
+ /**
+ * CodeRate capability
+ */
bitfield<FrontendAtsc3CodeRate> codeRateCap;
- /** FEC capability */
+
+ /**
+ * FEC capability
+ */
bitfield<FrontendAtsc3Fec> fecCap;
- /** Demodulator Output Format capability */
+
+ /**
+ * Demodulator Output Format capability
+ */
bitfield<FrontendAtsc3DemodOutputFormat> demodOutputFormatCap;
};
@@ -326,7 +459,9 @@
@export
enum FrontendDvbsModulation : int32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Modulation automatically */
+ /**
+ * hardware is able to detect and set Modulation automatically
+ */
AUTO = 1 << 0,
MOD_QPSK = 1 << 1,
MOD_8PSK = 1 << 2,
@@ -340,7 +475,9 @@
MOD_64APSK = 1 << 10,
MOD_128APSK = 1 << 11,
MOD_256APSK = 1 << 12,
- /** Reserved for Proprietary modulation */
+ /**
+ * Reserved for Proprietary modulation
+ */
MOD_RESERVED = 1 << 13,
};
@@ -374,10 +511,17 @@
*/
struct FrontendDvbsCodeRate {
FrontendInnerFec fec;
+
bool isLinear;
- /* true if enable short frame */
+
+ /**
+ * true if enable short frame
+ */
bool isShortFrames;
- /* bits number in 1000 symbol. 0 if use the default. */
+
+ /**
+ * bits number in 1000 symbol. 0 if use the default.
+ */
uint32_t bitsPer1000Symbol;
};
@@ -396,15 +540,26 @@
* Signal Settings for an DVBS Frontend.
*/
struct FrontendDvbsSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendDvbsModulation modulation;
+
FrontendDvbsCodeRate coderate;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
FrontendDvbsRolloff rolloff;
+
FrontendDvbsPilot pilot;
+
uint32_t inputStreamId;
+
FrontendDvbsStandard standard;
};
@@ -413,8 +568,10 @@
*/
struct FrontendDvbsCapabilities {
bitfield<FrontendDvbsModulation> modulationCap;
+
bitfield<FrontendInnerFec> innerfecCap;
- bitfield<FrontendDvbsStandard> standard;
+
+ bitfield<FrontendDvbsStandard> standard;
};
/**
@@ -423,7 +580,9 @@
@export
enum FrontendDvbcModulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Modulation automatically */
+ /**
+ * hardware is able to detect and set Modulation automatically
+ */
AUTO = 1 << 0,
MOD_16QAM = 1 << 1,
MOD_32QAM = 1 << 2,
@@ -467,14 +626,24 @@
* Signal Settings for an DVBC Frontend.
*/
struct FrontendDvbcSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendDvbcModulation modulation;
+
FrontendInnerFec fec;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
FrontendDvbcOuterFec outerFec;
+
FrontendDvbcAnnex annex;
+
FrontendDvbcSpectralInversion spectralInversion;
};
@@ -483,7 +652,9 @@
*/
struct FrontendDvbcCapabilities {
bitfield<FrontendDvbcModulation> modulationCap;
+
bitfield<FrontendInnerFec> fecCap;
+
bitfield<FrontendDvbcAnnex> annexCap;
};
@@ -493,7 +664,9 @@
@export
enum FrontendDvbtBandwidth : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Bandwidth automatically */
+ /**
+ * hardware is able to detect and set Bandwidth automatically
+ */
AUTO = 1 << 0,
BANDWIDTH_8MHZ = 1 << 1,
BANDWIDTH_7MHZ = 1 << 2,
@@ -509,7 +682,9 @@
@export
enum FrontendDvbtConstellation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Constellation automatically */
+ /**
+ * hardware is able to detect and set Constellation automatically
+ */
AUTO = 1 << 0,
CONSTELLATION_QPSK = 1 << 1,
CONSTELLATION_16QAM = 1 << 2,
@@ -523,7 +698,9 @@
@export
enum FrontendDvbtHierarchy : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Hierarchy automatically */
+ /**
+ * hardware is able to detect and set Hierarchy automatically
+ */
AUTO = 1 << 0,
HIERARCHY_NON_NATIVE = 1 << 1,
HIERARCHY_1_NATIVE = 1 << 2,
@@ -541,7 +718,9 @@
@export
enum FrontendDvbtCoderate : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Hierarchy automatically */
+ /**
+ * hardware is able to detect and set Hierarchy automatically
+ */
AUTO = 1 << 0,
CODERATE_1_2 = 1 << 1,
CODERATE_2_3 = 1 << 2,
@@ -560,7 +739,9 @@
@export
enum FrontendDvbtGuardInterval : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Guard Interval automatically */
+ /**
+ * hardware is able to detect and set Guard Interval automatically
+ */
AUTO = 1 << 0,
INTERVAL_1_32 = 1 << 1,
INTERVAL_1_16 = 1 << 2,
@@ -577,7 +758,9 @@
@export
enum FrontendDvbtTransmissionMode : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Transmission Mode automatically */
+ /**
+ * hardware is able to detect and set Transmission Mode automatically
+ */
AUTO = 1 << 0,
MODE_2K = 1 << 1,
MODE_8K = 1 << 2,
@@ -607,27 +790,50 @@
};
/**
- * Signal Setting for DVBT Frontend.
+ * Signal Settings for DVBT Frontend.
*/
struct FrontendDvbtSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendDvbtTransmissionMode transmissionMode;
+
FrontendDvbtBandwidth bandwidth;
+
FrontendDvbtConstellation constellation;
+
FrontendDvbtHierarchy hierarchy;
- /** Code Rate for High Priority level */
+
+ /**
+ * Code Rate for High Priority level
+ */
FrontendDvbtCoderate hpCoderate;
- /** Code Rate for Low Priority level */
+
+ /**
+ * Code Rate for Low Priority level
+ */
FrontendDvbtCoderate lpCoderate;
+
FrontendDvbtGuardInterval guardInterval;
+
bool isHighPriority;
+
FrontendDvbtStandard standard;
+
bool isMiso;
+
FrontendDvbtPlpMode plpMode;
- /** Physical Layer Pipe (PLP) Id */
+
+ /**
+ * Physical Layer Pipe (PLP) Id
+ */
uint8_t plpId;
- /** Group Id for Physical Layer Pipe (PLP) */
+
+ /**
+ * Group Id for Physical Layer Pipe (PLP)
+ */
uint8_t plpGroupId;
};
@@ -636,12 +842,19 @@
*/
struct FrontendDvbtCapabilities {
bitfield<FrontendDvbtTransmissionMode> transmissionModeCap;
+
bitfield<FrontendDvbtBandwidth> bandwidthCap;
+
bitfield<FrontendDvbtConstellation> constellationCap;
+
bitfield<FrontendDvbtCoderate> coderateCap;
+
bitfield<FrontendDvbtHierarchy> hierarchyCap;
+
bitfield<FrontendDvbtGuardInterval> guardIntervalCap;
+
bool isT2Supported;
+
bool isMisoSupported;
};
@@ -660,11 +873,13 @@
@export
enum FrontendIsdbsModulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Modulation automatically */
- AUTO = 1 << 0,
- MOD_BPSK = 1 << 1,
- MOD_QPSK = 1 << 2,
- MOD_TC8PSK = 1 << 3,
+ /**
+ * hardware is able to detect and set Modulation automatically
+ */
+ AUTO = 1 << 0,
+ MOD_BPSK = 1 << 1,
+ MOD_QPSK = 1 << 2,
+ MOD_TC8PSK = 1 << 3,
};
/**
@@ -673,13 +888,15 @@
@export
enum FrontendIsdbsCoderate : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Code Rate automatically */
- AUTO = 1 << 0,
- CODERATE_1_2 = 1 << 1,
- CODERATE_2_3 = 1 << 2,
- CODERATE_3_4 = 1 << 3,
- CODERATE_5_6 = 1 << 4,
- CODERATE_7_8 = 1 << 5,
+ /**
+ * hardware is able to detect and set Code Rate automatically
+ */
+ AUTO = 1 << 0,
+ CODERATE_1_2 = 1 << 1,
+ CODERATE_2_3 = 1 << 2,
+ CODERATE_3_4 = 1 << 3,
+ CODERATE_5_6 = 1 << 4,
+ CODERATE_7_8 = 1 << 5,
};
/**
@@ -692,17 +909,27 @@
};
/**
- * Signal Setting for ISDBS Frontend.
+ * Signal Settings for ISDBS Frontend.
*/
struct FrontendIsdbsSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
uint16_t streamId;
+
FrontendIsdbsStreamIdType streamIdType;
+
FrontendIsdbsModulation modulation;
+
FrontendIsdbsCoderate coderate;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
FrontendIsdbsRolloff rolloff;
};
@@ -711,6 +938,7 @@
*/
struct FrontendIsdbsCapabilities {
bitfield<FrontendIsdbsModulation> modulationCap;
+
bitfield<FrontendIsdbsCoderate> coderateCap;
};
@@ -729,13 +957,15 @@
@export
enum FrontendIsdbs3Modulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Modulation automatically */
- AUTO = 1 << 5,
- MOD_BPSK = 1 << 1,
- MOD_QPSK = 1 << 2,
- MOD_8PSK = 1 << 3,
- MOD_16APSK = 1 << 4,
- MOD_32APSK = 1 << 5,
+ /**
+ * hardware is able to detect and set Modulation automatically
+ */
+ AUTO = 1 << 5,
+ MOD_BPSK = 1 << 1,
+ MOD_QPSK = 1 << 2,
+ MOD_8PSK = 1 << 3,
+ MOD_16APSK = 1 << 4,
+ MOD_32APSK = 1 << 5,
};
/**
@@ -744,33 +974,45 @@
@export
enum FrontendIsdbs3Coderate : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Code Rate automatically */
- AUTO = 1 << 0,
- CODERATE_1_3 = 1 << 1,
- CODERATE_2_5 = 1 << 2,
- CODERATE_1_2 = 1 << 3,
- CODERATE_3_5 = 1 << 4,
- CODERATE_2_3 = 1 << 5,
- CODERATE_3_4 = 1 << 6,
- CODERATE_7_9 = 1 << 7,
- CODERATE_4_5 = 1 << 8,
- CODERATE_5_6 = 1 << 9,
- CODERATE_7_8 = 1 << 10,
- CODERATE_9_10 = 1 << 11,
+ /**
+ * hardware is able to detect and set Code Rate automatically
+ */
+ AUTO = 1 << 0,
+ CODERATE_1_3 = 1 << 1,
+ CODERATE_2_5 = 1 << 2,
+ CODERATE_1_2 = 1 << 3,
+ CODERATE_3_5 = 1 << 4,
+ CODERATE_2_3 = 1 << 5,
+ CODERATE_3_4 = 1 << 6,
+ CODERATE_7_9 = 1 << 7,
+ CODERATE_4_5 = 1 << 8,
+ CODERATE_5_6 = 1 << 9,
+ CODERATE_7_8 = 1 << 10,
+ CODERATE_9_10 = 1 << 11,
};
/**
- * Signal Setting for ISDBS3 Frontend.
+ * Signal Settings for ISDBS3 Frontend.
*/
struct FrontendIsdbs3Settings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
uint16_t streamId;
+
FrontendIsdbsStreamIdType streamIdType;
+
FrontendIsdbs3Modulation modulation;
+
FrontendIsdbs3Coderate coderate;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
FrontendIsdbs3Rolloff rolloff;
};
@@ -779,6 +1021,7 @@
*/
struct FrontendIsdbs3Capabilities {
bitfield<FrontendIsdbs3Modulation> modulationCap;
+
bitfield<FrontendIsdbs3Coderate> coderateCap;
};
@@ -788,7 +1031,9 @@
@export
enum FrontendIsdbtMode : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Mode automatically */
+ /**
+ * hardware is able to detect and set Mode automatically
+ */
AUTO = 1 << 0,
MODE_1 = 1 << 1,
MODE_2 = 1 << 2,
@@ -801,7 +1046,9 @@
@export
enum FrontendIsdbtBandwidth : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Bandwidth automatically */
+ /**
+ * hardware is able to detect and set Bandwidth automatically
+ */
AUTO = 1 << 0,
BANDWIDTH_8MHZ = 1 << 1,
BANDWIDTH_7MHZ = 1 << 2,
@@ -814,7 +1061,9 @@
@export
enum FrontendIsdbtModulation : uint32_t {
UNDEFINED = 0,
- /** hardware is able to detect and set Modulation automatically */
+ /**
+ * hardware is able to detect and set Modulation automatically
+ */
AUTO = 1 << 0,
MOD_DQPSK = 1 << 1,
MOD_QPSK = 1 << 2,
@@ -822,23 +1071,29 @@
MOD_64QAM = 1 << 4,
};
-/** Code Rate for ISDBT. */
typedef FrontendDvbtCoderate FrontendIsdbtCoderate;
-/** Guard Interval for ISDBT. */
typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval;
/**
- * Signal Setting for ISDBT Frontend.
+ * Signal Settings for ISDBT Frontend.
*/
struct FrontendIsdbtSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendIsdbtModulation modulation;
+
FrontendIsdbtBandwidth bandwidth;
+
FrontendIsdbtMode mode;
+
FrontendIsdbtCoderate coderate;
+
FrontendIsdbtGuardInterval guardInterval;
+
uint32_t serviceAreaId;
};
@@ -847,9 +1102,13 @@
*/
struct FrontendIsdbtCapabilities {
bitfield<FrontendIsdbtMode> modeCap;
+
bitfield<FrontendIsdbtBandwidth> bandwidthCap;
+
bitfield<FrontendIsdbtModulation> constellationCap;
+
bitfield<FrontendIsdbtCoderate> coderateCap;
+
bitfield<FrontendIsdbtGuardInterval> guardIntervalCap;
};
@@ -872,7 +1131,7 @@
UNDEFINED = 0,
BG = 1 << 0,
BG_A2 = 1 << 1,
- BG_NICAM = 1 << 2,
+ BG_NICAM = 1 << 2,
I = 1 << 3,
DK = 1 << 4,
DK1 = 1 << 5,
@@ -890,12 +1149,16 @@
};
/**
- * Signal Setting for Analog Frontend.
+ * Signal Settings for Analog Frontend.
*/
struct FrontendAnalogSettings {
- /** Signal frequency in Hertz */
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
+
FrontendAnalogType type;
+
FrontendAnalogSifStandard sifStandard;
};
@@ -904,21 +1167,30 @@
*/
struct FrontendAnalogCapabilities {
bitfield<FrontendAnalogType> typeCap;
+
bitfield<FrontendAnalogSifStandard> sifStandardCap;
};
/**
- * Signal Setting for Frontend.
+ * Signal Settings for Frontend.
*/
safe_union FrontendSettings {
FrontendAnalogSettings analog;
+
FrontendAtscSettings atsc;
+
FrontendAtsc3Settings atsc3;
+
FrontendDvbsSettings dvbs;
+
FrontendDvbcSettings dvbc;
+
FrontendDvbtSettings dvbt;
+
FrontendIsdbsSettings isdbs;
+
FrontendIsdbs3Settings isdbs3;
+
FrontendIsdbtSettings isdbt;
};
@@ -935,25 +1207,45 @@
* Scan Message Type for Frontend.
*/
enum FrontendScanMessageType : uint32_t {
- /** Scan locked the signal. */
+ /**
+ * Scan locked the signal.
+ */
LOCKED,
- /** Scan stopped. */
+ /**
+ * Scan stopped.
+ */
END,
- /** Scan progress report. */
+ /**
+ * Scan progress report.
+ */
PROGRESS_PERCENT,
- /** Locked frequency report. */
+ /**
+ * Locked frequency report.
+ */
FREQUENCY,
- /** Locked symbol rate. */
+ /**
+ * Locked symbol rate.
+ */
SYMBOL_RATE,
- /** Locked Plp Ids for DVBT2 frontend. */
+ /**
+ * Locked Plp Ids for DVBT2 frontend.
+ */
PLP_IDS,
- /** Locked group Ids for DVBT2 frontend. */
+ /**
+ * Locked group Ids for DVBT2 frontend.
+ */
GROUP_IDS,
- /** Stream Ids. */
+ /**
+ * Stream Ids.
+ */
INPUT_STREAM_IDS,
- /** Locked signal standard. */
+ /**
+ * Locked signal standard.
+ */
STANDARD,
- /** PLP status in a tuned frequency band for ATSC3 frontend. */
+ /**
+ * PLP status in a tuned frequency band for ATSC3 frontend.
+ */
ATSC3_PLP_INFO,
};
@@ -962,6 +1254,7 @@
*/
struct FrontendScanAtsc3PlpInfo {
uint8_t plpId;
+
bool bLlsFlag;
};
@@ -970,21 +1263,39 @@
*/
safe_union FrontendScanMessage {
bool isLocked;
+
bool isEnd;
- /** scan progress percent (0..100) */
+
+ /**
+ * scan progress percent (0..100)
+ */
uint8_t progressPercent;
- /** Signal frequency in Hertz */
+
+ /**
+ * Signal frequency in Hertz
+ */
uint32_t frequency;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
vec<uint8_t> plpIds;
+
vec<uint8_t> groupIds;
+
vec<uint16_t> inputStreamIds;
+
safe_union standard {
FrontendDvbsStandard sStd;
+
FrontendDvbtStandard tStd;
} std;
- /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */
+
+ /**
+ * A list of PLP status in a tuned frequency band for ATSC3 frontend.
+ */
vec<FrontendScanAtsc3PlpInfo> atsc3PlpInfos;
};
@@ -1008,22 +1319,6 @@
* event.
*/
LOST_LOCK,
- /**
- * If frontend detect that incoming Diseqc message is overflow.
- */
- DISEQC_RX_OVERFLOW,
- /**
- * If frontend detect that outgoing Diseqc message isn't delivered on time.
- */
- DISEQC_RX_TIMEOUT,
- /**
- * If frontend detect that the incoming Diseqc message has parity error.
- */
- DISEQC_RX_PARITY_ERROR,
- /**
- * If frontend detect that the LNB is overload.
- */
- LNB_OVERLOAD,
};
/**
@@ -1031,60 +1326,106 @@
*/
@export
enum FrontendStatusType : uint32_t {
- /** Lock status for Demod. */
+ /**
+ * Lock status for Demod.
+ */
DEMOD_LOCK,
- /** Signal to Noise Ratio. */
+ /**
+ * Signal to Noise Ratio.
+ */
SNR,
- /** Bit Error Ratio. */
+ /**
+ * Bit Error Ratio.
+ */
BER,
- /** Packages Error Ratio. */
+ /**
+ * Packages Error Ratio.
+ */
PER,
- /** Bit Error Ratio before FEC. */
+ /**
+ * Bit Error Ratio before FEC.
+ */
PRE_BER,
- /*
+ /**
* Signal Quality (0..100). Good data over total data in percent can be
* used as a way to present Signal Quality.
*/
SIGNAL_QUALITY,
- /** Signal Strength. */
+ /**
+ * Signal Strength.
+ */
SIGNAL_STRENGTH,
- /** Symbol Rate. */
+ /**
+ * Symbol Rate.
+ */
SYMBOL_RATE,
- /** Forward Error Correction Type. */
+ /**
+ * Forward Error Correction Type.
+ */
FEC,
- /** Modulation Type. */
+ /**
+ * Modulation Type.
+ */
MODULATION,
- /** Spectral Inversion Type. */
+ /**
+ * Spectral Inversion Type.
+ */
SPECTRAL,
- /** LNB Voltage. */
+ /**
+ * LNB Voltage.
+ */
LNB_VOLTAGE,
- /** Physical Layer Pipe ID. */
+ /**
+ * Physical Layer Pipe ID.
+ */
PLP_ID,
- /** Status for Emergency Warning Broadcasting System. */
+ /**
+ * Status for Emergency Warning Broadcasting System.
+ */
EWBS,
- /** Automatic Gain Control. */
+ /**
+ * Automatic Gain Control.
+ */
AGC,
- /** Low Noise Amplifier. */
+ /**
+ * Low Noise Amplifier.
+ */
LNA,
- /** Lock status for stream. */
- STREAM_LOCK,
- /** Error status by layer. */
+ /**
+ * Error status by layer.
+ */
LAYER_ERROR,
- /** CN value by VBER. */
+ /**
+ * CN value by VBER.
+ */
VBER_CN,
- /** CN value by LBER. */
+ /**
+ * CN value by LBER.
+ */
LBER_CN,
- /** CN value by XER. */
+ /**
+ * CN value by XER.
+ */
XER_CN,
- /** Moduration Error Ratio. */
+ /**
+ * Moduration Error Ratio.
+ */
MER,
- /** Difference between tuning frequency and actual locked frequency. */
+ /**
+ * Difference between tuning frequency and actual locked frequency.
+ */
FREQ_OFFSET,
- /* Hierarchy for DVBT. */
+ /**
+ * Hierarchy for DVBT.
+ */
HIERARCHY,
- /** Lock status for RF. */
+ /**
+ * Lock status for RF.
+ */
RF_LOCK,
- /** PLP information in a frequency band for ATSC3.0 frontend. */
+ /**
+ * PLP information in a frequency band for ATSC3.0 frontend.
+ */
ATSC3_PLP_INFO,
};
@@ -1092,23 +1433,34 @@
* Status for each tuning PLPs
*/
struct FrontendStatusAtsc3PlpInfo {
- /** PLP Id value. */
+ /**
+ * PLP Id value.
+ */
uint8_t plpId;
- /** Demod Lock/Unlock status of this particular PLP. */
+
+ /**
+ * Demod Lock/Unlock status of this particular PLP.
+ */
bool isLocked;
- /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */
+
+ /**
+ * Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation.
+ */
uint32_t uec;
};
-
/**
* Modulation Type for Frontend's status.
*/
safe_union FrontendModulationStatus {
FrontendDvbcModulation dvbc;
+
FrontendDvbsModulation dvbs;
+
FrontendIsdbsModulation isdbs;
+
FrontendIsdbs3Modulation isdbs3;
+
FrontendIsdbtModulation isdbt;
};
@@ -1116,46 +1468,99 @@
* The status for Frontend.
*/
safe_union FrontendStatus {
- /** Lock status for Demod in True/False. */
+ /**
+ * Lock status for Demod in True/False.
+ */
bool isDemodLocked;
- /** SNR value measured by 0.001 dB. */
+
+ /**
+ * SNR value measured by 0.001 dB.
+ */
int32_t snr;
- /** The number of error bit per 1 billion bits. */
+
+ /**
+ * The number of error bit per 1 billion bits.
+ */
uint32_t ber;
- /** The number of error package per 1 billion packages. */
+
+ /**
+ * The number of error package per 1 billion packages.
+ */
uint32_t per;
- /** The number of error bit per 1 billion bits before FEC. */
+
+ /**
+ * The number of error bit per 1 billion bits before FEC.
+ */
uint32_t preBer;
- /** Signal Quality in percent. */
+
+ /**
+ * Signal Quality in percent.
+ */
uint32_t signalQuality;
- /** Signal Strength measured by 0.001 dBm. */
+
+ /**
+ * Signal Strength measured by 0.001 dBm.
+ */
int32_t signalStrength;
- /** Symbols per second */
+
+ /**
+ * Symbols per second
+ */
uint32_t symbolRate;
+
FrontendInnerFec innerFec;
+
FrontendModulationStatus modulation;
+
FrontendDvbcSpectralInversion inversion;
- FrontendLnbVoltage lnbVoltage;
+
+ LnbVoltage lnbVoltage;
+
uint8_t plpId;
+
bool isEWBS;
- /** AGC value is normalized from 0 to 255. */
+
+ /**
+ * AGC value is normalized from 0 to 255.
+ */
uint8_t agc;
+
bool isLnaOn;
- bool isStreamLock;
+
vec<bool> isLayerError;
- /** CN value by VBER measured by 0.001 dB */
+
+ /**
+ * CN value by VBER measured by 0.001 dB
+ */
int32_t vberCn;
- /** CN value by LBER measured by 0.001 dB */
+
+ /**
+ * CN value by LBER measured by 0.001 dB
+ */
int32_t lberCn;
- /** CN value by XER measured by 0.001 dB */
+
+ /**
+ * CN value by XER measured by 0.001 dB
+ */
int32_t xerCn;
- /** MER value measured by 0.001 dB */
+
+ /**
+ * MER value measured by 0.001 dB
+ */
int32_t mer;
- /** Frequency difference in Hertz. */
+
+ /**
+ * Frequency difference in Hertz.
+ */
int32_t freqOffset;
+
FrontendDvbtHierarchy hierarchy;
+
bool isRfLocked;
- /** A list of PLP status for tuned PLPs for ATSC3 frontend. */
+
+ /**
+ * A list of PLP status for tuned PLPs for ATSC3 frontend.
+ */
vec<FrontendStatusAtsc3PlpInfo> plpInfo;
};
@@ -1164,32 +1569,60 @@
*/
struct FrontendInfo {
FrontendType type;
- /** Frequency in Hertz */
+
+ /**
+ * Frequency in Hertz
+ */
uint32_t minFrequency;
- /** Frequency in Hertz */
+
+ /**
+ * Frequency in Hertz
+ */
uint32_t maxFrequency;
- /** Minimum symbols per second */
+
+ /**
+ * Minimum symbols per second
+ */
uint32_t minSymbolRate;
- /** Maximum symbols per second */
+
+ /**
+ * Maximum symbols per second
+ */
uint32_t maxSymbolRate;
- /** Range in Hertz */
+
+ /**
+ * Range in Hertz
+ */
uint32_t acquireRange;
- /*
+
+ /**
* Frontends are assigned with the same exclusiveGroupId if they can't
* function at same time. For instance, they share same hardware module.
*/
uint32_t exclusiveGroupId;
- /** A list of supported status types which client can inquiry */
+
+ /**
+ * A list of supported status types which client can inquiry
+ */
vec<FrontendStatusType> statusCaps;
+
safe_union FrontendCapabilities {
FrontendAnalogCapabilities analogCaps;
+
FrontendAtscCapabilities atscCaps;
+
FrontendAtsc3Capabilities atsc3Caps;
+
FrontendDvbsCapabilities dvbsCaps;
+
FrontendDvbcCapabilities dvbcCaps;
+
FrontendDvbtCapabilities dvbtCaps;
+
FrontendIsdbsCapabilities isdbsCaps;
+
FrontendIsdbs3Capabilities isdbs3Caps;
+
FrontendIsdbtCapabilities isdbtCaps;
} frontendCaps;
};
@@ -1204,7 +1637,7 @@
* Power Voltage Type for LNB.
*/
@export
-enum FrontendLnbVoltage : uint32_t {
+enum LnbVoltage : uint32_t {
NONE,
VOLTAGE_5V,
VOLTAGE_11V,
@@ -1220,7 +1653,7 @@
* Tone Type for LNB.
*/
@export
-enum FrontendLnbTone : int32_t {
+enum LnbTone : int32_t {
NONE,
CONTINUOUS,
};
@@ -1229,41 +1662,92 @@
* The Position of LNB.
*/
@export
-enum FrontendLnbPosition : int32_t {
+enum LnbPosition : int32_t {
UNDEFINED,
POSITION_A,
POSITION_B,
};
+/**
+ * Lnb Event Type.
+ */
+@export
+enum LnbEventType : uint32_t {
+ DISEQC_RX_OVERFLOW,
+ /**
+ * If LNB detect that outgoing Diseqc message isn't delivered on time.
+ */
+ DISEQC_RX_TIMEOUT,
+ /**
+ * If LNB detect that the incoming Diseqc message has parity error.
+ */
+ DISEQC_RX_PARITY_ERROR,
+ /**
+ * If LNB detect that the LNB is overload.
+ */
+ LNB_OVERLOAD,
+};
+
/* Demux ID is used to associate with a hardware demux resource. */
typedef uint32_t DemuxId;
-/* Filter ID is used to associate with a hardware filter resource. */
-typedef uint32_t DemuxFilterId;
-
/**
- * Filter Type according to ISO/IEC 13818-1
+ * Filter Main Type specifies the protocol that the filter use to extract data
+ * from input stream.
*/
@export
-enum DemuxFilterType : uint32_t {
+enum DemuxFilterMainType : uint32_t {
/**
- * A filter to filter section data out from input stream.
+ * Transport Stream according to ISO/IEC 13818-1.
+ */
+ TS = 1 << 0,
+ /**
+ * MPEG Media Transport Protocol according to ISO/IEC 23008-1.
+ */
+ MMTP = 1 << 1,
+ /**
+ * Internet Protocol.
+ */
+ IP = 1 << 2,
+ /**
+ * Type Length Value according to ITU-R BT.1869.
+ */
+ TLV = 1 << 3,
+ /**
+ * ATSC Link-Layer Protocol according to A/330 ATSC3.0.
+ */
+ ALP = 1 << 4,
+};
+
+/**
+ * TS Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxTsFilterType : uint32_t {
+ UNDEFINED,
+ /**
+ * A filter to filter Section data out from input stream, and queue the
+ * data to the filter's FMQ (Fast Message Queue).
*/
SECTION,
/**
- * A filter to filter PES data out from input stream.
+ * A filter to filter Packetized Elementary Stream data out from input
+ * stream, and queue the data to the filter's FMQ.
*/
PES,
/**
- * A filter to filter TS payload out from input stream.
+ * A filter to filter a Transport Stream out from input stream, and queue
+ * the data to the filter's FMQ.
*/
TS,
/**
- * A filter to filter Audio Metadata out from input stream.
+ * A filter to filter Audio data out from input stream, and send Audio's
+ * Metadata to client through onFilterEvent.
*/
AUDIO,
/**
- * A filter to filter Video Metadata out from input stream.
+ * A filter to filter Video data out from input stream, and send Video's
+ * Metadata to client through onFilterEvent.
*/
VIDEO,
/**
@@ -1271,20 +1755,172 @@
*/
PCR,
/**
- * A filter to filter data directly to output buffer for record.
+ * A filter to filter data out from input stream, and queue the data to the
+ * buffer of the record.
*/
RECORD,
};
+/**
+ * MMTP Filter Type according to ISO/IEC 23008-1
+ */
+@export
+enum DemuxMmtpFilterType : uint32_t {
+ UNDEFINED,
+ /**
+ * A filter to filter signaling data out from input stream, and queue the
+ * data to the filter's FMQ (Fast Message Queue).
+ */
+ SECTION,
+ /**
+ * A filter to filter MFU (Media fragment unit) out from input stream, and
+ * queue the data to the filter's FMQ.
+ */
+ PES,
+ /**
+ * A filter to filter a MMTP stream out from input stream, and queue the
+ * data to the filter's FMQ.
+ */
+ MMTP,
+ /**
+ * A filter to filter Audio data out from input stream, and send Audio's
+ * Metadata to client through onFilterEvent.
+ */
+ AUDIO,
+ /**
+ * A filter to filter Video data out from input stream, and send Video's
+ * Metadata to client through onFilterEvent.
+ */
+ VIDEO,
+ /**
+ * A filter to filter data out from input stream, and queue the data to the
+ * buffer of the record.
+ */
+ RECORD,
+ /**
+ * A filter to filter application data out from input stream, and queue the
+ * data to the filter's FMQ.
+ */
+ DOWNLOAD,
+};
+
+/**
+ * IP Filter Type.
+ */
+@export
+enum DemuxIpFilterType : uint32_t {
+ UNDEFINED,
+ /**
+ * A filter to filter section data out from input stream, and queue the
+ * data to the filter's FMQ (Fast Message Queue).
+ */
+ SECTION,
+ /**
+ * A filter to set NTP (Network Time Procotol) channel from input stream.
+ */
+ NTP,
+ /**
+ * A filter to strip out IP message header and queue the data to the
+ * filter's FMQ.
+ */
+ IP_PAYLOAD,
+ /**
+ * A filter to filter a IP stream out from input stream. The output can be
+ * either upper stream of another filter or queued to the filter's FMQ.
+ */
+ IP,
+ /**
+ * A filter to strip out IP message header and be a data source of another
+ * filter.
+ */
+ PAYLOAD_THROUGH,
+};
+
+/**
+ * TLV Filter Type according to ITU-R BT.1869.
+ */
+@export
+enum DemuxTlvFilterType : uint32_t {
+ UNDEFINED,
+ /**
+ * A filter to filter signaling data out from input stream, and queue the
+ * data to the filter's FMQ (Fast Message Queue).
+ */
+ SECTION,
+ /**
+ * A filter to filter a TLV stream out from input stream. The output can be
+ * either upper stream of another filter or queued to the filter's FMQ.
+ */
+ TLV,
+ /**
+ * A filter to strip out TLV message header and be a data source of another
+ * filter.
+ */
+ PAYLOAD_THROUGH,
+};
+
+/**
+ * ALP Filter Type according to A/330 ATSC3.0.
+ */
+@export
+enum DemuxAlpFilterType : uint32_t {
+ UNDEFINED,
+ /**
+ * A filter to filter signaling data out from input stream, and queue the
+ * data to the filter's FMQ (Fast Message Queue).
+ */
+ SECTION,
+ /**
+ * A filter to set PTP (Precision Time Protocol) channel from input stream.
+ */
+ PTP,
+ /**
+ * A filter to strip out ALP message header and be a data source of another
+ * filter.
+ */
+ PAYLOAD_THROUGH,
+};
+
+/**
+ * Demux Filter Type.
+ */
+struct DemuxFilterType {
+ DemuxFilterMainType mainType;
+
+ safe_union DemuxFilterSubType {
+ DemuxTsFilterType tsFilterType;
+
+ DemuxMmtpFilterType mmtpFilterType;
+
+ DemuxIpFilterType ipFilterType;
+
+ DemuxTlvFilterType tlvFilterType;
+
+ DemuxAlpFilterType alpFilterType;
+ } subType;
+};
+
/* Packet ID is used to specify packets in transport stream. */
typedef uint16_t DemuxTpid;
+/* Packet ID is used to specify packets in MMTP */
+typedef uint16_t DemuxMmtpPid;
+
+/**
+ * Demux Packet ID.
+ */
+safe_union DemuxPid {
+ DemuxTpid tPid;
+
+ DemuxMmtpPid mmtpPid;
+};
+
@export
enum Constant : uint16_t {
/**
* An invalid packet ID in transport stream according to ISO/IEC 13818-1.
*/
- INVALID_TPID = 0xFFFF,
+ INVALID_TS_PID = 0xFFFF,
/**
* An invalid Stream ID.
*/
@@ -1304,7 +1940,7 @@
* The available data amount in the filter buffer is at low level which is
* set to 25 percent by default.
*/
- LOW_WATER = 1 << 1,
+ LOW_WATER = 1 << 1,
/**
* The available data amount in the filter buffer is at high level which is
* set to 75 percent by default.
@@ -1314,18 +1950,122 @@
* The data in the filter buffer is full and newly filtered data is being
* discarded.
*/
- OVERFLOW = 1 << 3,
+ OVERFLOW = 1 << 3,
};
/**
- * Bits Setting for Section Filter.
+ * Indexes can be tagged through TS (Transport Stream) header.
+ */
+@export
+enum DemuxTsIndex : uint32_t {
+ FIRST_PACKET = 1 << 0,
+ PAYLOAD_UNIT_START_INDICATOR = 1 << 1,
+ CHANGE_TO_NOT_SCRAMBLED = 1 << 2,
+ CHANGE_TO_EVEN_SCRAMBLED = 1 << 3,
+ CHANGE_TO_ODD_SCRAMBLED = 1 << 4,
+ DISCONTINUITY_INDICATOR = 1 << 5,
+ RANDOM_ACCESS_INDICATOR = 1 << 6,
+ PRIORITY_INDICATOR = 1 << 7,
+ PCR_FLAG = 1 << 8,
+ OPCR_FLAG = 1 << 9,
+ SPLICING_POINT_FLAG = 1 << 10,
+ PRIVATE_DATA = 1 << 11,
+ ADAPTATION_EXTENSION_FLAG = 1 << 12,
+};
+
+/**
+ * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
+ * according to ISO/IEC 13818-1.
+ */
+@export
+enum DemuxScIndex : uint32_t {
+ /**
+ * Start Code is for a new I Frame
+ */
+ I_FRAME = 1 << 0,
+ /**
+ * Start Code is for a new P Frame
+ */
+ P_FRAME = 1 << 1,
+ /**
+ * Start Code is for a new B Frame
+ */
+ B_FRAME = 1 << 2,
+ /**
+ * Start Code is for a new Sequence
+ */
+ SEQUENCE = 1 << 3,
+};
+
+/**
+ * Indexes can be tagged by NAL unit group in HEVC
+ * according to ISO/IEC 23008-2.
+ */
+@export
+enum DemuxScHevcIndex : uint32_t {
+ SPS = 1 << 0,
+ AUD = 1 << 1,
+ SLICE_CE_BLA_W_LP = 1 << 2,
+ SLICE_BLA_W_RADL = 1 << 3,
+ SLICE_BLA_N_LP = 1 << 4,
+ SLICE_IDR_W_RADL = 1 << 5,
+ SLICE_IDR_N_LP = 1 << 6,
+ SLICE_TRAIL_CRA = 1 << 7,
+};
+
+/**
+ * Index type to be used in the filter for record
+ */
+@export
+enum DemuxRecordIndexType : uint32_t {
+ /**
+ * Don't use index
+ */
+ NONE,
+ /**
+ * Use TS index
+ */
+ TS,
+ /**
+ * Use Start Code index
+ */
+ SC,
+ /**
+ * Use Start Code index for HEVC
+ */
+ SC_HEVC,
+};
+
+/**
+ * Filter Settings for Record data.
+ */
+struct DemuxFilterRecordSettings {
+ DemuxRecordIndexType indexType;
+
+ safe_union IndexMask {
+ bitfield<DemuxTsIndex> tsIndexMask;
+
+ bitfield<DemuxScIndex> scIndexMask;
+
+ bitfield<DemuxScHevcIndex> scHevcIndexMask;
+ } indexMask;
+};
+
+/**
+ * Bits Settings for Section Filter.
*/
struct DemuxFilterSectionBits {
- /* The bytes are configured for Section Filter */
+ /**
+ * The bytes are configured for Section Filter
+ */
vec<uint8_t> filter;
- /* Active bits in the configured bytes to be used for filtering */
+
+ /**
+ * Active bits in the configured bytes to be used for filtering
+ */
vec<uint8_t> mask;
- /*
+
+ /**
* Do positive match at the bit position of the configured bytes when the
* bit at same position of the mode is 0.
* Do negative match at the bit position of the configured bytes when the
@@ -1338,45 +2078,56 @@
* Filter Settings for Section data according to ISO/IEC 13818-1.
*/
struct DemuxFilterSectionSettings {
- DemuxTpid tpid;
- DemuxFilterSectionBits bits;
- /* Table ID for Section Filter */
- uint16_t tableId;
- /* Version number for Section Filter */
- uint16_t version;
- /* true if the filter checks CRC and discards data with wrong CRC */
+ safe_union Condition {
+ DemuxFilterSectionBits sectionBits;
+
+ struct TableInfo {
+ /**
+ * Table ID for Section Filter
+ */
+ uint16_t tableId;
+
+ /**
+ * Version number for Section Filter
+ */
+ uint16_t version;
+ } tableInfo;
+ } condition;
+
+ /**
+ * true if the filter checks CRC and discards data with wrong CRC
+ */
bool isCheckCrc;
- /* true if the filter repeats the data with the same version */
+
+ /**
+ * true if the filter repeats the data with the same version
+ */
bool isRepeat;
- /* true if the filter output raw data */
+
+ /**
+ * true if the filter send onFilterStatus instead of onFilterEvent.
+ */
bool isRaw;
};
-/* Stream ID is used to specify one elementary stream */
typedef uint16_t DemuxStreamId;
/**
* Filter Settings for a PES Data.
*/
struct DemuxFilterPesDataSettings {
- DemuxTpid tpid;
DemuxStreamId streamId;
- /* true if the filter output raw data */
+
+ /**
+ * true if the filter send onFilterStatus instead of onFilterEvent.
+ */
bool isRaw;
};
/**
- * Filter Settings for a TS Data.
+ * Filter Settings for a Video and Audio.
*/
-struct DemuxFilterTsSettings {
- DemuxTpid tpid;
-};
-
-/**
- * Filter Settings for a Audio.
- */
-struct DemuxFilterAudioSettings {
- DemuxTpid tpid;
+struct DemuxFilterAvSettings {
/**
* true if the filter output goes to decoder directly in pass through mode.
*/
@@ -1384,107 +2135,181 @@
};
/**
- * Filter Settings for a Video.
+ * Filter Settings for a Download.
*/
-struct DemuxFilterVideoSettings {
+struct DemuxFilterDownloadSettings {
+ uint32_t downloadId;
+};
+
+/**
+ * IP Settings for a IP filter.
+ */
+struct DemuxIpAddress {
+ safe_union SrcIpAddress {
+ uint8_t[4] v4;
+
+ uint8_t[16] v6;
+ } srcIpAddress;
+
+ safe_union DstIpAddress {
+ uint8_t[4] v4;
+
+ uint8_t[16] v6;
+ } dstIpAddress;
+
+ uint16_t srcPort;
+
+ uint16_t dstPort;
+};
+
+/**
+ * Filter Settings for a TS filter.
+ */
+struct DemuxTsFilterSettings {
DemuxTpid tpid;
+
+ safe_union FilterSettings {
+ /**
+ * Not additional parameters. it's used by PCR, TS subtype filters.
+ */
+ Monostate noinit;
+
+ DemuxFilterSectionSettings section;
+
+ DemuxFilterAvSettings av;
+
+ DemuxFilterPesDataSettings pesData;
+
+ DemuxFilterRecordSettings record;
+ } filterSettings;
+};
+
+/**
+ * Filter Settings for a MMTP filter.
+ */
+struct DemuxMmtpFilterSettings {
+ DemuxMmtpPid mmtpPid;
+
+ safe_union FilterSettings {
+ /**
+ * Not additional parameters. it's used by MMTP subtype filters.
+ */
+ Monostate noinit;
+
+ DemuxFilterSectionSettings section;
+
+ DemuxFilterAvSettings av;
+
+ DemuxFilterPesDataSettings pesData;
+
+ DemuxFilterRecordSettings record;
+
+ DemuxFilterDownloadSettings download;
+ } filterSettings;
+};
+
+/**
+ * Filter Settings for a IP filter.
+ */
+struct DemuxIpFilterSettings {
+ DemuxIpAddress ipAddr;
+
+ safe_union FilterSettings {
+ /**
+ * Not additional parameters. it's used by NTP, IP_PAYLOAD,
+ * PAYLOAD_THROUGH subtype filters.
+ */
+ Monostate noinit;
+
+ DemuxFilterSectionSettings section;
+
+ DemuxFilterPesDataSettings pesData;
+
+ /**
+ * true if the data from IP subtype go to next filter directly
+ */
+ bool bPassthrough;
+ } filterSettings;
+};
+
+/**
+ * Filter Settings for a TLV filter.
+ */
+struct DemuxTlvFilterSettings {
+ uint8_t packetType;
+
/**
- * true if the filter output goes to decoder directly in pass through mode.
+ * true if the filtered data is commpressed ip packet
*/
- bool isPassthrough;
+ bool bIsCompressedIpPacket;
+
+ safe_union FilterSettings {
+ /**
+ * Not additional parameters. it's used by PAYLOAD_THROUGH subtype
+ * filters.
+ */
+ Monostate noinit;
+
+ DemuxFilterSectionSettings section;
+
+ /**
+ * true if the data from TLV subtype go to next filter directly
+ */
+ bool bPassthrough;
+ } filterSettings;
};
/**
- * Filter Settings for a PCR (Program Clock Reference).
- */
-struct DemuxFilterPcrSettings {
- DemuxTpid tpid;
-};
-
-/**
- * Indexes can be tagged through TS (Transport Stream) header.
+ * ALP Length Type
*/
@export
-enum DemuxTsIndex : uint32_t {
- FIRST_PACKET = 1 << 0,
- PAYLOAD_UNIT_START_INDICATOR = 1 << 1,
- CHANGE_TO_NOT_SCRAMBLED = 1 << 2,
- CHANGE_TO_EVEN_SCRAMBLED = 1 << 3,
- CHANGE_TO_ODD_SCRAMBLED = 1 << 4,
- DISCONTINUITY_INDICATOR = 1 << 5,
- RANDOM_ACCESS_INDICATOR = 1 << 6,
- PRIORITY_INDICATOR = 1 << 7,
- PCR_FLAG = 1 << 8,
- OPCR_FLAG = 1 << 9,
- SPLICING_POINT_FLAG = 1 << 10,
- PRIVATE_DATA = 1 << 11,
- ADAPTATION_EXTENSION_FLAG = 1 << 12,
+enum DemuxAlpLengthType : uint8_t {
+ UNDEFINED = 0,
+ /**
+ * Length does NOT include additional header. Used in US region.
+ */
+ WITHOUT_ADDITIONAL_HEADER,
+ /**
+ * Length includes additional header. Used in Korea region.
+ */
+ WITH_ADDITIONAL_HEADER,
};
/**
- * A mask of TS indexes
- *
- * It's a combination of TS indexes.
+ * Filter Settings for a ALP filter.
*/
-typedef bitfield<DemuxTsIndex> DemuxTsIndexMask;
+struct DemuxAlpFilterSettings {
+ /**
+ * 0: IpV4, 2:Compressed Ip, 4:Signaling.
+ */
+ uint8_t packetType;
-/**
- * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
- * according to ISO/IEC 13818-1.
- */
-@export
-enum DemuxScIndex : uint32_t {
- /* Start Code is for a new I Frame */
- I_FRAME = 1 << 0,
- /* Start Code is for a new P Frame */
- P_FRAME = 1 << 1,
- /* Start Code is for a new B Frame */
- B_FRAME = 1 << 2,
- /* Start Code is for a new Sequence */
- SEQUENCE = 1 << 3,
-};
+ DemuxAlpLengthType lengthType;
-/**
- * A mask of Start Code Indexes
- *
- * It's a combination of Start Code Indexes.
- */
-typedef bitfield<DemuxScIndex> DemuxScIndexMask;
+ safe_union FilterSettings {
+ /**
+ * Not additional parameters. it's used by PTP, PAYLOAD_THROUGH subtype
+ * filters.
+ */
+ Monostate noinit;
-/* Index type to be used in the filter for record */
-@export
-enum DemuxRecordIndexType : uint32_t {
- /* Don't use index */
- NONE,
- /* Use TS index */
- TS,
- /* Use Start Code index */
- SC,
-};
-
-/**
- * Filter Settings for Record data.
- */
-struct DemuxFilterRecordSettings {
- DemuxTpid tpid;
- DemuxRecordIndexType indexType;
- safe_union IndexMask {
- DemuxTsIndexMask tsIndexMask;
- DemuxScIndexMask scIndexMask;
- } indexMask;
+ DemuxFilterSectionSettings section;
+ } filterSettings;
};
/**
* Filter Settings.
*/
safe_union DemuxFilterSettings {
- DemuxFilterSectionSettings section;
- DemuxFilterPesDataSettings pesData;
- DemuxFilterTsSettings ts;
- DemuxFilterAudioSettings audio;
- DemuxFilterVideoSettings video;
- DemuxFilterPcrSettings pcr;
- DemuxFilterRecordSettings record;
+ DemuxTsFilterSettings ts;
+
+ DemuxMmtpFilterSettings mmtp;
+
+ DemuxIpFilterSettings ip;
+
+ DemuxTlvFilterSettings tlv;
+
+ DemuxAlpFilterSettings alp;
};
/**
@@ -1493,38 +2318,106 @@
*/
@export
enum DemuxQueueNotifyBits : uint32_t {
- /* client writes data and notify HAL the data is ready. */
+ /**
+ * client writes data and notify HAL the data is ready.
+ */
DATA_READY = 1 << 0,
- /* client reads data and notify HAL the data is consumed. */
- DATA_CONSUMED = 1 << 1
+ /**
+ * client reads data and notify HAL the data is consumed.
+ */
+ DATA_CONSUMED = 1 << 1,
};
/**
* Filter Event for Section Filter.
*/
struct DemuxFilterSectionEvent {
- /* Table ID of filtered data */
+ /**
+ * Table ID of filtered data
+ */
uint16_t tableId;
- /* Version number of filtered data */
+
+ /**
+ * Version number of filtered data
+ */
uint16_t version;
- /* Section number of filtered data */
+
+ /**
+ * Section number of filtered data
+ */
uint16_t sectionNum;
- /* Data size in bytes of filtered data */
+
+ /**
+ * Data size in bytes of filtered data
+ */
uint16_t dataLength;
};
/**
+ * Extra Meta Data from AD (Audio Descriptor) according to
+ * ETSI TS 101 154 V2.1.1.
+ */
+struct AudioExtraMetaData {
+ uint8_t adFade;
+
+ uint8_t adPan;
+
+ uint8_t versionTextTag;
+
+ uint8_t adGainCenter;
+
+ uint8_t adGainFront;
+
+ uint8_t adGainSurround;
+};
+
+/**
* Filter Event for Audio or Video Filter.
*/
struct DemuxFilterMediaEvent {
- /* Presentation Time Stamp for audio or video frame. It based on 90KHz has
+ DemuxStreamId streamId;
+
+ /**
+ * true if PTS is present in PES header.
+ */
+ bool isPtsPresent;
+
+ /**
+ * Presentation Time Stamp for audio or video frame. It based on 90KHz has
* the same format as PTS (Presentation Time Stamp).
*/
uint64_t pts;
- /* Data size in bytes of audio or video frame */
- uint16_t dataLength;
- /* A handle associated to the memory where audio or video data stays. */
- handle secureMemory;
+
+ /**
+ * Data size in bytes of audio or video frame
+ */
+ uint32_t dataLength;
+
+ /**
+ * A handle associated to the memory where audio or video data stays.
+ */
+ handle avMemory;
+
+ /**
+ * True if the avMemory is in secure area, and isn't mappable.
+ */
+ bool isSecureMemory;
+
+ /**
+ * MPU sequence number of filtered data (only for MMTP)
+ */
+ uint32_t mpuSequenceNumber;
+
+ bool isPesPrivateData;
+
+ safe_union ExtraMetaData {
+ /**
+ * Not additional parameters. it's used for video.
+ */
+ Monostate noinit;
+
+ AudioExtraMetaData audio;
+ } extraMetaData;
};
/**
@@ -1532,176 +2425,309 @@
*/
struct DemuxFilterPesEvent {
DemuxStreamId streamId;
- /* Data size in bytes of PES data */
+
+ /**
+ * Data size in bytes of PES data
+ */
+ uint16_t dataLength;
+
+ /**
+ * MPU sequence number of filtered data (only for MMTP)
+ */
+ uint32_t mpuSequenceNumber;
+};
+
+/**
+ * Filter Event for TS Record data.
+ */
+struct DemuxFilterTsRecordEvent {
+ DemuxPid pid;
+
+ /**
+ * Indexes of record output
+ */
+ safe_union IndexMask {
+ bitfield<DemuxTsIndex> tsIndexMask;
+
+ bitfield<DemuxScIndex> scIndexMask;
+
+ bitfield<DemuxScHevcIndex> scHevcIndexMask;
+ } indexMask;
+
+ /**
+ * Byte number from beginning of the filter's output
+ */
+ uint64_t byteNumber;
+};
+
+/**
+ * Filter Event for MMTP Record data.
+ */
+struct DemuxFilterMmtpRecordEvent {
+ bitfield<DemuxScHevcIndex> scHevcIndexMask;
+
+ /**
+ * Byte number from beginning of the filter's output
+ */
+ uint64_t byteNumber;
+};
+
+/**
+ * Filter Event for Download data.
+ */
+struct DemuxFilterDownloadEvent {
+ uint32_t itemId;
+
+ /**
+ * MPU sequence number of filtered data (only for MMTP)
+ */
+ uint32_t mpuSequenceNumber;
+
+ uint32_t itemFragmentIndex;
+
+ uint32_t lastItemFragmentIndex;
+
+ /**
+ * Data size in bytes of filtered data
+ */
uint16_t dataLength;
};
/**
- * Filter Event for Record data.
+ * Filter Event for IP payload data.
*/
-struct DemuxFilterRecordEvent {
- DemuxTpid tpid;
- /* Indexes of record output */
- safe_union IndexMask {
- DemuxTsIndexMask tsIndexMask;
- DemuxScIndexMask scIndexMask;
- } indexMask;
- /* Packet number from beginning of the filter's output */
- uint64_t packetNum;
+struct DemuxFilterIpPayloadEvent {
+ /**
+ * Data size in bytes of IP data
+ */
+ uint16_t dataLength;
};
/**
* Filter Event.
*/
struct DemuxFilterEvent {
- DemuxFilterId filterId;
- DemuxFilterType filterType;
safe_union Event {
DemuxFilterSectionEvent section;
+
DemuxFilterMediaEvent media;
+
DemuxFilterPesEvent pes;
- DemuxFilterRecordEvent ts;
+
+ DemuxFilterTsRecordEvent tsRecord;
+
+ DemuxFilterMmtpRecordEvent mmtpRecord;
+
+ DemuxFilterDownloadEvent download;
+
+ DemuxFilterIpPayloadEvent ipPayload;
};
- /* An array of events */
+
+ /**
+ * An array of events
+ */
vec<Event> events;
};
-/**
- * A hardware resource ID to be used for audio and video hardware sync.
- */
typedef uint32_t AvSyncHwId;
-/**
- * A token to be used to link descrambler and key slot. It's opaque to
- * framework and apps.
- */
typedef vec<uint8_t> TunerKeyToken;
/**
* A data format in demux's output or input according to ISO/IEC 13818-1.
*/
@export
-enum DemuxDataFormat : uint32_t {
- /* Data is Transport Stream. */
+enum DataFormat : uint32_t {
+ /**
+ * Data is Transport Stream.
+ */
TS,
- /* Data is Packetized Elementary Stream. */
+ /**
+ * Data is Packetized Elementary Stream.
+ */
PES,
- /* Data is Elementary Stream. */
+ /**
+ * Data is Elementary Stream.
+ */
ES,
- /* Data is TLV (type-length-value) Stream for JP SHV */
+ /**
+ * Data is TLV (type-length-value) Stream for JP SHV
+ */
SHV_TLV,
};
-/**
- * A status of the demux's output.
- */
-typedef DemuxFilterStatus DemuxOutputStatus;
+typedef DemuxFilterStatus RecordStatus;
/**
- * The Settings for the demux's output.
+ * The Settings for the record in DVR.
*/
-struct DemuxOutputSettings {
+struct RecordSettings {
/**
* Register for interested status events so that the HAL can send these
* status events back to client.
*/
- bitfield<DemuxOutputStatus> statusMask;
+ bitfield<RecordStatus> statusMask;
+
/**
- * Unconsumed data size in bytes in the output. The HAL uses it to trigger
- * DemuxOutputStatus::LOW_WATER.
+ * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+ * OutputStatus::LOW_WATER.
*/
uint32_t lowThreshold;
+
/**
- * Unconsumed data size in bytes in the output. The HAL uses it to trigger
- * DemuxOutputStatus::High_WATER.
+ * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+ * OutputStatus::High_WATER.
*/
uint32_t highThreshold;
+
/**
- * The data format in the output.
+ * The data format in the record.
*/
- DemuxDataFormat dataFormat;
+ DataFormat dataFormat;
+
/**
- * The packet size in bytes in the output.
+ * The packet size in bytes in the record.
*/
uint8_t packetSize;
};
/**
- * A status of the demux's input.
+ * A status of the playback in DVR.
*/
@export
-enum DemuxInputStatus : uint32_t {
+enum PlaybackStatus : uint32_t {
/**
- * The space of the demux's input is empty.
+ * The space of the demux's playback is empty.
*/
- SPACE_EMPTY = 1 << 0,
+ SPACE_EMPTY = 1 << 0,
/**
- * The spece of the demux's input is almost empty.
+ * The spece of the demux's playback is almost empty.
*/
SPACE_ALMOST_EMPTY = 1 << 1,
/**
- * The space of the demux's input is almost full.
+ * The space of the demux's playback is almost full.
*/
- SPACE_ALMOST_FULL = 1 << 2,
+ SPACE_ALMOST_FULL = 1 << 2,
/**
- * The space of the demux's input is full.
+ * The space of the demux's playback is full.
*/
- SPACE_FULL = 1 << 3,
+ SPACE_FULL = 1 << 3,
};
/**
- * The Settings for the demux's input.
+ * The Setting for the playback in DVR.
*/
-@export
-struct DemuxInputSettings {
+struct PlaybackSettings {
/**
* Register for interested status events so that the HAL can send these
* status events back to client.
*/
- bitfield<DemuxInputStatus> statusMask;
+ bitfield<PlaybackStatus> statusMask;
+
/**
- * Unused space size in bytes in the input. The HAL uses it to trigger
- * DemuxInputStatus::SPACE_ALMOST_EMPTY.
+ * Unused space size in bytes in the playback. The HAL uses it to trigger
+ * InputStatus::SPACE_ALMOST_EMPTY.
*/
uint32_t lowThreshold;
+
/**
- * Unused space size in bytes in the input. The HAL uses it to trigger
- * DemuxInputStatus::SPACE_ALMOST_FULL.
+ * Unused space size in bytes in the playback. The HAL uses it to trigger
+ * InputStatus::SPACE_ALMOST_FULL.
*/
uint32_t highThreshold;
+
/**
- * The data format in the input.
+ * The data format in the playback.
*/
- DemuxDataFormat dataFormat;
+ DataFormat dataFormat;
+
/**
- * The packet size in bytes in the input.
+ * The packet size in bytes in the playback.
*/
uint8_t packetSize;
};
/**
+ * The type of DVR.
+ */
+@export
+enum DvrType : uint8_t {
+ RECORD,
+ PLAYBACK,
+};
+
+/**
+ * The Setting for DVR.
+ */
+safe_union DvrSettings {
+ RecordSettings record;
+
+ PlaybackSettings playback;
+};
+
+/**
* Capabilities for Demux.
*/
-@export
struct DemuxCapabilities {
- /* The number of Demux to be supported. */
+ /**
+ * The number of Demux to be supported.
+ */
uint32_t numDemux;
- /* The number of Input to be supported. */
- uint32_t numInput;
- /* The number of Output to be supported. */
- uint32_t numOutput;
- /* The number of TS Filter to be supported. */
+
+ /**
+ * The number of record to be supported.
+ */
+ uint32_t numRecord;
+
+ /**
+ * The number of playback to be supported.
+ */
+ uint32_t numPlayback;
+
+ /**
+ * The number of TS Filter to be supported.
+ */
uint32_t numTsFilter;
- /* The number of Section Filter to be supported. */
+
+ /**
+ * The number of Section Filter to be supported.
+ */
uint32_t numSectionFilter;
- /* The number of Audio Filter to be supported. */
+
+ /**
+ * The number of Audio Filter to be supported.
+ */
uint32_t numAudioFilter;
- /* The number of Video Filter to be supported. */
+
+ /**
+ * The number of Video Filter to be supported.
+ */
uint32_t numVideoFilter;
- /* The number of PES Filter to be supported. */
+
+ /**
+ * The number of PES Filter to be supported.
+ */
uint32_t numPesFilter;
- /* The number of PCR Filter to be supported. */
+
+ /**
+ * The number of PCR Filter to be supported.
+ */
uint32_t numPcrFilter;
- /* The maximum number of bytes is supported in the mask of Section Filter. */
+
+ /**
+ * The maximum number of bytes is supported in the mask of Section Filter.
+ */
uint32_t numBytesInSectionFilter;
+
+ bitfield<DemuxFilterMainType> filterCaps;
+
+ /**
+ * The array has same elements as DemuxFilterMainType. linkCaps[i] presents
+ * filter's capability as soource for the ith type in DemuxFilterMainType.
+ * The jth bit of linkCaps[i] is 1 if the output of ith type filter can be
+ * data source for the filter type j.
+ */
+ vec<bitfield<DemuxFilterMainType>> linkCaps;
+
+ bool bTimeFilter;
};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 7936185..c666226 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -20,8 +20,11 @@
#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/tv/tuner/1.0/IDemux.h>
-#include <android/hardware/tv/tuner/1.0/IDemuxCallback.h>
#include <android/hardware/tv/tuner/1.0/IDescrambler.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/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
#include <android/hardware/tv/tuner/1.0/IFrontend.h>
#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
#include <android/hardware/tv/tuner/1.0/ITuner.h>
@@ -57,8 +60,9 @@
using android::hardware::MQDescriptorSync;
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::tv::tuner::V1_0::DemuxDataFormat;
+using android::hardware::tv::tuner::V1_0::DataFormat;
using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
@@ -66,10 +70,11 @@
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::DemuxInputSettings;
-using android::hardware::tv::tuner::V1_0::DemuxInputStatus;
-using android::hardware::tv::tuner::V1_0::DemuxOutputStatus;
using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+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::FrontendAtscModulation;
using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
@@ -80,11 +85,17 @@
using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
using android::hardware::tv::tuner::V1_0::FrontendSettings;
using android::hardware::tv::tuner::V1_0::IDemux;
-using android::hardware::tv::tuner::V1_0::IDemuxCallback;
using android::hardware::tv::tuner::V1_0::IDescrambler;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::IFilterCallback;
using android::hardware::tv::tuner::V1_0::IFrontend;
using android::hardware::tv::tuner::V1_0::IFrontendCallback;
using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
using android::hardware::tv::tuner::V1_0::Result;
namespace {
@@ -131,17 +142,28 @@
0x73, 0x63, 0x65, 0x6e, 0x65,
};
-const uint16_t FMQ_SIZE_4K = 0x1000;
+// const uint16_t FMQ_SIZE_4K = 0x1000;
const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
struct FilterConf {
DemuxFilterType type;
DemuxFilterSettings setting;
};
-struct InputConf {
+enum FilterEventType : uint8_t {
+ UNDEFINED,
+ SECTION,
+ MEDIA,
+ PES,
+ RECORD,
+ MMTPRECORD,
+ DOWNLOAD,
+};
+
+struct PlaybackConf {
string inputDataFile;
- DemuxInputSettings setting;
+ PlaybackSettings setting;
};
class FrontendCallback : public IFrontendCallback {
@@ -154,14 +176,6 @@
return Void();
}
- virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override {
- android::Mutex::Autolock autoLock(mMsgLock);
- mDiseqcMessageReceived = true;
- mEventMessage = diseqcMessage;
- mMsgCondition.signal();
- return Void();
- }
-
virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
const FrontendScanMessage& /* message */) override {
android::Mutex::Autolock autoLock(mMsgLock);
@@ -211,14 +225,14 @@
}
}
-class DemuxCallback : public IDemuxCallback {
+class FilterCallback : public IFilterCallback {
public:
virtual Return<void> onFilterEvent(const 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
- mFilterIdToEvent[filterEvent.filterId] = filterEvent;
- readFilterEventData(filterEvent.filterId);
+ mFilterIdToEvent = filterEvent;
+ readFilterEventData();
mPidFilterOutputCount++;
// mFilterIdToMQ.erase(filterEvent.filterId);
@@ -227,96 +241,50 @@
return Void();
}
- virtual Return<void> onFilterStatus(uint32_t /*filterId*/,
- const DemuxFilterStatus /*status*/) override {
+ virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
return Void();
}
- virtual Return<void> onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); }
+ void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+ void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
- virtual Return<void> onInputStatus(DemuxInputStatus status) override {
- // android::Mutex::Autolock autoLock(mMsgLock);
- ALOGW("[vts] input status %d", status);
- switch (status) {
- case DemuxInputStatus::SPACE_EMPTY:
- case DemuxInputStatus::SPACE_ALMOST_EMPTY:
- ALOGW("[vts] keep inputing %d", status);
- mKeepWritingInputFMQ = true;
- break;
- case DemuxInputStatus::SPACE_ALMOST_FULL:
- case DemuxInputStatus::SPACE_FULL:
- ALOGW("[vts] stop inputing %d", status);
- mKeepWritingInputFMQ = false;
- break;
- }
- return Void();
- }
-
- void testOnFilterEvent(uint32_t filterId);
void testFilterDataOutput();
- void stopInputThread();
- void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor);
void startFilterEventThread(DemuxFilterEvent event);
- static void* __threadLoopInput(void* threadArgs);
static void* __threadLoopFilter(void* threadArgs);
- void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ);
void filterThreadLoop(DemuxFilterEvent& event);
- void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor);
- void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile);
- bool readFilterEventData(uint32_t filterId);
+ void updateFilterMQ(MQDesc& filterMQDescriptor);
+ void updateGoldenOutputMap(string goldenOutputFile);
+ bool readFilterEventData();
private:
- struct InputThreadArgs {
- DemuxCallback* user;
- InputConf* inputConf;
- bool* keepWritingInputFMQ;
- };
struct FilterThreadArgs {
- DemuxCallback* user;
+ FilterCallback* user;
DemuxFilterEvent event;
};
uint16_t mDataLength = 0;
std::vector<uint8_t> mDataOutputBuffer;
- bool mFilterEventReceived;
- std::map<uint32_t, string> mFilterIdToGoldenOutput;
+ string mFilterIdToGoldenOutput;
- std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
- std::unique_ptr<FilterMQ> mInputMQ;
- std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
- std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
- EventFlag* mInputMQEventFlag;
+ uint32_t mFilterId;
+ FilterEventType mFilterEventType;
+ std::unique_ptr<FilterMQ> mFilterIdToMQ;
+ EventFlag* mFilterIdToMQEventFlag;
+ DemuxFilterEvent mFilterIdToEvent;
android::Mutex mMsgLock;
android::Mutex mFilterOutputLock;
- android::Mutex mInputThreadLock;
android::Condition mMsgCondition;
android::Condition mFilterOutputCondition;
- bool mKeepWritingInputFMQ = true;
- bool mInputThreadRunning;
- pthread_t mInputThread;
pthread_t mFilterThread;
int mPidFilterOutputCount = 0;
};
-void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) {
- mInputMQ = std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
- EXPECT_TRUE(mInputMQ);
- struct InputThreadArgs* threadArgs =
- (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs));
- threadArgs->user = this;
- threadArgs->inputConf = &inputConf;
- threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ;
-
- pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs);
- pthread_setname_np(mInputThread, "test_playback_input_loop");
-}
-
-void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) {
+void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
struct FilterThreadArgs* threadArgs =
(struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
threadArgs->user = this;
@@ -326,7 +294,7 @@
pthread_setname_np(mFilterThread, "test_playback_input_loop");
}
-void DemuxCallback::testFilterDataOutput() {
+void FilterCallback::testFilterDataOutput() {
android::Mutex::Autolock autoLock(mMsgLock);
while (mPidFilterOutputCount < 1) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
@@ -338,95 +306,25 @@
ALOGW("[vts] pass and stop");
}
-void DemuxCallback::stopInputThread() {
- mInputThreadRunning = false;
- mKeepWritingInputFMQ = false;
-
- android::Mutex::Autolock autoLock(mInputThreadLock);
+void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
+ mFilterIdToMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mFilterIdToMQ);
+ EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(),
+ &mFilterIdToMQEventFlag) == android::OK);
}
-void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) {
- mFilterIdToMQ[filterId] =
- std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
- EXPECT_TRUE(mFilterIdToMQ[filterId]);
- EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(),
- &mFilterIdToMQEventFlag[filterId]) == android::OK);
+void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
+ mFilterIdToGoldenOutput = goldenOutputFile;
}
-void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) {
- mFilterIdToGoldenOutput[filterId] = goldenOutputFile;
-}
-
-void* DemuxCallback::__threadLoopInput(void* threadArgs) {
- DemuxCallback* const self =
- static_cast<DemuxCallback*>(((struct InputThreadArgs*)threadArgs)->user);
- self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf,
- ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ);
- return 0;
-}
-
-void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) {
- android::Mutex::Autolock autoLock(mInputThreadLock);
- mInputThreadRunning = true;
-
- // Create the EventFlag that is used to signal the HAL impl that data have been
- // written into the Input FMQ
- EventFlag* inputMQEventFlag;
- EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) ==
- android::OK);
-
- // open the stream and get its length
- std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary);
- int writeSize = inputConf->setting.packetSize * 6;
- char* buffer = new char[writeSize];
- ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str());
- if (!inputData.is_open()) {
- mInputThreadRunning = false;
- ALOGW("[vts] Error %s", strerror(errno));
- }
-
- while (mInputThreadRunning) {
- // move the stream pointer for packet size * 6 every read until the end
- while (*keepWritingInputFMQ) {
- inputData.read(buffer, writeSize);
- if (!inputData) {
- int leftSize = inputData.gcount();
- if (leftSize == 0) {
- mInputThreadRunning = false;
- break;
- }
- inputData.clear();
- inputData.read(buffer, leftSize);
- // Write the left over of the input data and quit the thread
- if (leftSize > 0) {
- EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize));
- inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
- }
- mInputThreadRunning = false;
- break;
- }
- // Write input FMQ and notify the Tuner Implementation
- EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize));
- inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
- inputData.seekg(writeSize, inputData.cur);
- sleep(1);
- }
- }
-
- ALOGW("[vts] Input thread end.");
-
- delete[] buffer;
- inputData.close();
-}
-
-void* DemuxCallback::__threadLoopFilter(void* threadArgs) {
- DemuxCallback* const self =
- static_cast<DemuxCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
+void* FilterCallback::__threadLoopFilter(void* threadArgs) {
+ FilterCallback* const self =
+ static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
return 0;
}
-void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
+void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
android::Mutex::Autolock autoLock(mFilterOutputLock);
// Read from mFilterIdToMQ[event.filterId] per event and filter type
@@ -439,30 +337,184 @@
// end thread
}
-bool DemuxCallback::readFilterEventData(uint32_t filterId) {
+bool FilterCallback::readFilterEventData() {
bool result = false;
- DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId];
- ALOGW("[vts] reading from filter FMQ %d", filterId);
+ DemuxFilterEvent filterEvent = mFilterIdToEvent;
+ ALOGW("[vts] reading from filter FMQ %d", mFilterId);
// todo separate filter handlers
for (int i = 0; i < filterEvent.events.size(); i++) {
- DemuxFilterPesEvent event = filterEvent.events[i].pes();
- mDataLength = event.dataLength;
+ switch (mFilterEventType) {
+ case FilterEventType::SECTION:
+ mDataLength = filterEvent.events[i].section().dataLength;
+ break;
+ case FilterEventType::PES:
+ mDataLength = filterEvent.events[i].pes().dataLength;
+ break;
+ case FilterEventType::MEDIA:
+ break;
+ case FilterEventType::RECORD:
+ break;
+ case FilterEventType::MMTPRECORD:
+ break;
+ case FilterEventType::DOWNLOAD:
+ break;
+ default:
+ break;
+ }
// EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
// match";
mDataOutputBuffer.resize(mDataLength);
- result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength);
+ result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength);
EXPECT_TRUE(result) << "can't read from Filter MQ";
/*for (int i = 0; i < mDataLength; i++) {
EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
}*/
}
- mFilterIdToMQEventFlag[filterId]->wake(
- static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+ mFilterIdToMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
return result;
}
+class DvrCallback : public IDvrCallback {
+ public:
+ virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+
+ virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+ // android::Mutex::Autolock autoLock(mMsgLock);
+ ALOGW("[vts] playback status %d", status);
+ switch (status) {
+ case PlaybackStatus::SPACE_EMPTY:
+ case PlaybackStatus::SPACE_ALMOST_EMPTY:
+ ALOGW("[vts] keep playback inputing %d", status);
+ mKeepWritingPlaybackFMQ = true;
+ break;
+ case PlaybackStatus::SPACE_ALMOST_FULL:
+ case PlaybackStatus::SPACE_FULL:
+ ALOGW("[vts] stop playback inputing %d", status);
+ mKeepWritingPlaybackFMQ = false;
+ break;
+ }
+ return Void();
+ }
+
+ void testFilterDataOutput();
+ void stopPlaybackThread();
+
+ void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+ static void* __threadLoopPlayback(void* threadArgs);
+ void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+
+ private:
+ struct PlaybackThreadArgs {
+ DvrCallback* user;
+ PlaybackConf* playbackConf;
+ bool* keepWritingPlaybackFMQ;
+ };
+ uint16_t mDataLength = 0;
+ std::vector<uint8_t> mDataOutputBuffer;
+
+ std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
+ std::unique_ptr<FilterMQ> mPlaybackMQ;
+ std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
+ std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
+ EventFlag* mPlaybackMQEventFlag;
+
+ android::Mutex mMsgLock;
+ android::Mutex mPlaybackThreadLock;
+ android::Condition mMsgCondition;
+
+ bool mKeepWritingPlaybackFMQ = true;
+ bool mPlaybackThreadRunning;
+ pthread_t mPlaybackThread;
+
+ int mPidFilterOutputCount = 0;
+};
+
+void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
+ MQDesc& playbackMQDescriptor) {
+ mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mPlaybackMQ);
+ struct PlaybackThreadArgs* threadArgs =
+ (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
+ threadArgs->user = this;
+ threadArgs->playbackConf = &playbackConf;
+ threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
+
+ pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
+ pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+ mPlaybackThreadRunning = false;
+ mKeepWritingPlaybackFMQ = false;
+
+ android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
+ DvrCallback* const self =
+ static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
+ self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
+ ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
+ return 0;
+}
+
+void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
+ 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);
+
+ // open the stream and get its length
+ std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
+ int writeSize = playbackConf->setting.packetSize * 6;
+ char* buffer = new char[writeSize];
+ ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
+ if (!inputData.is_open()) {
+ mPlaybackThreadRunning = false;
+ ALOGW("[vts] Error %s", strerror(errno));
+ }
+
+ while (mPlaybackThreadRunning) {
+ // move the stream pointer for packet size * 6 every read until the end
+ while (*keepWritingPlaybackFMQ) {
+ inputData.read(buffer, writeSize);
+ if (!inputData) {
+ int leftSize = inputData.gcount();
+ if (leftSize == 0) {
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ inputData.clear();
+ inputData.read(buffer, leftSize);
+ // Write the left over of the input data and quit the thread
+ if (leftSize > 0) {
+ EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
+ playbackMQEventFlag->wake(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ }
+ mPlaybackThreadRunning = false;
+ break;
+ }
+ // Write input FMQ and notify the Tuner Implementation
+ EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
+ playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ inputData.seekg(writeSize, inputData.cur);
+ sleep(1);
+ }
+ }
+
+ ALOGW("[vts] Playback thread end.");
+
+ delete[] buffer;
+ inputData.close();
+}
+
// Test environment for Tuner HIDL HAL.
class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -494,16 +546,21 @@
sp<FrontendCallback> mFrontendCallback;
sp<IDescrambler> mDescrambler;
sp<IDemux> mDemux;
- sp<DemuxCallback> mDemuxCallback;
+ sp<IDvr> mDvr;
+ sp<IFilter> mFilter;
+ std::map<uint32_t, sp<IFilter>> mFilters;
+ std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
+ sp<FilterCallback> mFilterCallback;
+ sp<DvrCallback> mDvrCallback;
MQDesc mFilterMQDescriptor;
- MQDesc mInputMQDescriptor;
+ MQDesc mPlaybackMQDescriptor;
vector<uint32_t> mUsedFilterIds;
uint32_t mDemuxId;
uint32_t mFilterId;
- pthread_t mInputThread;
- bool mInputThreadRunning;
+ pthread_t mPlaybackshread;
+ bool mPlaybackThreadRunning;
::testing::AssertionResult createFrontend(int32_t frontendId);
::testing::AssertionResult tuneFrontend(int32_t frontendId);
@@ -512,16 +569,16 @@
::testing::AssertionResult createDemux();
::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId,
FrontendSettings settings);
- ::testing::AssertionResult getInputMQDescriptor();
- ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting);
+ ::testing::AssertionResult getPlaybackMQDescriptor();
+ ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
- ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId);
+ ::testing::AssertionResult getFilterMQDescriptor();
::testing::AssertionResult closeDemux();
::testing::AssertionResult createDescrambler();
::testing::AssertionResult closeDescrambler();
::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
- InputConf inputConf,
+ PlaybackConf playbackConf,
vector<string> goldenOutputFiles);
::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
vector<string> goldenOutputFiles);
@@ -665,39 +722,43 @@
return ::testing::AssertionResult(status == Result::SUCCESS);
}
-::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) {
+::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) {
Result status;
if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
return ::testing::AssertionFailure();
}
- // Create demux callback
- if (!mDemuxCallback) {
- mDemuxCallback = new DemuxCallback();
- }
+ // Create dvr callback
+ mDvrCallback = new DvrCallback();
// Add playback input to the local demux
- status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback);
+ mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvr = dvr;
+ status = result;
+ });
if (status != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
- status = mDemux->configureInput(setting);
+ DvrSettings dvrSetting;
+ dvrSetting.playback(setting);
+ status = mDvr->configure(dvrSetting);
return ::testing::AssertionResult(status == Result::SUCCESS);
}
-::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() {
+::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() {
Result status;
- if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+ if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
return ::testing::AssertionFailure();
}
- mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) {
- mInputMQDescriptor = inputMQDesc;
+ mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mPlaybackMQDescriptor = dvrMQDesc;
status = result;
});
@@ -713,13 +774,20 @@
}
// Create demux callback
- if (!mDemuxCallback) {
- mDemuxCallback = new DemuxCallback();
- }
+ mFilterCallback = new FilterCallback();
// Add filter to the local demux
- mDemux->addFilter(type, FMQ_SIZE_4K, mDemuxCallback, [&](Result result, uint32_t filterId) {
- // TODO use a map to save all the filter id and FMQ
+ mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
+ [&](Result result, const sp<IFilter>& filter) {
+ mFilter = filter;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ mFilter->getId([&](Result result, uint32_t filterId) {
mFilterId = filterId;
status = result;
});
@@ -728,20 +796,64 @@
return ::testing::AssertionFailure();
}
+ mFilterCallback->setFilterId(mFilterId);
+
+ 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;
+ }
+ break;
+ case DemuxFilterMainType::MMTP:
+ /*mmtpSettings*/
+ break;
+ case DemuxFilterMainType::IP:
+ /*ipSettings*/
+ break;
+ case DemuxFilterMainType::TLV:
+ /*tlvSettings*/
+ break;
+ case DemuxFilterMainType::ALP:
+ /*alpSettings*/
+ break;
+ default:
+ break;
+ }
+ mFilterCallback->setFilterEventType(eventType);
+
// Configure the filter
- status = mDemux->configureFilter(mFilterId, setting);
+ status = mFilter->configure(setting);
return ::testing::AssertionResult(status == Result::SUCCESS);
}
-::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) {
+::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() {
Result status;
- if (!mDemux) {
+ if (!mDemux || !mFilter) {
return ::testing::AssertionFailure();
}
- mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) {
+ mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
mFilterMQDescriptor = filterMQDesc;
status = result;
});
@@ -750,7 +862,8 @@
}
::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(
- vector<FilterConf> filterConf, InputConf inputConf, vector<string> /*goldenOutputFiles*/) {
+ vector<FilterConf> filterConf, PlaybackConf playbackConf,
+ vector<string> /*goldenOutputFiles*/) {
Result status;
int filterIdsSize;
// Filter Configuration Module
@@ -758,45 +871,58 @@
if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
::testing::AssertionFailure() ||
// TODO use a map to save the FMQs/EvenFlags and pass to callback
- getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
+ getFilterMQDescriptor() == ::testing::AssertionFailure()) {
return ::testing::AssertionFailure();
}
filterIdsSize = mUsedFilterIds.size();
mUsedFilterIds.resize(filterIdsSize + 1);
mUsedFilterIds[filterIdsSize] = mFilterId;
- mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
- // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]);
- status = mDemux->startFilter(mFilterId);
+ mFilters[mFilterId] = mFilter;
+ mFilterCallbacks[mFilterId] = mFilterCallback;
+ mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+ // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]);
+ status = mFilter->start();
if (status != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
}
// Playback Input Module
- DemuxInputSettings inputSetting = inputConf.setting;
- if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() ||
- getInputMQDescriptor() == ::testing::AssertionFailure()) {
+ PlaybackSettings playbackSetting = playbackConf.setting;
+ if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() ||
+ getPlaybackMQDescriptor() == ::testing::AssertionFailure()) {
return ::testing::AssertionFailure();
}
- mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor);
- status = mDemux->startInput();
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+ mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor);
+ status = mDvr->start();
if (status != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
// Data Verify Module
- mDemuxCallback->testFilterDataOutput();
- mDemuxCallback->stopInputThread();
+ std::map<uint32_t, sp<FilterCallback>>::iterator it;
+ for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+ it->second->testFilterDataOutput();
+ }
+ mDvrCallback->stopPlaybackThread();
// Clean Up Module
for (int i = 0; i <= filterIdsSize; i++) {
- if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+ if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
}
- if (mDemux->stopInput() != Result::SUCCESS) {
+ if (mDvr->stop() != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
+ mUsedFilterIds.clear();
+ mFilterCallbacks.clear();
+ mFilters.clear();
return closeDemux();
}
@@ -831,31 +957,39 @@
if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
::testing::AssertionFailure() ||
// TODO use a map to save the FMQs/EvenFlags and pass to callback
- getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
+ getFilterMQDescriptor() == ::testing::AssertionFailure()) {
return ::testing::AssertionFailure();
}
filterIdsSize = mUsedFilterIds.size();
mUsedFilterIds.resize(filterIdsSize + 1);
mUsedFilterIds[filterIdsSize] = mFilterId;
- mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
- status = mDemux->startFilter(mFilterId);
+ mFilters[mFilterId] = mFilter;
+ mFilterCallbacks[mFilterId] = mFilterCallback;
+ mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+ status = mFilter->start();
if (status != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
}
// Data Verify Module
- mDemuxCallback->testFilterDataOutput();
+ std::map<uint32_t, sp<FilterCallback>>::iterator it;
+ for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+ it->second->testFilterDataOutput();
+ }
// Clean Up Module
for (int i = 0; i <= filterIdsSize; i++) {
- if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+ if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
}
if (mFrontend->stopTune() != Result::SUCCESS) {
return ::testing::AssertionFailure();
}
+ mUsedFilterIds.clear();
+ mFilterCallbacks.clear();
+ mFilters.clear();
return closeDemux();
}
@@ -992,7 +1126,7 @@
/*
* DATA FLOW TESTS
*/
-TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) {
+TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
description("Feed ts data from playback and configure pes filter to get output");
// todo modulize the filter conf parser
@@ -1000,32 +1134,39 @@
filterConf.resize(1);
DemuxFilterSettings filterSetting;
- DemuxFilterPesDataSettings pesFilterSetting{
+ DemuxTsFilterSettings tsFilterSetting{
.tpid = 18,
};
- filterSetting.pesData(pesFilterSetting);
- FilterConf pesFilterConf{
- .type = DemuxFilterType::PES,
+ DemuxFilterSectionSettings sectionFilterSetting;
+ tsFilterSetting.filterSettings.section(sectionFilterSetting);
+ filterSetting.ts(tsFilterSetting);
+
+ DemuxFilterType type{
+ .mainType = DemuxFilterMainType::TS,
+ };
+ type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+ FilterConf sectionFilterConf{
+ .type = type,
.setting = filterSetting,
};
- filterConf[0] = pesFilterConf;
+ filterConf[0] = sectionFilterConf;
- DemuxInputSettings inputSetting{
+ PlaybackSettings playbackSetting{
.statusMask = 0xf,
.lowThreshold = 0x1000,
.highThreshold = 0x07fff,
- .dataFormat = DemuxDataFormat::TS,
+ .dataFormat = DataFormat::TS,
.packetSize = 188,
};
- InputConf inputConf{
+ PlaybackConf playbackConf{
.inputDataFile = "/vendor/etc/test1.ts",
- .setting = inputSetting,
+ .setting = playbackSetting,
};
vector<string> goldenOutputFiles;
- ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles));
+ ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
}
TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
@@ -1036,12 +1177,19 @@
filterConf.resize(1);
DemuxFilterSettings filterSetting;
- DemuxFilterPesDataSettings pesFilterSetting{
- .tpid = 18,
+ DemuxTsFilterSettings tsFilterSetting{
+ .tpid = 119,
};
- filterSetting.pesData(pesFilterSetting);
+ DemuxFilterPesDataSettings pesFilterSetting;
+ tsFilterSetting.filterSettings.pesData(pesFilterSetting);
+ filterSetting.ts(tsFilterSetting);
+
+ DemuxFilterType type{
+ .mainType = DemuxFilterMainType::TS,
+ };
+ type.subType.tsFilterType(DemuxTsFilterType::PES);
FilterConf pesFilterConf{
- .type = DemuxFilterType::PES,
+ .type = type,
.setting = filterSetting,
};
filterConf[0] = pesFilterConf;
diff --git a/tv/tuner/README.md b/tv/tuner/README.md
index a833c87..aa1f62d 100644
--- a/tv/tuner/README.md
+++ b/tv/tuner/README.md
@@ -4,7 +4,7 @@
TV specific tuners.
-Sett 1.0/ITuner.hal for an overview.
+See 1.0/ITuner.hal for an overview.
*** note
**Warning:** The HALs are not (yet) frozen, as the HAL definition is
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp
index 391d3d4..10ec2cb 100644
--- a/vibrator/1.0/vts/functional/Android.bp
+++ b/vibrator/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalVibratorV1_0TargetTest.cpp"],
static_libs: ["android.hardware.vibrator@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
index 6f8aa02..2aee338 100644
--- a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
+++ b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
#include <android/hardware/vibrator/1.0/types.h>
#include <unistd.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::sp;
using ::android::hardware::hidl_enum_range;
@@ -35,27 +36,11 @@
#define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static VibratorHidlEnvironment* Instance() {
- static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
- private:
- VibratorHidlEnvironment() {}
-};
-
// The main test class for VIBRATOR HIDL HAL.
-class VibratorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
- VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+ vibrator = IVibrator::getService(GetParam());
ASSERT_NE(vibrator, nullptr);
}
@@ -79,13 +64,13 @@
<< "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
}
-TEST_F(VibratorHidlTest, OnThenOffBeforeTimeout) {
+TEST_P(VibratorHidlTest, OnThenOffBeforeTimeout) {
EXPECT_EQ(Status::OK, vibrator->on(2000));
sleep(1);
EXPECT_EQ(Status::OK, vibrator->off());
}
-TEST_F(VibratorHidlTest, PerformEffect) {
+TEST_P(VibratorHidlTest, PerformEffect) {
vibrator->perform(Effect::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
vibrator->perform(Effect::DOUBLE_CLICK, EffectStrength::LIGHT, validatePerformEffect);
}
@@ -93,7 +78,7 @@
/*
* Test to make sure effect values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest, PerformEffect_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadEffects_AboveValidRange) {
Effect effect = *std::prev(hidl_enum_range<Effect>().end());
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
EXPECT_OK(vibrator->perform(badEffect, EffectStrength::LIGHT, validatePerformEffectBadInput));
@@ -102,7 +87,7 @@
/*
* Test to make sure effect values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest, PerformEffect_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadEffects_BelowValidRange) {
Effect effect = *hidl_enum_range<Effect>().begin();
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
EXPECT_OK(vibrator->perform(badEffect, EffectStrength::LIGHT, validatePerformEffectBadInput));
@@ -111,7 +96,7 @@
/*
* Test to make sure strength values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest, PerformEffect_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadStrength_AboveValidRange) {
EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
EXPECT_OK(vibrator->perform(Effect::CLICK, badStrength, validatePerformEffectBadInput));
@@ -120,13 +105,13 @@
/*
* Test to make sure strength values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest, PerformEffect_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadStrength_BelowValidRange) {
EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
EXPECT_OK(vibrator->perform(Effect::CLICK, badStrength, validatePerformEffectBadInput));
}
-TEST_F(VibratorHidlTest, ChangeVibrationalAmplitude) {
+TEST_P(VibratorHidlTest, ChangeVibrationalAmplitude) {
if (vibrator->supportsAmplitudeControl()) {
EXPECT_EQ(Status::OK, vibrator->setAmplitude(1));
EXPECT_EQ(Status::OK, vibrator->on(2000));
@@ -137,23 +122,19 @@
}
}
-TEST_F(VibratorHidlTest, AmplitudeOutsideRangeFails) {
+TEST_P(VibratorHidlTest, AmplitudeOutsideRangeFails) {
if (vibrator->supportsAmplitudeControl()) {
EXPECT_EQ(Status::BAD_VALUE, vibrator->setAmplitude(0));
}
}
-TEST_F(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
+TEST_P(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
if (!vibrator->supportsAmplitudeControl()) {
EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setAmplitude(1));
}
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- VibratorHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, VibratorHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.1/vts/functional/Android.bp b/vibrator/1.1/vts/functional/Android.bp
index c65ff41..4cde350 100644
--- a/vibrator/1.1/vts/functional/Android.bp
+++ b/vibrator/1.1/vts/functional/Android.bp
@@ -22,6 +22,6 @@
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp b/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
index 3c3ebf2..da94308 100644
--- a/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
+++ b/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
@@ -16,11 +16,12 @@
#define LOG_TAG "vibrator_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/vibrator/1.1/IVibrator.h>
#include <android/hardware/vibrator/1.1/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unistd.h>
using ::android::sp;
@@ -34,27 +35,11 @@
#define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static VibratorHidlEnvironment* Instance() {
- static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
- private:
- VibratorHidlEnvironment() {}
-};
-
// The main test class for VIBRATOR HIDL HAL 1.1.
-class VibratorHidlTest_1_1 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_1 : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
- VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+ vibrator = IVibrator::getService(GetParam());
ASSERT_NE(vibrator, nullptr);
}
@@ -80,7 +65,7 @@
<< "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
}
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1) {
vibrator->perform_1_1(Effect_1_1::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
vibrator->perform_1_1(Effect_1_1::TICK, EffectStrength::STRONG, validatePerformEffect);
}
@@ -88,7 +73,7 @@
/*
* Test to make sure effect values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_AboveValidRange) {
Effect_1_1 effect = *std::prev(hidl_enum_range<Effect_1_1>().end());
Effect_1_1 badEffect = static_cast<Effect_1_1>(static_cast<int32_t>(effect) + 1);
EXPECT_OK(
@@ -98,7 +83,7 @@
/*
* Test to make sure effect values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_BelowValidRange) {
Effect_1_1 effect = *hidl_enum_range<Effect_1_1>().begin();
Effect_1_1 badEffect = static_cast<Effect_1_1>(static_cast<int32_t>(effect) - 1);
EXPECT_OK(
@@ -108,7 +93,7 @@
/*
* Test to make sure strength values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_AboveValidRange) {
EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
EXPECT_OK(vibrator->perform_1_1(Effect_1_1::CLICK, badStrength, validatePerformEffectBadInput));
@@ -117,17 +102,13 @@
/*
* Test to make sure strength values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_BelowValidRange) {
EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
EXPECT_OK(vibrator->perform_1_1(Effect_1_1::CLICK, badStrength, validatePerformEffectBadInput));
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- VibratorHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, VibratorHidlTest_1_1,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
index 1e3ec97..e7052f2 100644
--- a/vibrator/1.2/vts/functional/Android.bp
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -23,6 +23,6 @@
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
index d69695a..2058e85 100644
--- a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
+++ b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
@@ -16,12 +16,13 @@
#define LOG_TAG "vibrator_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/vibrator/1.0/types.h>
#include <android/hardware/vibrator/1.2/IVibrator.h>
#include <android/hardware/vibrator/1.2/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unistd.h>
using ::android::hardware::vibrator::V1_0::Status;
@@ -35,27 +36,11 @@
#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static VibratorHidlEnvironment* Instance() {
- static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
- private:
- VibratorHidlEnvironment() {}
-};
-
// The main test class for VIBRATOR HIDL HAL 1.2.
-class VibratorHidlTest_1_2 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_2 : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
- VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+ vibrator = IVibrator::getService(GetParam());
ASSERT_NE(vibrator, nullptr);
}
@@ -85,7 +70,7 @@
* Test to make sure effects within the valid range return are either supported and return OK with
* a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
*/
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2) {
for (const auto& effect : hidl_enum_range<Effect>()) {
for (const auto& strength : hidl_enum_range<EffectStrength>()) {
EXPECT_OK(vibrator->perform_1_2(effect, strength, validatePerformEffect));
@@ -96,7 +81,7 @@
/*
* Test to make sure effect values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_AboveValidRange) {
Effect effect = *std::prev(hidl_enum_range<Effect>().end());
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
EXPECT_OK(
@@ -106,7 +91,7 @@
/*
* Test to make sure effect values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_BelowValidRange) {
Effect effect = *hidl_enum_range<Effect>().begin();
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
EXPECT_OK(
@@ -116,7 +101,7 @@
/*
* Test to make sure strength values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_AboveValidRange) {
EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
EXPECT_OK(vibrator->perform_1_2(Effect::THUD, badStrength, validatePerformEffectBadInput));
@@ -125,17 +110,13 @@
/*
* Test to make sure strength values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_BelowValidRange) {
EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
EXPECT_OK(vibrator->perform_1_2(Effect::THUD, badStrength, validatePerformEffectBadInput));
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- VibratorHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, VibratorHidlTest_1_2,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
deleted file mode 100644
index ed7a562..0000000
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.example
- class hal
- user system
- group system
diff --git a/vibrator/1.3/vts/functional/Android.bp b/vibrator/1.3/vts/functional/Android.bp
index 5b4c893..038dc5c 100644
--- a/vibrator/1.3/vts/functional/Android.bp
+++ b/vibrator/1.3/vts/functional/Android.bp
@@ -24,6 +24,6 @@
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
index 818f9c7..3cd3430 100644
--- a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
+++ b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
@@ -16,11 +16,12 @@
#define LOG_TAG "vibrator_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/vibrator/1.0/types.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <unistd.h>
using ::android::sp;
@@ -34,27 +35,11 @@
#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static VibratorHidlEnvironment* Instance() {
- static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
- private:
- VibratorHidlEnvironment() {}
-};
-
// The main test class for VIBRATOR HIDL HAL 1.3.
-class VibratorHidlTest_1_3 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_3 : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
- VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+ vibrator = IVibrator::getService(GetParam());
ASSERT_NE(vibrator, nullptr);
}
@@ -63,7 +48,7 @@
sp<IVibrator> vibrator;
};
-TEST_F(VibratorHidlTest_1_3, ChangeVibrationalExternalControl) {
+TEST_P(VibratorHidlTest_1_3, ChangeVibrationalExternalControl) {
if (vibrator->supportsExternalControl()) {
EXPECT_EQ(Status::OK, vibrator->setExternalControl(true));
sleep(1);
@@ -72,7 +57,7 @@
}
}
-TEST_F(VibratorHidlTest_1_3, SetExternalControlReturnUnsupportedOperationIfNotSupported) {
+TEST_P(VibratorHidlTest_1_3, SetExternalControlReturnUnsupportedOperationIfNotSupported) {
if (!vibrator->supportsExternalControl()) {
EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setExternalControl(true));
}
@@ -98,7 +83,7 @@
* Test to make sure effects within the valid range return are either supported and return OK with
* a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
*/
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3) {
for (const auto& effect : hidl_enum_range<Effect>()) {
for (const auto& strength : hidl_enum_range<EffectStrength>()) {
EXPECT_OK(vibrator->perform_1_3(effect, strength, validatePerformEffect));
@@ -109,7 +94,7 @@
/*
* Test to make sure effect values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_AboveValidRange) {
Effect effect = *std::prev(hidl_enum_range<Effect>().end());
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
@@ -119,7 +104,7 @@
/*
* Test to make sure effect values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_BelowValidRange) {
Effect effect = *hidl_enum_range<Effect>().begin();
Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
@@ -129,7 +114,7 @@
/*
* Test to make sure strength values above the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_AboveValidRange) {
EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
@@ -139,18 +124,14 @@
/*
* Test to make sure strength values below the valid range are rejected.
*/
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_BelowValidRange) {
EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
validatePerformEffectUnsupportedOperation));
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- VibratorHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, VibratorHidlTest_1_3,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.4/vts/functional/Android.bp b/vibrator/1.4/vts/functional/Android.bp
index 4cdf3b6..202a824 100644
--- a/vibrator/1.4/vts/functional/Android.bp
+++ b/vibrator/1.4/vts/functional/Android.bp
@@ -25,6 +25,9 @@
"android.hardware.vibrator@1.3",
"android.hardware.vibrator@1.4",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.x/example/Android.bp
similarity index 81%
rename from vibrator/1.3/example/Android.bp
rename to vibrator/1.x/example/Android.bp
index 07f1c26..afbbb75 100644
--- a/vibrator/1.3/example/Android.bp
+++ b/vibrator/1.x/example/Android.bp
@@ -14,11 +14,11 @@
// limitations under the License.
cc_binary {
- name: "android.hardware.vibrator@1.3-service.example",
+ name: "android.hardware.vibrator@1.x-service.example",
vendor: true,
relative_install_path: "hw",
- init_rc: ["android.hardware.vibrator@1.3-service.example.rc"],
- vintf_fragments: ["android.hardware.vibrator@1.3-service.example.xml"],
+ init_rc: ["android.hardware.vibrator@1.x-service.example.rc"],
+ vintf_fragments: ["android.hardware.vibrator@1.x-service.example.xml"],
srcs: ["service.cpp", "Vibrator.cpp"],
cflags: ["-Wall", "-Werror"],
shared_libs: [
@@ -29,5 +29,6 @@
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
+ "android.hardware.vibrator@1.4",
],
}
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.x/example/OWNERS
similarity index 100%
rename from vibrator/1.3/example/OWNERS
rename to vibrator/1.x/example/OWNERS
diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.x/example/Vibrator.cpp
similarity index 86%
rename from vibrator/1.3/example/Vibrator.cpp
rename to vibrator/1.x/example/Vibrator.cpp
index b529437..4dd1cb9 100644
--- a/vibrator/1.3/example/Vibrator.cpp
+++ b/vibrator/1.x/example/Vibrator.cpp
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
static constexpr uint32_t MS_PER_S = 1000;
@@ -100,7 +100,25 @@
}
}
-Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+Return<void> Vibrator::perform_1_3(V1_3::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) {
+ return perform<decltype(effect)>(effect, strength, _hidl_cb);
+}
+
+// Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+
+Return<hidl_bitfield<Capabilities>> Vibrator::getCapabilities() {
+ return Capabilities::ON_COMPLETION_CALLBACK | Capabilities::PERFORM_COMPLETION_CALLBACK;
+}
+
+Return<Status> Vibrator::on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) {
+ mCallback = callback;
+ return on(timeoutMs);
+}
+
+Return<void> Vibrator::perform_1_4(V1_3::Effect effect, EffectStrength strength,
+ const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) {
+ mCallback = callback;
return perform<decltype(effect)>(effect, strength, _hidl_cb);
}
@@ -148,6 +166,14 @@
return Status::UNSUPPORTED_OPERATION;
} else {
ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false");
+ if (mEnabled && !enabled) {
+ if (auto callback = mCallback) {
+ mCallback = nullptr;
+ if (auto ret = callback->onComplete(); !ret.isOk()) {
+ ALOGE("Failed completion callback: %s", ret.description().c_str());
+ }
+ }
+ }
mEnabled = enabled;
return Status::OK;
}
@@ -271,7 +297,7 @@
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace vibrator
} // namespace hardware
} // namespace android
diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.x/example/Vibrator.h
similarity index 75%
rename from vibrator/1.3/example/Vibrator.h
rename to vibrator/1.x/example/Vibrator.h
index 5180774..ff63431 100644
--- a/vibrator/1.3/example/Vibrator.h
+++ b/vibrator/1.x/example/Vibrator.h
@@ -13,20 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#ifndef ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using android::hardware::vibrator::V1_0::EffectStrength;
using android::hardware::vibrator::V1_0::Status;
+using android::hardware::vibrator::V1_3::Effect;
class Vibrator : public IVibrator {
public:
@@ -51,7 +52,14 @@
// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
Return<bool> supportsExternalControl() override;
Return<Status> setExternalControl(bool enabled) override;
- Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+ Return<void> perform_1_3(V1_3::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+ Return<hidl_bitfield<Capabilities>> getCapabilities() override;
+ Return<Status> on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) override;
+ Return<void> perform_1_4(V1_3::Effect effect, EffectStrength strength,
+ const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) override;
private:
Return<void> perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
@@ -72,11 +80,12 @@
bool mExternalControl{false};
std::mutex mMutex;
timer_t mTimer{nullptr};
+ sp<IVibratorCallback> mCallback{nullptr};
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace vibrator
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#endif // ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
diff --git a/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
new file mode 100644
index 0000000..4893db6
--- /dev/null
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.vibrator-1-x /vendor/bin/hw/android.hardware.vibrator@1.x-service.example
+ class hal
+ user system
+ group system
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
similarity index 89%
rename from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
rename to vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
index 172aa21..ebc8c4b 100644
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.vibrator</name>
<transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1.4</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
diff --git a/vibrator/1.3/example/service.cpp b/vibrator/1.x/example/service.cpp
similarity index 82%
rename from vibrator/1.3/example/service.cpp
rename to vibrator/1.x/example/service.cpp
index 449996e..13c6691 100644
--- a/vibrator/1.3/example/service.cpp
+++ b/vibrator/1.x/example/service.cpp
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.vibrator@1.3-service.example"
+#define LOG_TAG "android.hardware.vibrator@1.x-service.example"
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
#include <hidl/HidlTransportSupport.h>
#include "Vibrator.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
-using android::hardware::vibrator::V1_3::IVibrator;
-using android::hardware::vibrator::V1_3::implementation::Vibrator;
+using android::hardware::vibrator::V1_4::IVibrator;
+using android::hardware::vibrator::V1_4::implementation::Vibrator;
using namespace android;
status_t registerVibratorService() {
diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp
index 9fdbb18..3942deb 100644
--- a/weaver/1.0/vts/functional/Android.bp
+++ b/weaver/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalWeaverV1_0TargetTest.cpp"],
static_libs: ["android.hardware.weaver@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
index de2a1de..ae92c36 100644
--- a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
+++ b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
@@ -15,12 +15,12 @@
*/
#include <android/hardware/weaver/1.0/IWeaver.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <limits>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
using ::android::hardware::weaver::V1_0::IWeaver;
using ::android::hardware::weaver::V1_0::WeaverConfig;
using ::android::hardware::weaver::V1_0::WeaverReadStatus;
@@ -34,22 +34,9 @@
const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
const std::vector<uint8_t> OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255};
-// Test environment for Weaver HIDL HAL.
-class WeaverHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static WeaverHidlEnvironment* Instance() {
- static WeaverHidlEnvironment* instance = new WeaverHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IWeaver>(); }
-};
-
-struct WeaverHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct WeaverHidlTest : public ::testing::TestWithParam<std::string> {
virtual void SetUp() override {
- weaver = ::testing::VtsHalHidlTargetTestBase::getService<IWeaver>(
- WeaverHidlEnvironment::Instance()->getServiceName<IWeaver>());
+ weaver = IWeaver::getService(GetParam());
ASSERT_NE(weaver, nullptr);
}
@@ -61,7 +48,7 @@
/*
* Checks config values are suitably large
*/
-TEST_F(WeaverHidlTest, GetConfig) {
+TEST_P(WeaverHidlTest, GetConfig) {
WeaverStatus status;
WeaverConfig config;
@@ -83,7 +70,7 @@
/*
* Gets the config twice and checks they are the same
*/
-TEST_F(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) {
+TEST_P(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) {
WeaverConfig config1;
WeaverConfig config2;
@@ -114,7 +101,7 @@
/*
* Gets the number of slots from the config and writes a key and value to the last one
*/
-TEST_F(WeaverHidlTest, WriteToLastSlot) {
+TEST_P(WeaverHidlTest, WriteToLastSlot) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -134,7 +121,7 @@
* Writes a key and value to a slot
* Reads the slot with the same key and receives the value that was previously written
*/
-TEST_F(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) {
+TEST_P(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) {
constexpr uint32_t slotId = 0;
const auto ret = weaver->write(slotId, KEY, VALUE);
ASSERT_TRUE(ret.isOk());
@@ -162,7 +149,7 @@
* Overwrites the slot with a new key and value
* Reads the slot with the new key and receives the new value
*/
-TEST_F(WeaverHidlTest, OverwritingSlotUpdatesTheValue) {
+TEST_P(WeaverHidlTest, OverwritingSlotUpdatesTheValue) {
constexpr uint32_t slotId = 0;
const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE);
ASSERT_TRUE(initialWriteRet.isOk());
@@ -193,7 +180,7 @@
* Writes a key and value to a slot
* Reads the slot with a different key so does not receive the value
*/
-TEST_F(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
+TEST_P(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
constexpr uint32_t slotId = 0;
const auto ret = weaver->write(slotId, KEY, VALUE);
ASSERT_TRUE(ret.isOk());
@@ -217,7 +204,7 @@
/*
* Writing to an invalid slot fails
*/
-TEST_F(WeaverHidlTest, WritingToInvalidSlotFails) {
+TEST_P(WeaverHidlTest, WritingToInvalidSlotFails) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -240,7 +227,7 @@
/*
* Reading from an invalid slot fails rather than incorrect key
*/
-TEST_F(WeaverHidlTest, ReadingFromInvalidSlotFails) {
+TEST_P(WeaverHidlTest, ReadingFromInvalidSlotFails) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -276,7 +263,7 @@
/*
* Writing a key that is too large fails
*/
-TEST_F(WeaverHidlTest, WriteWithTooLargeKeyFails) {
+TEST_P(WeaverHidlTest, WriteWithTooLargeKeyFails) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -297,7 +284,7 @@
/*
* Writing a value that is too large fails
*/
-TEST_F(WeaverHidlTest, WriteWithTooLargeValueFails) {
+TEST_P(WeaverHidlTest, WriteWithTooLargeValueFails) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -318,7 +305,7 @@
/*
* Reading with a key that is loo large fails
*/
-TEST_F(WeaverHidlTest, ReadWithTooLargeKeyFails) {
+TEST_P(WeaverHidlTest, ReadWithTooLargeKeyFails) {
WeaverStatus status;
WeaverConfig config;
const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -349,11 +336,7 @@
EXPECT_EQ(timeout, 0u);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(WeaverHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- WeaverHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WeaverHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IWeaver::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/IWifi.hal b/wifi/1.4/IWifi.hal
index f4bc618..765e09d 100644
--- a/wifi/1.4/IWifi.hal
+++ b/wifi/1.4/IWifi.hal
@@ -24,5 +24,4 @@
* module loaded in the system.
* IWifi.getChip() must return @1.2::IWifiChip
*/
-interface IWifi extends @1.3::IWifi {
-};
+interface IWifi extends @1.3::IWifi {};
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk
index 943becc..ab76ff6 100644
--- a/wifi/1.4/default/Android.mk
+++ b/wifi/1.4/default/Android.mk
@@ -150,7 +150,6 @@
tests/mock_wifi_legacy_hal.cpp \
tests/mock_wifi_mode_controller.cpp \
tests/ringbuffer_unit_tests.cpp \
- tests/wifi_ap_iface_unit_tests.cpp \
tests/wifi_nan_iface_unit_tests.cpp \
tests/wifi_chip_unit_tests.cpp \
tests/wifi_iface_util_unit_tests.cpp
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
index fde1df0..14a1504 100644
--- a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
@@ -170,12 +170,14 @@
legacy_hal::wifi_channel_stat channel_stat1 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+ .on_time = 0x1111,
.cca_busy_time = 0x55,
- .on_time = 0x1111};
+ };
legacy_hal::wifi_channel_stat channel_stat2 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+ .on_time = 0x2222,
.cca_busy_time = 0x66,
- .on_time = 0x2222};
+ };
radio.channel_stats.push_back(channel_stat1);
radio.channel_stats.push_back(channel_stat2);
}
diff --git a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp
deleted file mode 100644
index 230edd2..0000000
--- a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp
+++ /dev/null
@@ -1,79 +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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_ap_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_4 {
-namespace implementation {
-
-class WifiApIfaceTest : public Test {
- protected:
- 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_)};
- std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
- new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
- std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
- feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-};
-
-TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(false));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress())
- .WillOnce(testing::Return(std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}));
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_))
- .WillOnce(testing::Return(true));
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-
-TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(true));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0);
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0);
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-} // namespace implementation
-} // namespace V1_4
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
index b860910..e677f19 100644
--- a/wifi/1.4/default/wifi_ap_iface.cpp
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -31,26 +31,11 @@
WifiApIface::WifiApIface(
const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
- feature_flags_(feature_flags),
- is_valid_(true) {
- if (feature_flags_.lock()->isApMacRandomizationDisabled()) {
- LOG(INFO) << "AP MAC randomization disabled";
- return;
- }
- LOG(INFO) << "AP MAC randomization enabled";
- // Set random MAC address
- std::array<uint8_t, 6> randomized_mac =
- iface_util_.lock()->getOrCreateRandomMacAddress();
- bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac);
- if (!status) {
- LOG(ERROR) << "Failed to set random mac address";
- }
-}
+ is_valid_(true) {}
void WifiApIface::invalidate() {
legacy_hal_.reset();
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
index cb3ed3d..4f3438c 100644
--- a/wifi/1.4/default/wifi_ap_iface.h
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -20,7 +20,6 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.4/IWifiApIface.h>
-#include "wifi_feature_flags.h"
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
@@ -36,11 +35,9 @@
*/
class WifiApIface : public V1_4::IWifiApIface {
public:
- WifiApIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+ WifiApIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
@@ -72,7 +69,6 @@
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiApIface);
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 5a14b01..408096f 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -321,7 +321,6 @@
legacy_hal_(legacy_hal),
mode_controller_(mode_controller),
iface_util_(iface_util),
- feature_flags_(feature_flags),
is_valid_(true),
current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
modes_(feature_flags.lock()->getChipModes()),
@@ -806,8 +805,7 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = allocateApIfaceName();
- sp<WifiApIface> iface =
- new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
+ sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
index ae9af90..0d7061c 100644
--- a/wifi/1.4/default/wifi_chip.h
+++ b/wifi/1.4/default/wifi_chip.h
@@ -251,7 +251,6 @@
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
std::vector<sp<WifiApIface>> ap_ifaces_;
std::vector<sp<WifiNanIface>> nan_ifaces_;
std::vector<sp<WifiP2pIface>> p2p_ifaces_;
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp
index f9746eb..195b460 100644
--- a/wifi/1.4/default/wifi_feature_flags.cpp
+++ b/wifi/1.4/default/wifi_feature_flags.cpp
@@ -145,10 +145,12 @@
#undef NAN
#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-static const bool wifiHidlFeatureDisableApMacRandomization = true;
-#else
-static const bool wifiHidlFeatureDisableApMacRandomization = false;
-#endif // WIFI_HIDL_FEATURE_DISABLE_AP
+#pragma message \
+ "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+ "'config_wifi_ap_randomization_supported' in " \
+ "frameworks/base/core/res/res/values/config.xml in the device overlay " \
+ "instead"
+#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
WifiFeatureFlags::WifiFeatureFlags() {}
@@ -156,10 +158,6 @@
return kChipModes;
}
-bool WifiFeatureFlags::isApMacRandomizationDisabled() {
- return wifiHidlFeatureDisableApMacRandomization;
-}
-
} // namespace feature_flags
} // namespace implementation
} // namespace V1_4
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h
index 4e146cd..292dedf 100644
--- a/wifi/1.4/default/wifi_feature_flags.h
+++ b/wifi/1.4/default/wifi_feature_flags.h
@@ -43,7 +43,6 @@
virtual ~WifiFeatureFlags() = default;
virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
- virtual bool isApMacRandomizationDisabled();
};
} // namespace feature_flags
diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp
index 597c04b..8ceb926 100644
--- a/wifi/1.4/default/wifi_status_util.cpp
+++ b/wifi/1.4/default/wifi_status_util.cpp
@@ -46,6 +46,8 @@
return "BUSY";
case legacy_hal::WIFI_ERROR_UNKNOWN:
return "UNKNOWN";
+ default:
+ return "UNKNOWN ERROR";
}
}
@@ -92,6 +94,10 @@
case legacy_hal::WIFI_ERROR_UNKNOWN:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+ default:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+ "unknown error");
}
}
diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp
index de15aa7..965c946 100644
--- a/wifi/offload/1.0/vts/functional/Android.bp
+++ b/wifi/offload/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"],
static_libs: ["android.hardware.wifi.offload@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
index dbe4e74..83d834c 100644
--- a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
+++ b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
@@ -20,10 +20,11 @@
#include <android/hardware/wifi/offload/1.0/IOffload.h>
#include <android/hardware/wifi/offload/1.0/IOffloadCallback.h>
#include <android/hardware/wifi/offload/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <vector>
@@ -69,33 +70,11 @@
OffloadStatus error_code_;
};
-// Test environment for Weaver HIDL HAL.
-class WifiOffloadHidlEnvironment
- : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static WifiOffloadHidlEnvironment* Instance() {
- static WifiOffloadHidlEnvironment* instance =
- new WifiOffloadHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IOffload>();
- }
-
- private:
- WifiOffloadHidlEnvironment() {}
-};
-
// The main test class for WifiOffload HIDL HAL.
-class WifiOffloadHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiOffloadHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_offload_ =
- ::testing::VtsHalHidlTargetTestBase::getService<IOffload>(
- WifiOffloadHidlEnvironment::Instance()
- ->getServiceName<IOffload>());
+ wifi_offload_ = IOffload::getService(GetParam());
ASSERT_NE(wifi_offload_, nullptr);
wifi_offload_cb_ = new OffloadCallback();
@@ -136,7 +115,7 @@
/*
* Verify that setEventCallback method returns without errors
*/
-TEST_F(WifiOffloadHidlTest, setEventCallback) {
+TEST_P(WifiOffloadHidlTest, setEventCallback) {
auto returnObject = wifi_offload_->setEventCallback(wifi_offload_cb_);
ASSERT_EQ(true, returnObject.isOk());
}
@@ -144,7 +123,7 @@
/*
* Verify that subscribeScanResults method returns without errors
*/
-TEST_F(WifiOffloadHidlTest, subscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, subscribeScanResults) {
const auto& result = HIDL_INVOKE(wifi_offload_, subscribeScanResults, 0);
ASSERT_EQ(OffloadStatusCode::OK, result.code);
}
@@ -152,7 +131,7 @@
/*
* Verify that unsubscribeScanResults method returns without errors
*/
-TEST_F(WifiOffloadHidlTest, unsubscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, unsubscribeScanResults) {
auto returnObject = wifi_offload_->unsubscribeScanResults();
ASSERT_EQ(true, returnObject.isOk());
}
@@ -160,7 +139,7 @@
/*
* Verify that configureScans method returns without errors
*/
-TEST_F(WifiOffloadHidlTest, configureScans) {
+TEST_P(WifiOffloadHidlTest, configureScans) {
ScanParam* pScanParam = new ScanParam();
std::vector<uint32_t> frequencyList = {kFrequency1, kFrequency2};
pScanParam->disconnectedModeScanIntervalMs =
@@ -192,7 +171,7 @@
/*
* Verify that getScanStats returns without any errors
*/
-TEST_F(WifiOffloadHidlTest, getScanStats) {
+TEST_P(WifiOffloadHidlTest, getScanStats) {
const auto& result = HIDL_INVOKE(wifi_offload_, getScanStats);
OffloadStatus status = result.first;
ASSERT_EQ(OffloadStatusCode::OK, status.code);
@@ -201,7 +180,7 @@
/*
* Verify that onScanResult callback is invoked
*/
-TEST_F(WifiOffloadHidlTest, getScanResults) {
+TEST_P(WifiOffloadHidlTest, getScanResults) {
wifi_offload_->setEventCallback(wifi_offload_cb_);
std::vector<ScanResult> scan_results;
std::vector<uint8_t> ssid(kSsid1, kSsid1 + sizeof(kSsid1));
@@ -223,7 +202,7 @@
/*
* Verify that onError callback is invoked
*/
-TEST_F(WifiOffloadHidlTest, getError) {
+TEST_P(WifiOffloadHidlTest, getError) {
wifi_offload_->setEventCallback(wifi_offload_cb_);
OffloadStatus status = {OffloadStatusCode::ERROR, ""};
wifi_offload_cb_->onError(status);
@@ -231,12 +210,8 @@
ASSERT_EQ(true, res.no_timeout);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(WifiOffloadHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- WifiOffloadHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
-
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiOffloadHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IOffload::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/offload/1.0/vts/functional/hidl_call_util.h b/wifi/offload/1.0/vts/functional/hidl_call_util.h
index f3ca517..99868e8 100644
--- a/wifi/offload/1.0/vts/functional/hidl_call_util.h
+++ b/wifi/offload/1.0/vts/functional/hidl_call_util.h
@@ -21,8 +21,6 @@
#include <type_traits>
#include <utility>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace {
namespace detail {
template <typename>
diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal
index 75b7e96..246ce1f 100644
--- a/wifi/supplicant/1.3/ISupplicant.hal
+++ b/wifi/supplicant/1.3/ISupplicant.hal
@@ -26,5 +26,4 @@
* 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface,
* which can be cast to V1_3::ISupplicantStaIface.
*/
-interface ISupplicant extends @1.2::ISupplicant {
-};
+interface ISupplicant extends @1.2::ISupplicant {};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index 62b4033..cb207d8 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -18,7 +18,7 @@
import @1.0::SupplicantStatus;
import @1.2::ISupplicantStaIface;
-import @1.3::ISupplicantStaIfaceCallback;
+import ISupplicantStaIfaceCallback;
/**
* Interface exposed by the supplicant for each station mode network
@@ -43,4 +43,15 @@
*/
registerCallback_1_3(ISupplicantStaIfaceCallback callback)
generates (SupplicantStatus status);
+
+ /**
+ * Get Connection capabilities
+ *
+ * @return status Status of the operation, and connection capabilities.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ */
+ getConnectionCapabilities()
+ generates (SupplicantStatus status, ConnectionCapabilities capabilities);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index 5e265c6..ab08cff 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -60,6 +60,5 @@
* |SupplicantStatusCode.FAILURE_UNKNOWN|,
* |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
*/
- setPmkCache(vec<uint8_t> serializedEntry)
- generates (SupplicantStatus status);
+ setPmkCache(vec<uint8_t> serializedEntry) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
index a782b49..7874399 100644
--- a/wifi/supplicant/1.3/types.hal
+++ b/wifi/supplicant/1.3/types.hal
@@ -25,3 +25,36 @@
REQUIRE_CERT_STATUS,
REQUIRE_ALL_CERTS_STATUS,
};
+
+/**
+ * Wifi Technologies
+ */
+enum WifiTechnology : uint32_t {
+ UNKNOWN = 0,
+ /**
+ * For 802.11a/b/g
+ */
+ LEGACY = 1,
+ /**
+ * For 802.11n
+ */
+ HT = 2,
+ /**
+ * For 802.11ac
+ */
+ VHT = 3,
+ /**
+ * For 802.11ax
+ */
+ HE = 4,
+};
+
+/**
+ * Connection Capabilities.
+ */
+struct ConnectionCapabilities {
+ /**
+ * Wifi Technology
+ */
+ WifiTechnology technology;
+};
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 9b68a47..62f3228 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
@@ -37,6 +37,7 @@
using ::android::hardware::wifi::supplicant::V1_2::DppAkm;
using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode;
using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
+using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
@@ -179,3 +180,14 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+/*
+ * getConnectionCapabilities
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+ sta_iface_->getConnectionCapabilities(
+ [&](const SupplicantStatus& status,
+ ConnectionCapabilities /* capabilities */) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}