diff options
232 files changed, 17846 insertions, 1506 deletions
diff --git a/.clang-format b/.clang-format index 3494682bb3..ddcf5a2915 100644..120000 --- a/.clang-format +++ b/.clang-format @@ -1,25 +1 @@ -# -# 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. -# - -BasedOnStyle: Google -CommentPragmas: NOLINT:.* -DerivePointerAlignment: false -AllowShortFunctionsOnASingleLine: Inline -ColumnLimit: 100 -TabWidth: 4 -UseTab: Never -IndentWidth: 4 -ContinuationIndentWidth: 8 +../../build/soong/scripts/system-clang-format
\ No newline at end of file diff --git a/audio/5.0/config/api/current.txt b/audio/5.0/config/api/current.txt index 822237e014..17f38c1647 100644 --- a/audio/5.0/config/api/current.txt +++ b/audio/5.0/config/api/current.txt @@ -20,8 +20,10 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_HDMI; + enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_IP; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_LINE; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK; @@ -91,6 +93,10 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_ERLC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LTP; @@ -106,7 +112,9 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APE; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX_HD; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_CELT; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DSD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DTS; @@ -122,6 +130,8 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_IEC61937; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LDAC; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LHDC; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LHDC_LL; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_1_0; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_2_0; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_2_1; diff --git a/audio/5.0/config/audio_policy_configuration.xsd b/audio/5.0/config/audio_policy_configuration.xsd index efe93b3ee9..ee3a437d1d 100644 --- a/audio/5.0/config/audio_policy_configuration.xsd +++ b/audio/5.0/config/audio_policy_configuration.xsd @@ -277,6 +277,8 @@ <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> @@ -364,6 +366,14 @@ <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:restriction> </xs:simpleType> <xs:simpleType name="extendableAudioFormat"> diff --git a/audio/common/5.0/types.hal b/audio/common/5.0/types.hal index b4e947096f..ffe45069a8 100644 --- a/audio/common/5.0/types.hal +++ b/audio/common/5.0/types.hal @@ -235,6 +235,12 @@ enum AudioFormat : uint32_t { LDAC = 0x23000000UL, /** Dolby Metadata-enhanced Audio Transmission */ MAT = 0x24000000UL, + AAC_LATM = 0x25000000UL, + CELT = 0x26000000UL, + APTX_ADAPTIVE = 0x27000000UL, + LHDC = 0x28000000UL, + LHDC_LL = 0x29000000UL, + /** Deprecated */ MAIN_MASK = 0xFF000000UL, SUB_MASK = 0x00FFFFFFUL, @@ -306,6 +312,9 @@ enum AudioFormat : uint32_t { 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), }; /** diff --git a/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000000..bdb17cdc3c --- /dev/null +++ b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp @@ -0,0 +1,55 @@ +/* + * 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 <math.h> + +// pull in all the <= 4.0 tests +#include "4.0/AudioPrimaryHidlHalTest.cpp" + +TEST_P(InputStreamTest, SetMicrophoneDirection) { + doc::test("Make sure setMicrophoneDirection correctly handles valid & invalid arguments"); + + // MicrophoneDirection dir = MicrophoneDirection::FRONT; + for (MicrophoneDirection dir : android::hardware::hidl_enum_range<MicrophoneDirection>()) { + ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneDirection(dir)); + } + + // Bogus values + for (auto dir : {42, -1, 4}) { + ASSERT_RESULT(invalidArgsOrNotSupported, + stream->setMicrophoneDirection(MicrophoneDirection(dir))); + } +} + +TEST_P(InputStreamTest, SetMicrophoneFieldDimension) { + doc::test("Make sure setMicrophoneFieldDimension correctly handles valid & invalid arguments"); + + // Valid zoom values -1.0 -> 1.0 + float incr = 0.1f; + for (float val = -1.0f; val <= 1.0; val += incr) { + ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneFieldDimension(val)); + } + + // Bogus values + for (float val = 1.0f + incr; val <= 10.0f; val += incr) { + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(val)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-val)); + } + // Some extremes + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(NAN)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-NAN)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(INFINITY)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-INFINITY)); +} diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 6498289dd4..88fdb5a1dd 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -20,9 +20,6 @@ cc_defaults { static_libs: [ "android.hardware.audio.common.test.utility", "libaudiopolicycomponents", - "libicuuc", - "libicuuc_stubdata", - "libandroidicu", "libmedia_helper", "libxml2", ], @@ -73,8 +70,7 @@ cc_test { name: "VtsHalAudioV5_0TargetTest", defaults: ["VtsHalAudioTargetTest_defaults"], srcs: [ - // for now the tests are the same as V4 - "4.0/AudioPrimaryHidlHalTest.cpp", + "5.0/AudioPrimaryHidlHalTest.cpp", ], static_libs: [ "android.hardware.audio@5.0", diff --git a/audio/effect/2.0/xml/audio_effects_conf.xsd b/audio/effect/2.0/xml/audio_effects_conf.xsd index df281b32d1..b97b847a39 100644 --- a/audio/effect/2.0/xml/audio_effects_conf.xsd +++ b/audio/effect/2.0/xml/audio_effects_conf.xsd @@ -39,6 +39,7 @@ <xs:enumeration value="voice_recognition"/> <xs:enumeration value="voice_communication"/> <xs:enumeration value="unprocessed"/> + <xs:enumeration value="voice_performance"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="streamOutputType"> diff --git a/audio/effect/5.0/types.hal b/audio/effect/5.0/types.hal index 84e11086b4..4b6c196b81 100644 --- a/audio/effect/5.0/types.hal +++ b/audio/effect/5.0/types.hal @@ -53,6 +53,7 @@ enum Result : int32_t { * | 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 @@ -136,6 +137,7 @@ enum EffectFlags : int32_t { 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 diff --git a/audio/effect/5.0/xml/api/current.txt b/audio/effect/5.0/xml/api/current.txt index 4a7f88b558..473bb10358 100644 --- a/audio/effect/5.0/xml/api/current.txt +++ b/audio/effect/5.0/xml/api/current.txt @@ -74,6 +74,7 @@ package audio.effects.V5_0 { enum_constant public static final audio.effects.V5_0.StreamInputType voice_call; enum_constant public static final audio.effects.V5_0.StreamInputType voice_communication; enum_constant public static final audio.effects.V5_0.StreamInputType voice_downlink; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_performance; enum_constant public static final audio.effects.V5_0.StreamInputType voice_recognition; enum_constant public static final audio.effects.V5_0.StreamInputType voice_uplink; } diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp index de6cad9ad0..cccb5c86aa 100644 --- a/audio/effect/all-versions/vts/functional/Android.bp +++ b/audio/effect/all-versions/vts/functional/Android.bp @@ -26,9 +26,6 @@ cc_defaults { "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libeffectsconfig", - "libicuuc", - "libicuuc_stubdata", - "libandroidicu", "libxml2", ], header_libs: [ 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 7614cad1f7..08cdffa715 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 @@ -198,6 +198,15 @@ const ConfigDeclaration kVehicleProperties[]{ {.config = { + .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {SEAT_1_LEFT}}}, + + {.config = + { .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, @@ -321,6 +330,8 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::CONTINUOUS, .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, }, .initialValue = {.floatValues = {100.0f}}}, // units in meters @@ -328,6 +339,8 @@ const ConfigDeclaration kVehicleProperties[]{ {.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, diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal index e3c256a2bf..813f04000b 100644 --- a/biometrics/face/1.0/IBiometricsFace.hal +++ b/biometrics/face/1.0/IBiometricsFace.hal @@ -18,9 +18,6 @@ package android.hardware.biometrics.face@1.0; import IBiometricsFaceClientCallback; -// TODO(b/78538290): Update comments with state machine transitions when ready. -// TODO(b/78537981): Update comments with callback interaction contract. -// TODO(b/79496983): Update comments with status returns fully enumerated. /** * The HAL interface for biometric face authentication. */ diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal index a488d671d0..b5db966b47 100644 --- a/biometrics/face/1.0/types.hal +++ b/biometrics/face/1.0/types.hal @@ -281,9 +281,62 @@ enum FaceAcquiredInfo : int32_t { TOO_SIMILAR = 15, /** + * The magnitude of the pan angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The pan angle is defined as the angle swept out by the user’s face turning + * their neck left and right. The pan angle would be zero if the user faced the + * camera directly. + * + * The user should be informed to look more directly at the camera. + */ + PAN_TOO_EXTREME = 16, + + /** + * The magnitude of the tilt angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The tilt angle is defined as the angle swept out by the user’s face looking up + * and down. The tilt angle would be zero if the user faced the camera directly. + * + * The user should be informed to look more directly at the camera. + */ + TILT_TOO_EXTREME = 17, + + /** + * The magnitude of the roll angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The roll angle is defined as the angle swept out by the user’s face tilting their head + * towards their shoulders to the left and right. The roll angle would be zero if the user's + * head is vertically aligned with the camera. + * + * The user should be informed to look more directly at the camera. + */ + ROLL_TOO_EXTREME = 18, + + /** + * The user’s face has been obscured by some object. + * + * The user should be informed to remove any objects from the line of sight from + * the sensor to the user’s face. + */ + FACE_OBSCURED = 19, + + /** + * This message represents the earliest message sent at the beginning of the authentication + * pipeline. It is expected to be used to measure latency. For example, in a camera-based + * authentication system it's expected to be sent prior to camera initialization. Note this + * should be sent whenever authentication is restarted (see IBiometricsFace#userActivity). + * The framework will measure latency based on the time between the last START message and the + * onAuthenticated callback. + */ + START = 20, + + /** * Used to enable a vendor-specific acquisition message. */ - VENDOR = 16 + VENDOR = 21 }; /** diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp index 6049fe2b54..5d67f75f04 100644 --- a/bluetooth/audio/2.0/Android.bp +++ b/bluetooth/audio/2.0/Android.bp @@ -16,13 +16,25 @@ hidl_interface { ], types: [ "AacObjectType", + "AacParameters", + "AacVariableBitRate", + "AptxParameters", + "AudioCapabilities", + "AudioConfiguration", "BitsPerSample", "ChannelMode", + "CodecCapabilities", "CodecConfiguration", "CodecType", "LdacChannelMode", + "LdacParameters", + "LdacQualityIndex", + "PcmParameters", "SampleRate", + "SbcAllocMethod", + "SbcBlockLength", "SbcChannelMode", + "SbcParameters", "SessionType", "Status", "TimeSpec", diff --git a/bluetooth/audio/2.0/IBluetoothAudioPort.hal b/bluetooth/audio/2.0/IBluetoothAudioPort.hal index 17d13b8663..fedc8d3eba 100644 --- a/bluetooth/audio/2.0/IBluetoothAudioPort.hal +++ b/bluetooth/audio/2.0/IBluetoothAudioPort.hal @@ -27,6 +27,9 @@ import android.hardware.audio.common@5.0::SourceMetadata; * * Moreover, the Audio HAL can also get the presentation position of the stream * and provide stream metadata. + * + * Note: For HIDL APIs with a "generates" statement, the callback parameter used + * for return value must be invoked synchronously before the API call returns. */ interface IBluetoothAudioPort { /** diff --git a/bluetooth/audio/2.0/IBluetoothAudioProvider.hal b/bluetooth/audio/2.0/IBluetoothAudioProvider.hal index bb5eb1b9e3..2b08cc3e4a 100644 --- a/bluetooth/audio/2.0/IBluetoothAudioProvider.hal +++ b/bluetooth/audio/2.0/IBluetoothAudioProvider.hal @@ -23,6 +23,9 @@ import IBluetoothAudioPort; * * The Bluetooth stack calls methods in this interface to start and end audio * sessions and sends callback events to the Audio HAL. + * + * Note: For HIDL APIs with a "generates" statement, the callback parameter used + * for return value must be invoked synchronously before the API call returns. */ interface IBluetoothAudioProvider { @@ -35,8 +38,10 @@ interface IBluetoothAudioProvider { * Note: endSession() must be called to unregister this IBluetoothAudioPort * * @param hostIf An instance of IBluetoothAudioPort for stream control - * @param codecConfig The codec configuration negotiated with the remote - * device + * @param audioConfig The audio configuration negotiated with the remote + * device. The PCM parameters are set if software based encoding, + * otherwise the correct codec configuration is used for hardware + * encoding. * * @return status One of the following * SUCCESS if this IBluetoothAudioPort was successfully registered with @@ -47,10 +52,10 @@ interface IBluetoothAudioProvider { * any other reason * @return dataMQ The fast message queue for audio data from this provider. * Audio data will be in PCM format as specified by the - * codecConfig.pcmDataConfiguration parameter. - * nullptr if streaming is offloaded to hardware or on failure. + * audioConfig.pcmConfig parameter. + * Invalid if streaming is offloaded to hardware or on failure. */ - startSession(IBluetoothAudioPort hostIf, CodecConfiguration codecConfig) + startSession(IBluetoothAudioPort hostIf, AudioConfiguration audioConfig) generates (Status status, fmq_sync<uint8_t> dataMQ); /** diff --git a/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.hal index 56b8594178..1025665206 100644 --- a/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.hal +++ b/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.hal @@ -25,6 +25,9 @@ import IBluetoothAudioProvider; * When the Bluetooth stack is ready to create an audio session, it must first * obtain the IBluetoothAudioProvider for that session type by calling * openProvider(). + * + * Note: For HIDL APIs with a "generates" statement, the callback parameter used + * for return value must be invoked synchronously before the API call returns. */ interface IBluetoothAudioProvidersFactory { @@ -43,4 +46,26 @@ interface IBluetoothAudioProvidersFactory { */ openProvider(SessionType sessionType) generates (Status status, IBluetoothAudioProvider provider); + + /** + * Gets a list of audio capabilities for a session type. + * + * For software encoding, the PCM capabilities are returned. + * For hardware encoding, the supported codecs and their capabilities are + * returned. + * + * @param sessionType The session type (e.g. + * A2DP_SOFTWARE_ENCODING_DATAPATH). + * @return audioCapabilities A list containing all the capabilities + * supported by the sesson type. The capabilities is a list of + * available options when configuring the codec for the session. + * For software encoding it is the PCM data rate. + * For hardware encoding it is the list of supported codecs and their + * capabilities. + * If a provider isn't supported, an empty list should be returned. + * Note: Only one entry should exist per codec when using hardware + * encoding. + */ + getProviderCapabilities(SessionType sessionType) + generates (vec<AudioCapabilities> audioCapabilities); }; diff --git a/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp new file mode 100644 index 0000000000..84fba34ca9 --- /dev/null +++ b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderA2dpOffload" + +#include <android-base/logging.h> +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> + +#include "A2dpOffloadAudioProvider.h" +#include "BluetoothAudioSessionReport.h" +#include "BluetoothAudioSupportedCodecsDB.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::bluetooth::audio::BluetoothAudioSessionReport; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::Void; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + +A2dpOffloadAudioProvider::A2dpOffloadAudioProvider() + : BluetoothAudioProvider() { + session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH; +} + +bool A2dpOffloadAudioProvider::isValid(const SessionType& sessionType) { + return (sessionType == session_type_); +} + +Return<void> A2dpOffloadAudioProvider::startSession( + const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) { + /** + * Initialize the audio platform if audioConfiguration is supported. + * Save the the IBluetoothAudioPort interface, so that it can be used + * later to send stream control commands to the HAL client, based on + * interaction with Audio framework. + */ + if (audioConfig.getDiscriminator() != + AudioConfiguration::hidl_discriminator::codecConfig) { + LOG(WARNING) << __func__ + << " - Invalid Audio Configuration=" << toString(audioConfig); + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } else if (!android::bluetooth::audio::IsOffloadCodecConfigurationValid( + session_type_, audioConfig.codecConfig())) { + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } + + return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb); +} + +Return<void> A2dpOffloadAudioProvider::onSessionReady( + startSession_cb _hidl_cb) { + BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_, + nullptr, audio_config_); + _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor()); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h new file mode 100644 index 0000000000..9f40278a4b --- /dev/null +++ b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BluetoothAudioProvider.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +class A2dpOffloadAudioProvider : public BluetoothAudioProvider { + public: + A2dpOffloadAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, + startSession_cb _hidl_cb) override; + + private: + Return<void> onSessionReady(startSession_cb _hidl_cb) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp new file mode 100644 index 0000000000..f71a73e233 --- /dev/null +++ b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderA2dpSoftware" + +#include <android-base/logging.h> + +#include "A2dpSoftwareAudioProvider.h" +#include "BluetoothAudioSessionReport.h" +#include "BluetoothAudioSupportedCodecsDB.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::bluetooth::audio::BluetoothAudioSessionReport; +using ::android::hardware::Void; + +static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo +static constexpr uint32_t kPcmFrameCount = 128; +static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount; +static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms) +static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount; +static constexpr uint32_t kBufferCount = 2; // double buffer +static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount; + +A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider() + : BluetoothAudioProvider(), mDataMQ(nullptr) { + LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize + << " byte(s)"; + std::unique_ptr<DataMQ> tempDataMQ( + new DataMQ(kDataMqSize, /* EventFlag */ true)); + if (tempDataMQ && tempDataMQ->isValid()) { + mDataMQ = std::move(tempDataMQ); + session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH; + } else { + ALOGE_IF(!tempDataMQ, "failed to allocate data MQ"); + ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid"); + } +} + +bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) { + return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid()); +} + +Return<void> A2dpSoftwareAudioProvider::startSession( + const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) { + /** + * Initialize the audio platform if audioConfiguration is supported. + * Save the the IBluetoothAudioPort interface, so that it can be used + * later to send stream control commands to the HAL client, based on + * interaction with Audio framework. + */ + if (audioConfig.getDiscriminator() != + AudioConfiguration::hidl_discriminator::pcmConfig) { + LOG(WARNING) << __func__ + << " - Invalid Audio Configuration=" << toString(audioConfig); + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid( + audioConfig.pcmConfig())) { + LOG(WARNING) << __func__ << " - Unsupported PCM Configuration=" + << toString(audioConfig.pcmConfig()); + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } + + return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb); +} + +Return<void> A2dpSoftwareAudioProvider::onSessionReady( + startSession_cb _hidl_cb) { + if (mDataMQ && mDataMQ->isValid()) { + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_); + _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc()); + } else { + _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor()); + } + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h new file mode 100644 index 0000000000..228a928c30 --- /dev/null +++ b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> + +#include "BluetoothAudioProvider.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + +class A2dpSoftwareAudioProvider : public BluetoothAudioProvider { + public: + A2dpSoftwareAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, + startSession_cb _hidl_cb) override; + + private: + // audio data queue for software encoding + std::unique_ptr<DataMQ> mDataMQ; + + Return<void> onSessionReady(startSession_cb _hidl_cb) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/Android.bp b/bluetooth/audio/2.0/default/Android.bp new file mode 100644 index 0000000000..1dfc05dfaa --- /dev/null +++ b/bluetooth/audio/2.0/default/Android.bp @@ -0,0 +1,48 @@ +cc_library_shared { + name: "android.hardware.bluetooth.audio@2.0-impl", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "BluetoothAudioProvidersFactory.cpp", + "BluetoothAudioProvider.cpp", + "A2dpOffloadAudioProvider.cpp", + "A2dpSoftwareAudioProvider.cpp", + "HearingAidAudioProvider.cpp", + ], + header_libs: ["libhardware_headers"], + shared_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.bluetooth.audio@2.0", + "libbase", + "libbluetooth_audio_session", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +} + +cc_library_shared { + name: "libbluetooth_audio_session", + defaults: ["hidl_defaults"], + vendor: true, + srcs: [ + "session/BluetoothAudioSession.cpp", + "session/BluetoothAudioSupportedCodecsDB.cpp", + ], + export_include_dirs: ["session/"], + header_libs: ["libhardware_headers"], + shared_libs: [ + "android.hardware.bluetooth.audio@2.0", + "libbase", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +} diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp new file mode 100644 index 0000000000..ab8973e52e --- /dev/null +++ b/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderStub" + +#include <android-base/logging.h> + +#include "BluetoothAudioProvider.h" +#include "BluetoothAudioSessionReport.h" +#include "BluetoothAudioSupportedCodecsDB.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::bluetooth::audio::BluetoothAudioSessionReport; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::Void; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + +void BluetoothAudioDeathRecipient::serviceDied( + uint64_t cookie __unused, + const wp<::android::hidl::base::V1_0::IBase>& who __unused) { + LOG(ERROR) << "BluetoothAudioDeathRecipient::" << __func__ + << " - BluetoothAudio Service died"; + provider_->endSession(); +} + +BluetoothAudioProvider::BluetoothAudioProvider() + : death_recipient_(new BluetoothAudioDeathRecipient(this)), + session_type_(SessionType::UNKNOWN), + audio_config_({}) {} + +Return<void> BluetoothAudioProvider::startSession( + const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) { + if (hostIf == nullptr) { + _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor()); + return Void(); + } + + /** + * Initialize the audio platform if audioConfiguration is supported. + * Save the the IBluetoothAudioPort interface, so that it can be used + * later to send stream control commands to the HAL client, based on + * interaction with Audio framework. + */ + audio_config_ = audioConfig; + stack_iface_ = hostIf; + stack_iface_->linkToDeath(death_recipient_, 0); + + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", AudioConfiguration=[" << toString(audio_config_) << "]"; + + onSessionReady(_hidl_cb); + return Void(); +} + +Return<void> BluetoothAudioProvider::streamStarted( + BluetoothAudioStatus status) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status); + + /** + * Streaming on control path has started, + * HAL server should start the streaming on data path. + */ + if (stack_iface_) { + BluetoothAudioSessionReport::ReportControlStatus(session_type_, true, + status); + } else { + LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status) << " has NO session"; + } + + return Void(); +} + +Return<void> BluetoothAudioProvider::streamSuspended( + BluetoothAudioStatus status) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status); + + /** + * Streaming on control path has suspend, + * HAL server should suspend the streaming on data path. + */ + if (stack_iface_) { + BluetoothAudioSessionReport::ReportControlStatus(session_type_, false, + status); + } else { + LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status) << " has NO session"; + } + + return Void(); +} + +Return<void> BluetoothAudioProvider::endSession() { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); + + if (stack_iface_) { + BluetoothAudioSessionReport::OnSessionEnded(session_type_); + stack_iface_->unlinkToDeath(death_recipient_); + } else { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + } + + /** + * Clean up the audio platform as remote audio device is no + * longer active + */ + stack_iface_ = nullptr; + audio_config_ = {}; + + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvider.h b/bluetooth/audio/2.0/default/BluetoothAudioProvider.h new file mode 100644 index 0000000000..02bf2b992a --- /dev/null +++ b/bluetooth/audio/2.0/default/BluetoothAudioProvider.h @@ -0,0 +1,79 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h> + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::SessionType; + +using BluetoothAudioStatus = + ::android::hardware::bluetooth::audio::V2_0::Status; + +class BluetoothAudioDeathRecipient; + +class BluetoothAudioProvider : public IBluetoothAudioProvider { + public: + BluetoothAudioProvider(); + ~BluetoothAudioProvider() = default; + + virtual bool isValid(const SessionType& sessionType) = 0; + + Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, + startSession_cb _hidl_cb) override; + Return<void> streamStarted(BluetoothAudioStatus status) override; + Return<void> streamSuspended(BluetoothAudioStatus status) override; + Return<void> endSession() override; + + protected: + sp<BluetoothAudioDeathRecipient> death_recipient_; + + SessionType session_type_; + AudioConfiguration audio_config_; + sp<IBluetoothAudioPort> stack_iface_; + + virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0; +}; + +class BluetoothAudioDeathRecipient : public hidl_death_recipient { + public: + BluetoothAudioDeathRecipient(const sp<BluetoothAudioProvider> provider) + : provider_(provider) {} + + virtual void serviceDied( + uint64_t cookie, + const wp<::android::hidl::base::V1_0::IBase>& who) override; + + private: + sp<BluetoothAudioProvider> provider_; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp new file mode 100644 index 0000000000..df89cc8bae --- /dev/null +++ b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProvidersFactory" + +#include <android-base/logging.h> + +#include "BluetoothAudioProvidersFactory.h" +#include "BluetoothAudioSupportedCodecsDB.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::hidl_vec; +using ::android::hardware::Void; + +A2dpSoftwareAudioProvider + BluetoothAudioProvidersFactory::a2dp_software_provider_instance_; +A2dpOffloadAudioProvider + BluetoothAudioProvidersFactory::a2dp_offload_provider_instance_; +HearingAidAudioProvider + BluetoothAudioProvidersFactory::hearing_aid_provider_instance_; + +Return<void> BluetoothAudioProvidersFactory::openProvider( + const SessionType sessionType, openProvider_cb _hidl_cb) { + LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType); + BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS; + BluetoothAudioProvider* provider = nullptr; + switch (sessionType) { + case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH: + provider = &a2dp_software_provider_instance_; + break; + case SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH: + provider = &a2dp_offload_provider_instance_; + break; + case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH: + provider = &hearing_aid_provider_instance_; + break; + default: + status = BluetoothAudioStatus::FAILURE; + } + if (provider == nullptr || !provider->isValid(sessionType)) { + provider = nullptr; + status = BluetoothAudioStatus::FAILURE; + LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType) + << ", status=" << toString(status); + } + _hidl_cb(status, provider); + return Void(); +} + +Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities( + const SessionType sessionType, getProviderCapabilities_cb _hidl_cb) { + hidl_vec<AudioCapabilities> audio_capabilities = + hidl_vec<AudioCapabilities>(0); + if (sessionType == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + std::vector<CodecCapabilities> db_codec_capabilities = + android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType); + if (db_codec_capabilities.size()) { + audio_capabilities.resize(db_codec_capabilities.size()); + for (int i = 0; i < db_codec_capabilities.size(); ++i) { + audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]); + } + } + } else if (sessionType != SessionType::UNKNOWN) { + std::vector<PcmParameters> db_pcm_capabilities = + android::bluetooth::audio::GetSoftwarePcmCapabilities(); + if (db_pcm_capabilities.size() == 1) { + audio_capabilities.resize(1); + audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]); + } + } + LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType) + << " supports " << audio_capabilities.size() << " codecs"; + _hidl_cb(audio_capabilities); + return Void(); +} + +IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory( + const char* /* name */) { + return new BluetoothAudioProvidersFactory(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h new file mode 100644 index 0000000000..0b515365bb --- /dev/null +++ b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h> + +#include "A2dpOffloadAudioProvider.h" +#include "A2dpSoftwareAudioProvider.h" +#include "BluetoothAudioProvider.h" +#include "HearingAidAudioProvider.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory { + public: + BluetoothAudioProvidersFactory() {} + + Return<void> openProvider(const SessionType sessionType, + openProvider_cb _hidl_cb) override; + + Return<void> getProviderCapabilities( + const SessionType sessionType, + getProviderCapabilities_cb _hidl_cb) override; + + private: + static A2dpSoftwareAudioProvider a2dp_software_provider_instance_; + static A2dpOffloadAudioProvider a2dp_offload_provider_instance_; + static HearingAidAudioProvider hearing_aid_provider_instance_; +}; + +extern "C" IBluetoothAudioProvidersFactory* +HIDL_FETCH_IBluetoothAudioProvidersFactory(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp new file mode 100644 index 0000000000..e91cf8ad44 --- /dev/null +++ b/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderHearingAid" + +#include <android-base/logging.h> + +#include "BluetoothAudioSessionReport.h" +#include "BluetoothAudioSupportedCodecsDB.h" +#include "HearingAidAudioProvider.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::bluetooth::audio::BluetoothAudioSessionReport; +using ::android::hardware::Void; + +static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo +static constexpr uint32_t kPcmFrameCount = 128; +static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount; +static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms) +static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount; +static constexpr uint32_t kBufferCount = 1; // single buffer +static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount; + +HearingAidAudioProvider::HearingAidAudioProvider() + : BluetoothAudioProvider(), mDataMQ(nullptr) { + LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize + << " byte(s)"; + std::unique_ptr<DataMQ> tempDataMQ( + new DataMQ(kDataMqSize, /* EventFlag */ true)); + if (tempDataMQ && tempDataMQ->isValid()) { + mDataMQ = std::move(tempDataMQ); + session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH; + } else { + ALOGE_IF(!tempDataMQ, "failed to allocate data MQ"); + ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid"); + } +} + +bool HearingAidAudioProvider::isValid(const SessionType& sessionType) { + return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid()); +} + +Return<void> HearingAidAudioProvider::startSession( + const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) { + /** + * Initialize the audio platform if audioConfiguration is supported. + * Save the the IBluetoothAudioPort interface, so that it can be used + * later to send stream control commands to the HAL client, based on + * interaction with Audio framework. + */ + if (audioConfig.getDiscriminator() != + AudioConfiguration::hidl_discriminator::pcmConfig) { + LOG(WARNING) << __func__ + << " - Invalid Audio Configuration=" << toString(audioConfig); + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid( + audioConfig.pcmConfig())) { + LOG(WARNING) << __func__ << " - Unsupported PCM Configuration=" + << toString(audioConfig.pcmConfig()); + _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION, + DataMQ::Descriptor()); + return Void(); + } + + return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb); +} + +Return<void> HearingAidAudioProvider::onSessionReady(startSession_cb _hidl_cb) { + if (mDataMQ && mDataMQ->isValid()) { + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_); + _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc()); + } else { + _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor()); + } + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/HearingAidAudioProvider.h b/bluetooth/audio/2.0/default/HearingAidAudioProvider.h new file mode 100644 index 0000000000..117eb32c9a --- /dev/null +++ b/bluetooth/audio/2.0/default/HearingAidAudioProvider.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> + +#include "BluetoothAudioProvider.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + +class HearingAidAudioProvider : public BluetoothAudioProvider { + public: + HearingAidAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf, + const AudioConfiguration& audioConfig, + startSession_cb _hidl_cb) override; + + private: + // audio data queue for software encoding + std::unique_ptr<DataMQ> mDataMQ; + + Return<void> onSessionReady(startSession_cb _hidl_cb) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp new file mode 100644 index 0000000000..d60e7324f3 --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp @@ -0,0 +1,427 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderSession" + +#include "BluetoothAudioSession.h" + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> + +namespace android { +namespace bluetooth { +namespace audio { + +using ::android::hardware::audio::common::V5_0::AudioContentType; +using ::android::hardware::audio::common::V5_0::AudioUsage; +using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata; +using ::android::hardware::audio::common::V5_0::SourceMetadata; +using ::android::hardware::bluetooth::audio::V2_0::CodecType; +using ::android::hardware::bluetooth::audio::V2_0::TimeSpec; + +const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = { + .codecType = CodecType::UNKNOWN, + .encodedAudioBitrate = 0x00000000, + .peerMtu = 0xffff, + .isScmstEnabled = false, + .config = {}}; +AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration = + {}; +AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {}; + +static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending +static constexpr int kWritePollMs = 1; // polled non-blocking interval + +static inline timespec timespec_convert_from_hal(const TimeSpec& TS) { + return {.tv_sec = static_cast<long>(TS.tvSec), + .tv_nsec = static_cast<long>(TS.tvNSec)}; +} + +BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type) + : session_type_(session_type), stack_iface_(nullptr), mDataMQ(nullptr) { + invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters); + invalidOffloadAudioConfiguration.codecConfig(kInvalidCodecConfiguration); +} + +// The report function is used to report that the Bluetooth stack has started +// this session without any failure, and will invoke session_changed_cb_ to +// notify those registered bluetooth_audio outputs +void BluetoothAudioSession::OnSessionStarted( + const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ, + const AudioConfiguration& audio_config) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (stack_iface == nullptr) { + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << ", IBluetoothAudioPort Invalid"; + } else if (!UpdateAudioConfig(audio_config)) { + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << ", AudioConfiguration=" << toString(audio_config) + << " Invalid"; + } else if (!UpdateDataPath(dataMQ)) { + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << " DataMQ Invalid"; + audio_config_ = + (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH + ? kInvalidOffloadAudioConfiguration + : kInvalidSoftwareAudioConfiguration); + } else { + stack_iface_ = stack_iface; + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", AudioConfiguration=" << toString(audio_config); + ReportSessionStatus(); + } +} + +// The report function is used to report that the Bluetooth stack has ended the +// session, and will invoke session_changed_cb_ to notify registered +// bluetooth_audio outputs +void BluetoothAudioSession::OnSessionEnded() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (IsSessionReady()) { + ReportSessionStatus(); + } + audio_config_ = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH + ? kInvalidOffloadAudioConfiguration + : kInvalidSoftwareAudioConfiguration); + stack_iface_ = nullptr; + UpdateDataPath(nullptr); +} + +// invoking the registered session_changed_cb_ +void BluetoothAudioSession::ReportSessionStatus() { + // This is locked already by OnSessionStarted / OnSessionEnded + if (observers_.empty()) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO port state observer"; + return; + } + for (auto& observer : observers_) { + uint16_t cookie = observer.first; + std::shared_ptr<struct PortStatusCallbacks> cb = observer.second; + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " notify to bluetooth_audio=0x" + << android::base::StringPrintf("%04x", cookie); + cb->session_changed_cb_(cookie); + } +} + +// The report function is used to report that the Bluetooth stack has notified +// the result of startStream or suspendStream, and will invoke +// control_result_cb_ to notify registered bluetooth_audio outputs +void BluetoothAudioSession::ReportControlStatus( + bool start_resp, const BluetoothAudioStatus& status) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (observers_.empty()) { + LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO port state observer"; + return; + } + for (auto& observer : observers_) { + uint16_t cookie = observer.first; + std::shared_ptr<struct PortStatusCallbacks> cb = observer.second; + LOG(INFO) << __func__ << " - status=" << toString(status) + << " for SessionType=" << toString(session_type_) + << ", bluetooth_audio=0x" + << android::base::StringPrintf("%04x", cookie) + << (start_resp ? " started" : " suspended"); + cb->control_result_cb_(cookie, start_resp, status); + } +} + +// The function helps to check if this session is ready or not +// @return: true if the Bluetooth stack has started the specified session +bool BluetoothAudioSession::IsSessionReady() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + bool dataMQ_valid = + (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH || + (mDataMQ != nullptr && mDataMQ->isValid())); + return stack_iface_ != nullptr && dataMQ_valid; +} + +bool BluetoothAudioSession::UpdateDataPath(const DataMQ::Descriptor* dataMQ) { + if (dataMQ == nullptr) { + // usecase of reset by nullptr + mDataMQ = nullptr; + return true; + } + std::unique_ptr<DataMQ> tempDataMQ; + tempDataMQ.reset(new DataMQ(*dataMQ)); + if (!tempDataMQ || !tempDataMQ->isValid()) { + mDataMQ = nullptr; + return false; + } + mDataMQ = std::move(tempDataMQ); + return true; +} + +bool BluetoothAudioSession::UpdateAudioConfig( + const AudioConfiguration& audio_config) { + bool is_software_session = + (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH); + bool is_offload_session = + (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH); + auto audio_config_discriminator = audio_config.getDiscriminator(); + bool is_software_audio_config = + (is_software_session && + audio_config_discriminator == + AudioConfiguration::hidl_discriminator::pcmConfig); + bool is_offload_audio_config = + (is_offload_session && + audio_config_discriminator == + AudioConfiguration::hidl_discriminator::codecConfig); + if (!is_software_audio_config && !is_offload_audio_config) { + return false; + } + audio_config_ = audio_config; + return true; +} + +// The control function helps the bluetooth_audio module to register +// PortStatusCallbacks +// @return: cookie - the assigned number to this bluetooth_audio output +uint16_t BluetoothAudioSession::RegisterStatusCback( + const PortStatusCallbacks& cbacks) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + uint16_t cookie = ObserversCookieGetInitValue(session_type_); + uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_); + + while (cookie < cookie_upper_bound) { + if (observers_.find(cookie) == observers_.end()) { + break; + } + ++cookie; + } + if (cookie >= cookie_upper_bound) { + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << " has " << observers_.size() + << " observers already (No Resource)"; + return kObserversCookieUndefined; + } + std::shared_ptr<struct PortStatusCallbacks> cb = + std::make_shared<struct PortStatusCallbacks>(); + *cb = cbacks; + observers_[cookie] = cb; + return cookie; +} + +// The control function helps the bluetooth_audio module to unregister +// PortStatusCallbacks +// @param: cookie - indicates which bluetooth_audio output is +void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (observers_.erase(cookie) != 1) { + LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) + << " no such provider=0x" + << android::base::StringPrintf("%04x", cookie); + } +} + +// The control function is for the bluetooth_audio module to get the current +// AudioConfiguration +const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (IsSessionReady()) { + return audio_config_; + } else if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + return kInvalidOffloadAudioConfiguration; + } else { + return kInvalidSoftwareAudioConfiguration; + } +} + +// Those control functions are for the bluetooth_audio module to start, suspend, +// stop stream, to check position, and to update metadata. +bool BluetoothAudioSession::StartStream() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + auto hal_retval = stack_iface_->startStream(); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + return false; + } + return true; +} + +bool BluetoothAudioSession::SuspendStream() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + auto hal_retval = stack_iface_->suspendStream(); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + return false; + } + return true; +} + +void BluetoothAudioSession::StopStream() { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (!IsSessionReady()) { + return; + } + auto hal_retval = stack_iface_->stopStream(); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + } +} + +bool BluetoothAudioSession::GetPresentationPosition( + uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed, + timespec* data_position) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + bool retval = false; + auto hal_retval = stack_iface_->getPresentationPosition( + [&retval, &remote_delay_report_ns, &total_bytes_readed, &data_position]( + BluetoothAudioStatus status, + const uint64_t& remoteDeviceAudioDelayNanos, + uint64_t transmittedOctets, + const TimeSpec& transmittedOctetsTimeStamp) { + if (status == BluetoothAudioStatus::SUCCESS) { + if (remote_delay_report_ns) + *remote_delay_report_ns = remoteDeviceAudioDelayNanos; + if (total_bytes_readed) *total_bytes_readed = transmittedOctets; + if (data_position) + *data_position = + timespec_convert_from_hal(transmittedOctetsTimeStamp); + retval = true; + } + }); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + return false; + } + return retval; +} + +void BluetoothAudioSession::UpdateTracksMetadata( + const struct source_metadata* source_metadata) { + std::lock_guard<std::recursive_mutex> guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return; + } + + ssize_t track_count = source_metadata->track_count; + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ", " + << track_count << " track(s)"; + if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + return; + } + + struct playback_track_metadata* track = source_metadata->tracks; + SourceMetadata sourceMetadata; + PlaybackTrackMetadata* halMetadata; + + sourceMetadata.tracks.resize(track_count); + halMetadata = sourceMetadata.tracks.data(); + while (track_count && track) { + halMetadata->usage = static_cast<AudioUsage>(track->usage); + halMetadata->contentType = + static_cast<AudioContentType>(track->content_type); + halMetadata->gain = track->gain; + LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_) + << ", usage=" << toString(halMetadata->usage) + << ", content=" << toString(halMetadata->contentType) + << ", gain=" << halMetadata->gain; + --track_count; + ++track; + ++halMetadata; + } + auto hal_retval = stack_iface_->updateMetadata(sourceMetadata); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + } +} + +// The control function writes stream to FMQ +size_t BluetoothAudioSession::OutWritePcmData(const void* buffer, + size_t bytes) { + if (buffer == nullptr || !bytes) return 0; + size_t totalWritten = 0; + int ms_timeout = kFmqSendTimeoutMs; + do { + std::unique_lock<std::recursive_mutex> lock(mutex_); + if (!IsSessionReady()) break; + size_t availableToWrite = mDataMQ->availableToWrite(); + if (availableToWrite) { + if (availableToWrite > (bytes - totalWritten)) { + availableToWrite = bytes - totalWritten; + } + + if (!mDataMQ->write(static_cast<const uint8_t*>(buffer) + totalWritten, + availableToWrite)) { + ALOGE("FMQ datapath writting %zu/%zu failed", totalWritten, bytes); + return totalWritten; + } + totalWritten += availableToWrite; + } else if (ms_timeout >= kWritePollMs) { + lock.unlock(); + usleep(kWritePollMs * 1000); + ms_timeout -= kWritePollMs; + } else { + ALOGD("data %zu/%zu overflow %d ms", totalWritten, bytes, + (kFmqSendTimeoutMs - ms_timeout)); + return totalWritten; + } + } while (totalWritten < bytes); + return totalWritten; +} + +std::unique_ptr<BluetoothAudioSessionInstance> + BluetoothAudioSessionInstance::instance_ptr = + std::unique_ptr<BluetoothAudioSessionInstance>( + new BluetoothAudioSessionInstance()); + +// API to fetch the session of A2DP / Hearing Aid +std::shared_ptr<BluetoothAudioSession> +BluetoothAudioSessionInstance::GetSessionInstance( + const SessionType& session_type) { + std::lock_guard<std::mutex> guard(instance_ptr->mutex_); + if (!instance_ptr->sessions_map_.empty()) { + auto entry = instance_ptr->sessions_map_.find(session_type); + if (entry != instance_ptr->sessions_map_.end()) { + return entry->second; + } + } + std::shared_ptr<BluetoothAudioSession> session_ptr = + std::make_shared<BluetoothAudioSession>(session_type); + instance_ptr->sessions_map_[session_type] = session_ptr; + return session_ptr; +} + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h new file mode 100644 index 0000000000..85e8742d07 --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h @@ -0,0 +1,185 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <mutex> +#include <unordered_map> + +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h> +#include <fmq/MessageQueue.h> +#include <hardware/audio.h> +#include <hidl/MQDescriptor.h> + +namespace android { +namespace bluetooth { +namespace audio { + +using ::android::sp; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample; +using ::android::hardware::bluetooth::audio::V2_0::ChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort; +using ::android::hardware::bluetooth::audio::V2_0::PcmParameters; +using ::android::hardware::bluetooth::audio::V2_0::SampleRate; +using ::android::hardware::bluetooth::audio::V2_0::SessionType; + +using BluetoothAudioStatus = + ::android::hardware::bluetooth::audio::V2_0::Status; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + +static constexpr uint16_t kObserversCookieSize = 0x0010; // 0x0000 ~ 0x000f +constexpr uint16_t kObserversCookieUndefined = + (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00); +inline SessionType ObserversCookieGetSessionType(uint16_t cookie) { + return static_cast<SessionType>(cookie >> 8 & 0x00ff); +} +inline uint16_t ObserversCookieGetInitValue(SessionType session_type) { + return (static_cast<uint16_t>(session_type) << 8 & 0xff00); +} +inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) { + return (static_cast<uint16_t>(session_type) << 8 & 0xff00) + + kObserversCookieSize; +} + +// This presents the callbacks of started / suspended and session changed, +// and the bluetooth_audio module uses to receive the status notification +struct PortStatusCallbacks { + // control_result_cb_ - when the Bluetooth stack reports results of + // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke + // this callback to report to the bluetooth_audio module. + // @param: cookie - indicates which bluetooth_audio output should handle + // @param: start_resp - this report is for startStream or not + // @param: status - the result of startStream + std::function<void(uint16_t cookie, bool start_resp, + const BluetoothAudioStatus& status)> + control_result_cb_; + // session_changed_cb_ - when the Bluetooth stack start / end session, the + // BluetoothAudioProvider will invoke this callback to notify to the + // bluetooth_audio module. + // @param: cookie - indicates which bluetooth_audio output should handle + std::function<void(uint16_t cookie)> session_changed_cb_; +}; + +class BluetoothAudioSession { + private: + // using recursive_mutex to allow hwbinder to re-enter agian. + std::recursive_mutex mutex_; + SessionType session_type_; + + // audio control path to use for both software and offloading + sp<IBluetoothAudioPort> stack_iface_; + // audio data path (FMQ) for software encoding + std::unique_ptr<DataMQ> mDataMQ; + // audio data configuration for both software and offloading + AudioConfiguration audio_config_; + + static AudioConfiguration invalidSoftwareAudioConfiguration; + static AudioConfiguration invalidOffloadAudioConfiguration; + + // saving those registered bluetooth_audio's callbacks + std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>> + observers_; + + bool UpdateDataPath(const DataMQ::Descriptor* dataMQ); + bool UpdateAudioConfig(const AudioConfiguration& audio_config); + // invoking the registered session_changed_cb_ + void ReportSessionStatus(); + + public: + BluetoothAudioSession(const SessionType& session_type); + + // The function helps to check if this session is ready or not + // @return: true if the Bluetooth stack has started the specified session + bool IsSessionReady(); + + // The report function is used to report that the Bluetooth stack has started + // this session without any failure, and will invoke session_changed_cb_ to + // notify those registered bluetooth_audio outputs + void OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface, + const DataMQ::Descriptor* dataMQ, + const AudioConfiguration& audio_config); + + // The report function is used to report that the Bluetooth stack has ended + // the session, and will invoke session_changed_cb_ to notify registered + // bluetooth_audio outputs + void OnSessionEnded(); + + // The report function is used to report that the Bluetooth stack has notified + // the result of startStream or suspendStream, and will invoke + // control_result_cb_ to notify registered bluetooth_audio outputs + void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status); + + // The control function helps the bluetooth_audio module to register + // PortStatusCallbacks + // @return: cookie - the assigned number to this bluetooth_audio output + uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks); + + // The control function helps the bluetooth_audio module to unregister + // PortStatusCallbacks + // @param: cookie - indicates which bluetooth_audio output is + void UnregisterStatusCback(uint16_t cookie); + + // The control function is for the bluetooth_audio module to get the current + // AudioConfiguration + const AudioConfiguration& GetAudioConfig(); + + // Those control functions are for the bluetooth_audio module to start, + // suspend, stop stream, to check position, and to update metadata. + bool StartStream(); + bool SuspendStream(); + void StopStream(); + bool GetPresentationPosition(uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_readed, + timespec* data_position); + void UpdateTracksMetadata(const struct source_metadata* source_metadata); + + // The control function writes stream to FMQ + size_t OutWritePcmData(const void* buffer, size_t bytes); + + static constexpr PcmParameters kInvalidPcmParameters = { + .sampleRate = SampleRate::RATE_UNKNOWN, + .bitsPerSample = BitsPerSample::BITS_UNKNOWN, + .channelMode = ChannelMode::UNKNOWN}; + // can't be constexpr because of non-literal type + static const CodecConfiguration kInvalidCodecConfiguration; + + static constexpr AudioConfiguration& kInvalidSoftwareAudioConfiguration = + invalidSoftwareAudioConfiguration; + static constexpr AudioConfiguration& kInvalidOffloadAudioConfiguration = + invalidOffloadAudioConfiguration; +}; + +class BluetoothAudioSessionInstance { + public: + // The API is to fetch the specified session of A2DP / Hearing Aid + static std::shared_ptr<BluetoothAudioSession> GetSessionInstance( + const SessionType& session_type); + + private: + static std::unique_ptr<BluetoothAudioSessionInstance> instance_ptr; + std::mutex mutex_; + std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>> + sessions_map_; +}; + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h new file mode 100644 index 0000000000..6707765638 --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h @@ -0,0 +1,143 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BluetoothAudioSession.h" + +namespace android { +namespace bluetooth { +namespace audio { + +class BluetoothAudioSessionControl { + public: + // The control API helps to check if session is ready or not + // @return: true if the Bluetooth stack has started th specified session + static bool IsSessionReady(const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->IsSessionReady(); + } + return false; + } + + // The control API helps the bluetooth_audio module to register + // PortStatusCallbacks + // @return: cookie - the assigned number to this bluetooth_audio output + static uint16_t RegisterControlResultCback( + const SessionType& session_type, const PortStatusCallbacks& cbacks) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->RegisterStatusCback(cbacks); + } + return kObserversCookieUndefined; + } + + // The control API helps the bluetooth_audio module to unregister + // PortStatusCallbacks + // @param: cookie - indicates which bluetooth_audio output is + static void UnregisterControlResultCback(const SessionType& session_type, + uint16_t cookie) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->UnregisterStatusCback(cookie); + } + } + + // The control API for the bluetooth_audio module to get current + // AudioConfiguration + static const AudioConfiguration& GetAudioConfig( + const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioConfig(); + } else if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + return BluetoothAudioSession::kInvalidOffloadAudioConfiguration; + } else { + return BluetoothAudioSession::kInvalidSoftwareAudioConfiguration; + } + } + + // Those control APIs for the bluetooth_audio module to start / suspend / stop + // stream, to check position, and to update metadata. + static bool StartStream(const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->StartStream(); + } + return false; + } + + static bool SuspendStream(const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->SuspendStream(); + } + return false; + } + + static void StopStream(const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->StopStream(); + } + } + + static bool GetPresentationPosition(const SessionType& session_type, + uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_readed, + timespec* data_position) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetPresentationPosition( + remote_delay_report_ns, total_bytes_readed, data_position); + } + return false; + } + + static void UpdateTracksMetadata( + const SessionType& session_type, + const struct source_metadata* source_metadata) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->UpdateTracksMetadata(source_metadata); + } + } + + // The control API writes stream to FMQ + static size_t OutWritePcmData(const SessionType& session_type, + const void* buffer, size_t bytes) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->OutWritePcmData(buffer, bytes); + } + return 0; + } +}; + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.h new file mode 100644 index 0000000000..5a83ae2d1f --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.h @@ -0,0 +1,63 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BluetoothAudioSession.h" + +namespace android { +namespace bluetooth { +namespace audio { + +class BluetoothAudioSessionReport { + public: + // The API reports the Bluetooth stack has started the session, and will + // inform registered bluetooth_audio outputs + static void OnSessionStarted(const SessionType& session_type, + const sp<IBluetoothAudioPort> host_iface, + const DataMQ::Descriptor* dataMQ, + const AudioConfiguration& audio_config) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->OnSessionStarted(host_iface, dataMQ, audio_config); + } + } + // The API reports the Bluetooth stack has ended the session, and will + // inform registered bluetooth_audio outputs + static void OnSessionEnded(const SessionType& session_type) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->OnSessionEnded(); + } + } + // The API reports the Bluetooth stack has replied the result of startStream + // or suspendStream, and will inform registered bluetooth_audio outputs + static void ReportControlStatus(const SessionType& session_type, + const bool& start_resp, + const BluetoothAudioStatus& status) { + std::shared_ptr<BluetoothAudioSession> session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->ReportControlStatus(start_resp, status); + } + } +}; + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp new file mode 100644 index 0000000000..292e28b3b2 --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp @@ -0,0 +1,413 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BTAudioProviderSessionCodecsDB" + +#include "BluetoothAudioSupportedCodecsDB.h" + +#include <android-base/logging.h> + +namespace android { +namespace bluetooth { +namespace audio { + +using ::android::hardware::bluetooth::audio::V2_0::AacObjectType; +using ::android::hardware::bluetooth::audio::V2_0::AacParameters; +using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate; +using ::android::hardware::bluetooth::audio::V2_0::AptxParameters; +using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample; +using ::android::hardware::bluetooth::audio::V2_0::ChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::CodecType; +using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::LdacParameters; +using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex; +using ::android::hardware::bluetooth::audio::V2_0::SampleRate; +using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod; +using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength; +using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands; +using ::android::hardware::bluetooth::audio::V2_0::SbcParameters; + +// Default Supported PCM Parameters +static const PcmParameters kDefaultSoftwarePcmCapabilities = { + .sampleRate = static_cast<SampleRate>( + SampleRate::RATE_44100 | SampleRate::RATE_48000 | + SampleRate::RATE_88200 | SampleRate::RATE_96000 | + SampleRate::RATE_16000 | SampleRate::RATE_24000), + .channelMode = + static_cast<ChannelMode>(ChannelMode::MONO | ChannelMode::STEREO), + .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 | + BitsPerSample::BITS_24 | + BitsPerSample::BITS_32)}; + +// Default Supported Codecs +// SBC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(MONO|STEREO) +// all blocks | subbands 8 | Loudness +static const SbcParameters kDefaultOffloadSbcCapability = { + .sampleRate = SampleRate::RATE_44100, + .channelMode = static_cast<SbcChannelMode>(SbcChannelMode::MONO | + SbcChannelMode::JOINT_STEREO), + .blockLength = static_cast<SbcBlockLength>( + SbcBlockLength::BLOCKS_4 | SbcBlockLength::BLOCKS_8 | + SbcBlockLength::BLOCKS_12 | SbcBlockLength::BLOCKS_16), + .numSubbands = SbcNumSubbands::SUBBAND_8, + .allocMethod = SbcAllocMethod::ALLOC_MD_L, + .bitsPerSample = BitsPerSample::BITS_16, + .minBitpool = 2, + .maxBitpool = 53}; + +// AAC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(STEREO) +static const AacParameters kDefaultOffloadAacCapability = { + .objectType = AacObjectType::MPEG2_LC, + .sampleRate = SampleRate::RATE_44100, + .channelMode = ChannelMode::STEREO, + .variableBitRateEnabled = AacVariableBitRate::DISABLED, + .bitsPerSample = BitsPerSample::BITS_16}; + +// LDAC: mSampleRate:(44100|48000|88200|96000), mBitsPerSample:(16|24|32), +// mChannelMode:(DUAL|STEREO) +static const LdacParameters kDefaultOffloadLdacCapability = { + .sampleRate = static_cast<SampleRate>( + SampleRate::RATE_44100 | SampleRate::RATE_48000 | + SampleRate::RATE_88200 | SampleRate::RATE_96000), + .channelMode = static_cast<LdacChannelMode>(LdacChannelMode::DUAL | + LdacChannelMode::STEREO), + .qualityIndex = LdacQualityIndex::QUALITY_HIGH, + .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 | + BitsPerSample::BITS_24 | + BitsPerSample::BITS_32)}; + +// aptX: mSampleRate:(44100|48000), mBitsPerSample:(16), mChannelMode:(STEREO) +static const AptxParameters kDefaultOffloadAptxCapability = { + .sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 | + SampleRate::RATE_48000), + .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), + .bitsPerSample = BitsPerSample::BITS_24, + .channelMode = ChannelMode::STEREO}; + +const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = { + {.codecType = CodecType::SBC, .capabilities = {}}, + {.codecType = CodecType::AAC, .capabilities = {}}, + {.codecType = CodecType::LDAC, .capabilities = {}}, + {.codecType = CodecType::APTX, .capabilities = {}}, + {.codecType = CodecType::APTX_HD, .capabilities = {}}}; + +static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield) { + bool single = false; + uint32_t test_bit = 0x00000001; + while (test_bit <= bitmasks && test_bit <= bitfield) { + if (bitfield & test_bit && bitmasks & test_bit) { + if (single) return false; + single = true; + } + if (test_bit == 0x80000000) break; + test_bit <<= 1; + } + return single; +} + +static bool IsOffloadSbcConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific); +static bool IsOffloadAacConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific); +static bool IsOffloadLdacConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific); +static bool IsOffloadAptxConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific); +static bool IsOffloadAptxHdConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific); + +static bool IsOffloadSbcConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific) { + if (codec_specific.getDiscriminator() != + CodecConfiguration::CodecSpecific::hidl_discriminator::sbcConfig) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } + const SbcParameters sbc_data = codec_specific.sbcConfig(); + if (!IsSingleBit(static_cast<uint32_t>(sbc_data.sampleRate), 0xff) || + !IsSingleBit(static_cast<uint32_t>(sbc_data.channelMode), 0x0f) || + !IsSingleBit(static_cast<uint32_t>(sbc_data.blockLength), 0xf0) || + !IsSingleBit(static_cast<uint32_t>(sbc_data.numSubbands), 0x0c) || + !IsSingleBit(static_cast<uint32_t>(sbc_data.allocMethod), 0x03) || + !IsSingleBit(static_cast<uint32_t>(sbc_data.bitsPerSample), 0x07) || + sbc_data.minBitpool > sbc_data.maxBitpool) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } else if ((sbc_data.sampleRate & kDefaultOffloadSbcCapability.sampleRate) && + (sbc_data.channelMode & + kDefaultOffloadSbcCapability.channelMode) && + (sbc_data.blockLength & + kDefaultOffloadSbcCapability.blockLength) && + (sbc_data.numSubbands & + kDefaultOffloadSbcCapability.numSubbands) && + (sbc_data.allocMethod & + kDefaultOffloadSbcCapability.allocMethod) && + (sbc_data.bitsPerSample & + kDefaultOffloadSbcCapability.bitsPerSample) && + (kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool && + sbc_data.maxBitpool <= kDefaultOffloadSbcCapability.maxBitpool)) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported CodecSpecific=" << toString(codec_specific); + return false; +} + +static bool IsOffloadAacConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific) { + if (codec_specific.getDiscriminator() != + CodecConfiguration::CodecSpecific::hidl_discriminator::aacConfig) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } + const AacParameters aac_data = codec_specific.aacConfig(); + if (!IsSingleBit(static_cast<uint32_t>(aac_data.objectType), 0xf0) || + !IsSingleBit(static_cast<uint32_t>(aac_data.sampleRate), 0xff) || + !IsSingleBit(static_cast<uint32_t>(aac_data.channelMode), 0x03) || + !IsSingleBit(static_cast<uint32_t>(aac_data.bitsPerSample), 0x07)) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } else if ((aac_data.objectType & kDefaultOffloadAacCapability.objectType) && + (aac_data.sampleRate & kDefaultOffloadAacCapability.sampleRate) && + (aac_data.channelMode & + kDefaultOffloadAacCapability.channelMode) && + (aac_data.variableBitRateEnabled == AacVariableBitRate::DISABLED || + kDefaultOffloadAacCapability.variableBitRateEnabled == + AacVariableBitRate::ENABLED) && + (aac_data.bitsPerSample & + kDefaultOffloadAacCapability.bitsPerSample)) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported CodecSpecific=" << toString(codec_specific); + return false; +} + +static bool IsOffloadLdacConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific) { + if (codec_specific.getDiscriminator() != + CodecConfiguration::CodecSpecific::hidl_discriminator::ldacConfig) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } + const LdacParameters ldac_data = codec_specific.ldacConfig(); + if (!IsSingleBit(static_cast<uint32_t>(ldac_data.sampleRate), 0xff) || + !IsSingleBit(static_cast<uint32_t>(ldac_data.channelMode), 0x07) || + (ldac_data.qualityIndex > LdacQualityIndex::QUALITY_LOW && + ldac_data.qualityIndex != LdacQualityIndex::QUALITY_ABR) || + !IsSingleBit(static_cast<uint32_t>(ldac_data.bitsPerSample), 0x07)) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } else if ((ldac_data.sampleRate & + kDefaultOffloadLdacCapability.sampleRate) && + (ldac_data.channelMode & + kDefaultOffloadLdacCapability.channelMode) && + (ldac_data.bitsPerSample & + kDefaultOffloadLdacCapability.bitsPerSample)) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported CodecSpecific=" << toString(codec_specific); + return false; +} + +static bool IsOffloadAptxConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific) { + if (codec_specific.getDiscriminator() != + CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } + const AptxParameters aptx_data = codec_specific.aptxConfig(); + if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) || + !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) || + !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } else if ((aptx_data.sampleRate & + kDefaultOffloadAptxCapability.sampleRate) && + (aptx_data.channelMode & + kDefaultOffloadAptxCapability.channelMode) && + (aptx_data.bitsPerSample & + kDefaultOffloadAptxCapability.bitsPerSample)) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported CodecSpecific=" << toString(codec_specific); + return false; +} + +static bool IsOffloadAptxHdConfigurationValid( + const CodecConfiguration::CodecSpecific& codec_specific) { + if (codec_specific.getDiscriminator() != + CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } + const AptxParameters aptx_data = codec_specific.aptxConfig(); + if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) || + !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) || + !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) { + LOG(WARNING) << __func__ + << ": Invalid CodecSpecific=" << toString(codec_specific); + return false; + } else if ((aptx_data.sampleRate & + kDefaultOffloadAptxHdCapability.sampleRate) && + (aptx_data.channelMode & + kDefaultOffloadAptxHdCapability.channelMode) && + (aptx_data.bitsPerSample & + kDefaultOffloadAptxHdCapability.bitsPerSample)) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported CodecSpecific=" << toString(codec_specific); + return false; +} + +std::vector<PcmParameters> GetSoftwarePcmCapabilities() { + return std::vector<PcmParameters>(1, kDefaultSoftwarePcmCapabilities); +} + +std::vector<CodecCapabilities> GetOffloadCodecCapabilities( + const SessionType& session_type) { + if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + return std::vector<CodecCapabilities>(0); + } + std::vector<CodecCapabilities> offload_a2dp_codec_capabilities = + kDefaultOffloadA2dpCodecCapabilities; + for (auto& codec_capability : offload_a2dp_codec_capabilities) { + switch (codec_capability.codecType) { + case CodecType::SBC: + codec_capability.capabilities.sbcCapabilities( + kDefaultOffloadSbcCapability); + break; + case CodecType::AAC: + codec_capability.capabilities.aacCapabilities( + kDefaultOffloadAacCapability); + break; + case CodecType::LDAC: + codec_capability.capabilities.ldacCapabilities( + kDefaultOffloadLdacCapability); + break; + case CodecType::APTX: + codec_capability.capabilities.aptxCapabilities( + kDefaultOffloadAptxCapability); + break; + case CodecType::APTX_HD: + codec_capability.capabilities.aptxCapabilities( + kDefaultOffloadAptxHdCapability); + break; + case CodecType::UNKNOWN: + codec_capability = {}; + break; + } + } + return offload_a2dp_codec_capabilities; +} + +bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config) { + if ((pcm_config.sampleRate != SampleRate::RATE_44100 && + pcm_config.sampleRate != SampleRate::RATE_48000 && + pcm_config.sampleRate != SampleRate::RATE_88200 && + pcm_config.sampleRate != SampleRate::RATE_96000 && + pcm_config.sampleRate != SampleRate::RATE_16000 && + pcm_config.sampleRate != SampleRate::RATE_24000) || + (pcm_config.bitsPerSample != BitsPerSample::BITS_16 && + pcm_config.bitsPerSample != BitsPerSample::BITS_24 && + pcm_config.bitsPerSample != BitsPerSample::BITS_32) || + (pcm_config.channelMode != ChannelMode::MONO && + pcm_config.channelMode != ChannelMode::STEREO)) { + LOG(WARNING) << __func__ + << ": Invalid PCM Configuration=" << toString(pcm_config); + return false; + } else if (pcm_config.sampleRate & + kDefaultSoftwarePcmCapabilities.sampleRate && + pcm_config.bitsPerSample & + kDefaultSoftwarePcmCapabilities.bitsPerSample && + pcm_config.channelMode & + kDefaultSoftwarePcmCapabilities.channelMode) { + return true; + } + LOG(WARNING) << __func__ + << ": Unsupported PCM Configuration=" << toString(pcm_config); + return false; +} + +bool IsOffloadCodecConfigurationValid(const SessionType& session_type, + const CodecConfiguration& codec_config) { + if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + LOG(ERROR) << __func__ + << ": Invalid SessionType=" << toString(session_type); + return false; + } else if (codec_config.encodedAudioBitrate < 0x00000001 || + 0x00ffffff < codec_config.encodedAudioBitrate) { + LOG(ERROR) << __func__ << ": Unsupported Codec Configuration=" + << toString(codec_config); + return false; + } + const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config; + switch (codec_config.codecType) { + case CodecType::SBC: + if (IsOffloadSbcConfigurationValid(codec_specific)) { + return true; + } + return false; + case CodecType::AAC: + if (IsOffloadAacConfigurationValid(codec_specific)) { + return true; + } + return false; + case CodecType::LDAC: + if (IsOffloadLdacConfigurationValid(codec_specific)) { + return true; + } + return false; + case CodecType::APTX: + if (IsOffloadAptxConfigurationValid(codec_specific)) { + return true; + } + return false; + case CodecType::APTX_HD: + if (IsOffloadAptxHdConfigurationValid(codec_specific)) { + return true; + } + return false; + case CodecType::UNKNOWN: + return false; + } + return false; +} + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h new file mode 100644 index 0000000000..e71dc8a183 --- /dev/null +++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/hardware/bluetooth/audio/2.0/types.h> + +namespace android { +namespace bluetooth { +namespace audio { + +using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities; +using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::PcmParameters; +using ::android::hardware::bluetooth::audio::V2_0::SessionType; + +std::vector<PcmParameters> GetSoftwarePcmCapabilities(); +std::vector<CodecCapabilities> GetOffloadCodecCapabilities( + const SessionType& session_type); + +bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config); +bool IsOffloadCodecConfigurationValid(const SessionType& session_type, + const CodecConfiguration& codec_config); + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/2.0/types.hal b/bluetooth/audio/2.0/types.hal index 928694866a..909dd573f9 100644 --- a/bluetooth/audio/2.0/types.hal +++ b/bluetooth/audio/2.0/types.hal @@ -17,6 +17,14 @@ package android.hardware.bluetooth.audio@2.0; /** + * The different audio parameter structs are used to provide a method to list + * all the Capabilities of a codec as well as to configure the codecs. All + * fields are bitfields unless specified. If used as a configuration, only one + * bit may be enabled. If used for Capabilities, enable all bits corresponding to + * supported features. + */ + +/** * POSIX timespec. */ struct TimeSpec { @@ -85,6 +93,25 @@ enum SbcChannelMode : uint8_t { MONO = 0x08, }; +enum SbcBlockLength : uint8_t { + BLOCKS_4 = 0x80, + BLOCKS_8 = 0x40, + BLOCKS_12 = 0x20, + BLOCKS_16 = 0x10, +}; + +enum SbcNumSubbands : uint8_t { + SUBBAND_4 = 0x08, + SUBBAND_8 = 0x04, +}; + +enum SbcAllocMethod : uint8_t { + /** SNR */ + ALLOC_MD_S = 0x02, + /** Loudness */ + ALLOC_MD_L = 0x01, +}; + enum AacObjectType : uint8_t { /** MPEG-2 Low Complexity. Support is Mandatory. */ MPEG2_LC = 0x80, @@ -96,6 +123,11 @@ enum AacObjectType : uint8_t { MPEG4_SCALABLE = 0x10, }; +enum AacVariableBitRate : uint8_t { + ENABLED = 0x80, + DISABLED = 0x00, +}; + enum LdacChannelMode : uint8_t { /** Channel Mode: 3 bits */ UNKNOWN = 0x00, @@ -104,67 +136,117 @@ enum LdacChannelMode : uint8_t { MONO = 0x04, }; +enum LdacQualityIndex : uint8_t { + // 990kbps + QUALITY_HIGH = 0x00, + // 660kbps + QUALITY_MID = 0x01, + // 330kbps + QUALITY_LOW = 0x02, + // Adaptive Bit Rate mode + QUALITY_ABR = 0x7F, +}; + +/** Used for Software Encoding audio feed parameters */ +struct PcmParameters { + SampleRate sampleRate; + ChannelMode channelMode; + BitsPerSample bitsPerSample; +}; + +/** + * Used for Hardware Encoding SBC codec parameters. + * minBitpool and maxBitpool are not bitfields. + */ +struct SbcParameters { + SampleRate sampleRate; + SbcChannelMode channelMode; + SbcBlockLength blockLength; + SbcNumSubbands numSubbands; + SbcAllocMethod allocMethod; + BitsPerSample bitsPerSample; + uint8_t minBitpool; + uint8_t maxBitpool; +}; + +/** Used for Hardware Encoding AAC codec parameters */ +struct AacParameters { + AacObjectType objectType; + SampleRate sampleRate; + ChannelMode channelMode; + AacVariableBitRate variableBitRateEnabled; + BitsPerSample bitsPerSample; +}; + +/** + * Used for Hardware Encoding LDAC codec parameters + * Only used when configuring the codec. When Capabilities are requested, this + * field is left empty since all qualities must be supported. Not a bitfield. + */ +struct LdacParameters { + SampleRate sampleRate; + LdacChannelMode channelMode; + LdacQualityIndex qualityIndex; + BitsPerSample bitsPerSample; +}; + +/** Used for Hardware Encoding AptX and AptX-HD codec parameters */ +struct AptxParameters { + SampleRate sampleRate; + ChannelMode channelMode; + BitsPerSample bitsPerSample; +}; + +/** + * Used to specify the capabilities of the codecs supported by Hardware Encoding. + * AptX and AptX-HD both use the AptxParameters field. + */ +struct CodecCapabilities { + CodecType codecType; + + safe_union Capabilities { + SbcParameters sbcCapabilities; + AacParameters aacCapabilities; + LdacParameters ldacCapabilities; + AptxParameters aptxCapabilities; + } capabilities; +}; + +/** Used to specify the capabilities of the different session types. */ +safe_union AudioCapabilities { + PcmParameters pcmCapabilities; + CodecCapabilities codecCapabilities; +}; + +/** + * Used to configure a Hardware Encoding session. + * AptX and AptX-HD both use the AptxParameters field. + */ struct CodecConfiguration { - /** Audio PCM data configuration */ - struct PcmDataConfiguration { - /** Sampling rate for encoder */ - SampleRate sampleRate; - /** Bits per sample for encoder */ - BitsPerSample bitsPerSample; - /** Channel mode for encoder */ - ChannelMode channelMode; - } pcmDataConfiguration; - - /** Encoded audio data codec configuration. It is used only if the - * HAL is responsible for encoding the PCM audio data. */ - struct EncodedDataConfiguration { - /** Bluetooth A2DP codec */ - CodecType codecType; - /** - * The encoded audio bitrate in bits / second. - * 0x00000000 - The audio bitrate is not specified / unused - * 0x00000001 - 0x00FFFFFF - Encoded audio bitrate in bits/second - * 0x01000000 - 0xFFFFFFFF - Reserved - */ - uint32_t encodedAudioBitrate; - /** Peer MTU (in octets) */ - uint16_t peerMtu; - /** Content protection by SCMS-T */ - bool isScmstEnabled; - safe_union CodecSpecific { - /** - * SBC Codec specific information - * Refer to SBC Codec specific information elements in A2DP v1.3 - * Profile Specification. - */ - struct SbcData { - /** Reserved: 4 bits | Channel Mode: 4 bits */ - SbcChannelMode channelMode; - /** Block length: 4 bits | Subbands: 2 bits | Allocation Method: 2 bits */ - uint8_t codecParameters; - /** Minimum bitpool value */ - uint8_t minBitpool; - /** Maximum bitpool value */ - uint8_t maxBitpool; - } sbcData; - struct AacData { - /** AAC Object Type */ - AacObjectType aacObjectType; - /** True if Variable Bit Rate is enabled */ - bool variableBitRateEnabled; - } aacData; - struct LdacData { - /** Reserved: 5 bits | Channel Mode: 3 bits */ - LdacChannelMode channelMode; - /** - * LDAC bitrate index value: - * 0x00 - High - * 0x01 - Mid - * 0x02 - Low - * 0x7F - ABR (Adaptive Bit Rate) - */ - uint8_t bitrateIndex; - } ldacData; - } codecSpecific; - } encodedDataConfiguration; + CodecType codecType; + /** + * The encoded audio bitrate in bits / second. + * 0x00000000 - The audio bitrate is not specified / unused + * 0x00000001 - 0x00FFFFFF - Encoded audio bitrate in bits/second + * 0x01000000 - 0xFFFFFFFF - Reserved + * + * The HAL needs to support all legal bitrates for the selected codec. + */ + uint32_t encodedAudioBitrate; + /** Peer MTU (in octets) */ + uint16_t peerMtu; + /** Content protection by SCMS-T */ + bool isScmstEnabled; + safe_union CodecSpecific { + SbcParameters sbcConfig; + AacParameters aacConfig; + LdacParameters ldacConfig; + AptxParameters aptxConfig; + } config; +}; + +/** Used to configure either a Hardware or Software Encoding session based on session type */ +safe_union AudioConfiguration { + PcmParameters pcmConfig; + CodecConfiguration codecConfig; }; diff --git a/bluetooth/audio/2.0/vts/OWNERS b/bluetooth/audio/2.0/vts/OWNERS new file mode 100644 index 0000000000..b6c0813977 --- /dev/null +++ b/bluetooth/audio/2.0/vts/OWNERS @@ -0,0 +1,3 @@ +include platform/system/bt:/OWNERS + +cheneyni@google.com diff --git a/bluetooth/audio/2.0/vts/functional/Android.bp b/bluetooth/audio/2.0/vts/functional/Android.bp new file mode 100644 index 0000000000..b672fe4970 --- /dev/null +++ b/bluetooth/audio/2.0/vts/functional/Android.bp @@ -0,0 +1,12 @@ +cc_test { + name: "VtsHalBluetoothAudioV2_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBluetoothAudioV2_0TargetTest.cpp"], + static_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.bluetooth.audio@2.0", + ], + shared_libs: [ + "libfmq", + ], +} diff --git a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp new file mode 100644 index 0000000000..9572d3f47b --- /dev/null +++ b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp @@ -0,0 +1,915 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "bluetooth_audio_hidl_hal_test" + +#include <android-base/logging.h> +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h> +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h> +#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h> +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> +#include <utils/Log.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::V5_0::SourceMetadata; +using ::android::hardware::bluetooth::audio::V2_0::AacObjectType; +using ::android::hardware::bluetooth::audio::V2_0::AacParameters; +using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate; +using ::android::hardware::bluetooth::audio::V2_0::AptxParameters; +using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities; +using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample; +using ::android::hardware::bluetooth::audio::V2_0::ChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities; +using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration; +using ::android::hardware::bluetooth::audio::V2_0::CodecType; +using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort; +using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider; +using ::android::hardware::bluetooth::audio::V2_0:: + IBluetoothAudioProvidersFactory; +using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::LdacParameters; +using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex; +using ::android::hardware::bluetooth::audio::V2_0::PcmParameters; +using ::android::hardware::bluetooth::audio::V2_0::SampleRate; +using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod; +using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength; +using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode; +using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands; +using ::android::hardware::bluetooth::audio::V2_0::SbcParameters; +using ::android::hardware::bluetooth::audio::V2_0::SessionType; + +using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; +using BluetoothAudioStatus = + ::android::hardware::bluetooth::audio::V2_0::Status; +using CodecSpecificConfig = ::android::hardware::bluetooth::audio::V2_0:: + CodecConfiguration::CodecSpecific; + +namespace { +constexpr SampleRate a2dp_sample_rates[5] = { + SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000, + SampleRate::RATE_88200, SampleRate::RATE_96000}; +constexpr BitsPerSample a2dp_bits_per_samples[4] = { + BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24, + BitsPerSample::BITS_32}; +constexpr ChannelMode a2dp_channel_modes[3] = { + ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO}; +constexpr CodecType a2dp_codec_types[6] = {CodecType::UNKNOWN, CodecType::SBC, + CodecType::AAC, CodecType::APTX, + CodecType::APTX_HD, CodecType::LDAC}; + +template <typename T> +std::vector<T> ExtractValuesFromBitmask(T bitmasks, uint32_t bitfield, + bool supported) { + std::vector<T> retval; + if (!supported) { + retval.push_back(static_cast<T>(bitfield)); + } + uint32_t test_bit = 0x00000001; + while (test_bit <= static_cast<uint32_t>(bitmasks) && test_bit <= bitfield) { + if ((bitfield & test_bit)) { + if ((!(bitmasks & test_bit) && !supported) || + ((bitmasks & test_bit) && supported)) { + retval.push_back(static_cast<T>(test_bit)); + } + } + if (test_bit == 0x80000000) { + break; + } + test_bit <<= 1; + } + return retval; +} +} // namespace + +// Test environment for Bluetooth Audio HAL. +class BluetoothAudioHidlEnvironment + : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static BluetoothAudioHidlEnvironment* Instance() { + static BluetoothAudioHidlEnvironment* instance = + new BluetoothAudioHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { + registerTestService<IBluetoothAudioProvidersFactory>(); + } + + private: + BluetoothAudioHidlEnvironment() {} +}; + +// The base test class for Bluetooth Audio HAL. +class BluetoothAudioProvidersFactoryHidlTest + : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + providers_factory_ = ::testing::VtsHalHidlTargetTestBase::getService< + IBluetoothAudioProvidersFactory>( + BluetoothAudioHidlEnvironment::Instance() + ->getServiceName<IBluetoothAudioProvidersFactory>()); + ASSERT_NE(providers_factory_, nullptr); + } + + virtual void TearDown() override { providers_factory_ = nullptr; } + + // A simple test implementation of IBluetoothAudioPort. + class BluetoothAudioPort : public ::testing::VtsHalHidlTargetCallbackBase< + BluetoothAudioProvidersFactoryHidlTest>, + public IBluetoothAudioPort { + BluetoothAudioProvidersFactoryHidlTest& parent_; + + public: + BluetoothAudioPort(BluetoothAudioProvidersFactoryHidlTest& parent) + : parent_(parent) {} + virtual ~BluetoothAudioPort() = default; + + Return<void> startStream() override { + parent_.audio_provider_->streamStarted(BluetoothAudioStatus::SUCCESS); + return Void(); + } + + Return<void> suspendStream() override { + parent_.audio_provider_->streamSuspended(BluetoothAudioStatus::SUCCESS); + return Void(); + } + + Return<void> stopStream() override { return Void(); } + + Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) { + _hidl_cb(BluetoothAudioStatus::SUCCESS, 0, 0, {.tvSec = 0, .tvNSec = 0}); + return Void(); + } + + Return<void> updateMetadata(const SourceMetadata& sourceMetadata __unused) { + return Void(); + } + }; + + void GetProviderCapabilitiesHelper(const SessionType& session_type) { + temp_provider_capabilities_.clear(); + auto hidl_cb = [& temp_capabilities = this->temp_provider_capabilities_]( + const hidl_vec<AudioCapabilities>& audioCapabilities) { + for (auto audioCapability : audioCapabilities) + temp_capabilities.push_back(audioCapability); + }; + auto hidl_retval = + providers_factory_->getProviderCapabilities(session_type, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + if (session_type == SessionType::UNKNOWN) { + ASSERT_TRUE(temp_provider_capabilities_.empty()); + } else if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + // All software paths are mandatory and must have exact 1 "PcmParameters" + ASSERT_EQ(temp_provider_capabilities_.size(), 1); + ASSERT_EQ(temp_provider_capabilities_[0].getDiscriminator(), + AudioCapabilities::hidl_discriminator::pcmCapabilities); + } else { + uint32_t codec_type_bitmask = 0x00000000; + // empty capability means offload is unsupported + for (auto audio_capability : temp_provider_capabilities_) { + ASSERT_EQ(audio_capability.getDiscriminator(), + AudioCapabilities::hidl_discriminator::codecCapabilities); + const CodecCapabilities& codec_capabilities = + audio_capability.codecCapabilities(); + // Every codec can present once at most + ASSERT_EQ(codec_type_bitmask & + static_cast<uint32_t>(codec_capabilities.codecType), + 0); + switch (codec_capabilities.codecType) { + case CodecType::SBC: + ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(), + CodecCapabilities::Capabilities::hidl_discriminator:: + sbcCapabilities); + break; + case CodecType::AAC: + ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(), + CodecCapabilities::Capabilities::hidl_discriminator:: + aacCapabilities); + break; + case CodecType::APTX: + FALLTHROUGH_INTENDED; + case CodecType::APTX_HD: + ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(), + CodecCapabilities::Capabilities::hidl_discriminator:: + aptxCapabilities); + break; + case CodecType::LDAC: + ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(), + CodecCapabilities::Capabilities::hidl_discriminator:: + ldacCapabilities); + break; + case CodecType::UNKNOWN: + break; + } + codec_type_bitmask |= codec_capabilities.codecType; + } + } + } + + // This helps to open the specified provider and check the openProvider() + // has corruct return values. BUT, to keep it simple, it does not consider + // the capability, and please do so at the SetUp of each session's test. + void OpenProviderHelper(const SessionType& session_type) { + BluetoothAudioStatus cb_status; + auto hidl_cb = [&cb_status, &local_provider = this->audio_provider_]( + BluetoothAudioStatus status, + const sp<IBluetoothAudioProvider>& provider) { + cb_status = status; + local_provider = provider; + }; + auto hidl_retval = providers_factory_->openProvider(session_type, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + if (cb_status == BluetoothAudioStatus::SUCCESS) { + ASSERT_NE(session_type, SessionType::UNKNOWN); + ASSERT_NE(audio_provider_, nullptr); + audio_port_ = new BluetoothAudioPort(*this); + } else { + // A2DP_HARDWARE_OFFLOAD_DATAPATH is optional + ASSERT_TRUE(session_type == SessionType::UNKNOWN || + session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH); + ASSERT_EQ(cb_status, BluetoothAudioStatus::FAILURE); + ASSERT_EQ(audio_provider_, nullptr); + } + } + + bool IsPcmParametersSupported(const PcmParameters& pcm_parameters) { + if (temp_provider_capabilities_.size() != 1 || + temp_provider_capabilities_[0].getDiscriminator() != + AudioCapabilities::hidl_discriminator::pcmCapabilities) { + return false; + } + auto pcm_capability = temp_provider_capabilities_[0].pcmCapabilities(); + bool is_parameter_valid = + (pcm_parameters.sampleRate != SampleRate::RATE_UNKNOWN && + pcm_parameters.channelMode != ChannelMode::UNKNOWN && + pcm_parameters.bitsPerSample != BitsPerSample::BITS_UNKNOWN); + bool is_parameter_in_capability = + (pcm_capability.sampleRate & pcm_parameters.sampleRate && + pcm_capability.channelMode & pcm_parameters.channelMode && + pcm_capability.bitsPerSample & pcm_parameters.bitsPerSample); + return is_parameter_valid && is_parameter_in_capability; + } + + sp<IBluetoothAudioProvidersFactory> providers_factory_; + + // temp storage saves the specified provider capability by + // GetProviderCapabilitiesHelper() + std::vector<AudioCapabilities> temp_provider_capabilities_; + + // audio_provider_ is for the Bluetooth stack to report session started/ended + // and handled audio stream started / suspended + sp<IBluetoothAudioProvider> audio_provider_; + + // audio_port_ is for the Audio HAL to send stream start/suspend/stop commands + // to Bluetooth stack + sp<IBluetoothAudioPort> audio_port_; + + static constexpr SessionType session_types_[4] = { + SessionType::UNKNOWN, SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH, + SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH, + SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH}; +}; + +/** + * Test whether we can get the FactoryService from HIDL + */ +TEST_F(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {} + +/** + * Test whether we can open a provider for each provider returned by + * getProviderCapabilities() with non-empty capabalities + */ +TEST_F(BluetoothAudioProvidersFactoryHidlTest, + OpenProviderAndCheckCapabilitiesBySession) { + for (auto session_type : session_types_) { + GetProviderCapabilitiesHelper(session_type); + OpenProviderHelper(session_type); + // We must be able to open a provider if its getProviderCapabilities() + // returns non-empty list. + EXPECT_TRUE(temp_provider_capabilities_.empty() || + audio_provider_ != nullptr); + } +} + +/** + * openProvider A2DP_SOFTWARE_ENCODING_DATAPATH + */ +class BluetoothAudioProviderA2dpSoftwareHidlTest + : public BluetoothAudioProvidersFactoryHidlTest { + public: + virtual void SetUp() override { + BluetoothAudioProvidersFactoryHidlTest::SetUp(); + GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH); + OpenProviderHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH); + ASSERT_NE(audio_provider_, nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProvidersFactoryHidlTest::TearDown(); + } +}; + +/** + * Test whether we can open a provider of type + */ +TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {} + +/** + * Test whether each provider of type + * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with + * different PCM config + */ +TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, + StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) { + bool is_codec_config_valid; + std::unique_ptr<DataMQ> tempDataMQ; + auto hidl_cb = [&is_codec_config_valid, &tempDataMQ]( + BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + if (is_codec_config_valid) { + ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS); + ASSERT_TRUE(dataMQ.isHandleValid()); + tempDataMQ.reset(new DataMQ(dataMQ)); + } else { + EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION); + EXPECT_FALSE(dataMQ.isHandleValid()); + } + }; + AudioConfiguration audio_config = {}; + PcmParameters pcm_parameters = {}; + for (auto sample_rate : a2dp_sample_rates) { + pcm_parameters.sampleRate = sample_rate; + for (auto bits_per_sample : a2dp_bits_per_samples) { + pcm_parameters.bitsPerSample = bits_per_sample; + for (auto channel_mode : a2dp_channel_modes) { + pcm_parameters.channelMode = channel_mode; + is_codec_config_valid = IsPcmParametersSupported(pcm_parameters); + audio_config.pcmConfig(pcm_parameters); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + if (is_codec_config_valid) { + EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid()); + } + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } // ChannelMode + } // BitsPerSampple + } // SampleRate +} + +/** + * openProvider A2DP_HARDWARE_OFFLOAD_DATAPATH + */ +class BluetoothAudioProviderA2dpHardwareHidlTest + : public BluetoothAudioProvidersFactoryHidlTest { + public: + virtual void SetUp() override { + BluetoothAudioProvidersFactoryHidlTest::SetUp(); + GetProviderCapabilitiesHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH); + OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH); + ASSERT_TRUE(temp_provider_capabilities_.empty() || + audio_provider_ != nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProvidersFactoryHidlTest::TearDown(); + } + + bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); } + + void GetOffloadCodecCapabilityHelper(const CodecType& codec_type) { + temp_codec_capabilities_ = {}; + for (auto codec_capability : temp_provider_capabilities_) { + if (codec_capability.codecCapabilities().codecType != codec_type) { + continue; + } + temp_codec_capabilities_ = codec_capability.codecCapabilities(); + } + } + + std::vector<CodecSpecificConfig> GetSbcCodecSpecificSupportedList( + bool supported) { + std::vector<CodecSpecificConfig> sbc_codec_specifics; + GetOffloadCodecCapabilityHelper(CodecType::SBC); + if (temp_codec_capabilities_.codecType != CodecType::SBC) { + return sbc_codec_specifics; + } + // parse the capability + SbcParameters sbc_capability = + temp_codec_capabilities_.capabilities.sbcCapabilities(); + if (sbc_capability.minBitpool > sbc_capability.maxBitpool) { + return sbc_codec_specifics; + } + std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>( + sbc_capability.sampleRate, 0xff, supported); + std::vector<SbcChannelMode> channel_modes = + ExtractValuesFromBitmask<SbcChannelMode>(sbc_capability.channelMode, + 0x0f, supported); + std::vector<SbcBlockLength> block_lengths = + ExtractValuesFromBitmask<SbcBlockLength>(sbc_capability.blockLength, + 0xf0, supported); + std::vector<SbcNumSubbands> num_subbandss = + ExtractValuesFromBitmask<SbcNumSubbands>(sbc_capability.numSubbands, + 0x0c, supported); + std::vector<SbcAllocMethod> alloc_methods = + ExtractValuesFromBitmask<SbcAllocMethod>(sbc_capability.allocMethod, + 0x03, supported); + std::vector<BitsPerSample> bits_per_samples = + ExtractValuesFromBitmask<BitsPerSample>(sbc_capability.bitsPerSample, + 0x07, supported); + // combine those parameters into one list of + // CodecConfiguration::CodecSpecific + CodecSpecificConfig codec_specific = {}; + SbcParameters sbc_data; + for (auto sample_rate : sample_rates) { + for (auto channel_mode : channel_modes) { + for (auto block_length : block_lengths) { + for (auto num_subbands : num_subbandss) { + for (auto alloc_method : alloc_methods) { + for (auto bits_per_sample : bits_per_samples) { + sbc_data = {.sampleRate = sample_rate, + .channelMode = channel_mode, + .blockLength = block_length, + .numSubbands = num_subbands, + .allocMethod = alloc_method, + .bitsPerSample = bits_per_sample, + .minBitpool = sbc_capability.minBitpool, + .maxBitpool = sbc_capability.maxBitpool}; + codec_specific.sbcConfig(sbc_data); + sbc_codec_specifics.push_back(codec_specific); + } + } + } + } + } + } + return sbc_codec_specifics; + } + + std::vector<CodecSpecificConfig> GetAacCodecSpecificSupportedList( + bool supported) { + std::vector<CodecSpecificConfig> aac_codec_specifics; + GetOffloadCodecCapabilityHelper(CodecType::AAC); + if (temp_codec_capabilities_.codecType != CodecType::AAC) { + return aac_codec_specifics; + } + // parse the capability + AacParameters aac_capability = + temp_codec_capabilities_.capabilities.aacCapabilities(); + std::vector<AacObjectType> object_types = + ExtractValuesFromBitmask<AacObjectType>(aac_capability.objectType, 0xf0, + supported); + std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>( + aac_capability.sampleRate, 0xff, supported); + std::vector<ChannelMode> channel_modes = + ExtractValuesFromBitmask<ChannelMode>(aac_capability.channelMode, 0x03, + supported); + std::vector<AacVariableBitRate> variable_bit_rate_enableds = { + AacVariableBitRate::DISABLED}; + if (aac_capability.variableBitRateEnabled == AacVariableBitRate::ENABLED) { + variable_bit_rate_enableds.push_back(AacVariableBitRate::ENABLED); + } + std::vector<BitsPerSample> bits_per_samples = + ExtractValuesFromBitmask<BitsPerSample>(aac_capability.bitsPerSample, + 0x07, supported); + // combine those parameters into one list of + // CodecConfiguration::CodecSpecific + CodecSpecificConfig codec_specific = {}; + AacParameters aac_data; + for (auto object_type : object_types) { + for (auto sample_rate : sample_rates) { + for (auto channel_mode : channel_modes) { + for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) { + for (auto bits_per_sample : bits_per_samples) { + aac_data = {.objectType = object_type, + .sampleRate = sample_rate, + .channelMode = channel_mode, + .variableBitRateEnabled = variable_bit_rate_enabled, + .bitsPerSample = bits_per_sample}; + codec_specific.aacConfig(aac_data); + aac_codec_specifics.push_back(codec_specific); + } + } + } + } + } + return aac_codec_specifics; + } + + std::vector<CodecSpecificConfig> GetLdacCodecSpecificSupportedList( + bool supported) { + std::vector<CodecSpecificConfig> ldac_codec_specifics; + GetOffloadCodecCapabilityHelper(CodecType::LDAC); + if (temp_codec_capabilities_.codecType != CodecType::LDAC) { + return ldac_codec_specifics; + } + // parse the capability + LdacParameters ldac_capability = + temp_codec_capabilities_.capabilities.ldacCapabilities(); + std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>( + ldac_capability.sampleRate, 0xff, supported); + std::vector<LdacChannelMode> channel_modes = + ExtractValuesFromBitmask<LdacChannelMode>(ldac_capability.channelMode, + 0x07, supported); + std::vector<LdacQualityIndex> quality_indexes = { + LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID, + LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR}; + std::vector<BitsPerSample> bits_per_samples = + ExtractValuesFromBitmask<BitsPerSample>(ldac_capability.bitsPerSample, + 0x07, supported); + // combine those parameters into one list of + // CodecConfiguration::CodecSpecific + CodecSpecificConfig codec_specific = {}; + LdacParameters ldac_data; + for (auto sample_rate : sample_rates) { + for (auto channel_mode : channel_modes) { + for (auto quality_index : quality_indexes) { + for (auto bits_per_sample : bits_per_samples) { + ldac_data = {.sampleRate = sample_rate, + .channelMode = channel_mode, + .qualityIndex = quality_index, + .bitsPerSample = bits_per_sample}; + codec_specific.ldacConfig(ldac_data); + ldac_codec_specifics.push_back(codec_specific); + } + } + } + } + return ldac_codec_specifics; + } + + std::vector<CodecSpecificConfig> GetAptxCodecSpecificSupportedList( + bool is_hd, bool supported) { + std::vector<CodecSpecificConfig> aptx_codec_specifics; + GetOffloadCodecCapabilityHelper( + (is_hd ? CodecType::APTX_HD : CodecType::APTX)); + if ((is_hd && temp_codec_capabilities_.codecType != CodecType::APTX_HD) || + (!is_hd && temp_codec_capabilities_.codecType != CodecType::APTX)) { + return aptx_codec_specifics; + } + // parse the capability + AptxParameters aptx_capability = + temp_codec_capabilities_.capabilities.aptxCapabilities(); + std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>( + aptx_capability.sampleRate, 0xff, supported); + std::vector<ChannelMode> channel_modes = + ExtractValuesFromBitmask<ChannelMode>(aptx_capability.channelMode, 0x03, + supported); + std::vector<BitsPerSample> bits_per_samples = + ExtractValuesFromBitmask<BitsPerSample>(aptx_capability.bitsPerSample, + 0x07, supported); + // combine those parameters into one list of + // CodecConfiguration::CodecSpecific + CodecSpecificConfig codec_specific = {}; + AptxParameters aptx_data; + for (auto sample_rate : sample_rates) { + for (auto channel_mode : channel_modes) { + for (auto bits_per_sample : bits_per_samples) { + aptx_data = {.sampleRate = sample_rate, + .channelMode = channel_mode, + .bitsPerSample = bits_per_sample}; + codec_specific.aptxConfig(aptx_data); + aptx_codec_specifics.push_back(codec_specific); + } + } + } + return aptx_codec_specifics; + } + + // temp storage saves the specified codec capability by + // GetOffloadCodecCapabilityHelper() + CodecCapabilities temp_codec_capabilities_; +}; + +/** + * Test whether we can open a provider of type + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {} + +/** + * Test whether each provider of type + * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with + * SBC hardware encoding config + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, + StartAndEndA2dpSbcHardwareSession) { + if (!IsOffloadSupported()) { + return; + } + + CodecConfiguration codec_config = {}; + codec_config.codecType = CodecType::SBC; + codec_config.encodedAudioBitrate = 328000; + codec_config.peerMtu = 1005; + codec_config.isScmstEnabled = false; + AudioConfiguration audio_config = {}; + std::vector<CodecSpecificConfig> sbc_codec_specifics = + GetSbcCodecSpecificSupportedList(true); + auto hidl_cb = [](BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS); + EXPECT_FALSE(dataMQ.isHandleValid()); + }; + for (auto codec_specific : sbc_codec_specifics) { + codec_config.config = codec_specific; + audio_config.codecConfig(codec_config); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } +} + +/** + * Test whether each provider of type + * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with + * AAC hardware encoding config + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, + StartAndEndA2dpAacHardwareSession) { + if (!IsOffloadSupported()) { + return; + } + + CodecConfiguration codec_config = {}; + codec_config.codecType = CodecType::AAC; + codec_config.encodedAudioBitrate = 320000; + codec_config.peerMtu = 1005; + codec_config.isScmstEnabled = false; + AudioConfiguration audio_config = {}; + std::vector<CodecSpecificConfig> aac_codec_specifics = + GetAacCodecSpecificSupportedList(true); + auto hidl_cb = [](BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS); + EXPECT_FALSE(dataMQ.isHandleValid()); + }; + for (auto codec_specific : aac_codec_specifics) { + codec_config.config = codec_specific; + audio_config.codecConfig(codec_config); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } +} + +/** + * Test whether each provider of type + * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with + * LDAC hardware encoding config + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, + StartAndEndA2dpLdacHardwareSession) { + if (!IsOffloadSupported()) { + return; + } + + CodecConfiguration codec_config = {}; + codec_config.codecType = CodecType::LDAC; + codec_config.encodedAudioBitrate = 990000; + codec_config.peerMtu = 1005; + codec_config.isScmstEnabled = false; + AudioConfiguration audio_config = {}; + std::vector<CodecSpecificConfig> ldac_codec_specifics = + GetLdacCodecSpecificSupportedList(true); + auto hidl_cb = [](BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS); + EXPECT_FALSE(dataMQ.isHandleValid()); + }; + for (auto codec_specific : ldac_codec_specifics) { + codec_config.config = codec_specific; + audio_config.codecConfig(codec_config); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } +} + +/** + * Test whether each provider of type + * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with + * AptX hardware encoding config + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, + StartAndEndA2dpAptxHardwareSession) { + if (!IsOffloadSupported()) { + return; + } + + for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) { + CodecConfiguration codec_config = {}; + codec_config.codecType = codec_type; + codec_config.encodedAudioBitrate = + (codec_type == CodecType::APTX ? 352000 : 576000); + codec_config.peerMtu = 1005; + codec_config.isScmstEnabled = false; + AudioConfiguration audio_config = {}; + std::vector<CodecSpecificConfig> aptx_codec_specifics = + GetAptxCodecSpecificSupportedList( + (codec_type == CodecType::APTX_HD ? true : false), true); + auto hidl_cb = [](BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS); + EXPECT_FALSE(dataMQ.isHandleValid()); + }; + for (auto codec_specific : aptx_codec_specifics) { + codec_config.config = codec_specific; + audio_config.codecConfig(codec_config); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } + } +} + +/** + * Test whether each provider of type + * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with + * an invalid codec config + */ +TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, + StartAndEndA2dpHardwareSessionInvalidCodecConfig) { + if (!IsOffloadSupported()) { + return; + } + ASSERT_NE(audio_provider_, nullptr); + + std::vector<CodecSpecificConfig> codec_specifics; + for (auto codec_type : a2dp_codec_types) { + switch (codec_type) { + case CodecType::SBC: + codec_specifics = GetSbcCodecSpecificSupportedList(false); + break; + case CodecType::AAC: + codec_specifics = GetAacCodecSpecificSupportedList(false); + break; + case CodecType::LDAC: + codec_specifics = GetLdacCodecSpecificSupportedList(false); + break; + case CodecType::APTX: + codec_specifics = GetAptxCodecSpecificSupportedList(false, false); + break; + case CodecType::APTX_HD: + codec_specifics = GetAptxCodecSpecificSupportedList(true, false); + break; + case CodecType::UNKNOWN: + codec_specifics.clear(); + break; + } + if (codec_specifics.empty()) { + continue; + } + + CodecConfiguration codec_config = {}; + codec_config.codecType = codec_type; + codec_config.encodedAudioBitrate = 328000; + codec_config.peerMtu = 1005; + codec_config.isScmstEnabled = false; + AudioConfiguration audio_config = {}; + auto hidl_cb = [](BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION); + EXPECT_FALSE(dataMQ.isHandleValid()); + }; + for (auto codec_specific : codec_specifics) { + codec_config.config = codec_specific; + audio_config.codecConfig(codec_config); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } + } +} + +/** + * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH + */ +class BluetoothAudioProviderHearingAidSoftwareHidlTest + : public BluetoothAudioProvidersFactoryHidlTest { + public: + virtual void SetUp() override { + BluetoothAudioProvidersFactoryHidlTest::SetUp(); + GetProviderCapabilitiesHelper( + SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH); + OpenProviderHelper(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH); + ASSERT_NE(audio_provider_, nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProvidersFactoryHidlTest::TearDown(); + } + + static constexpr SampleRate hearing_aid_sample_rates_[3] = { + SampleRate::RATE_UNKNOWN, SampleRate::RATE_16000, SampleRate::RATE_24000}; + static constexpr BitsPerSample hearing_aid_bits_per_samples_[3] = { + BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, + BitsPerSample::BITS_24}; + static constexpr ChannelMode hearing_aid_channel_modes_[3] = { + ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO}; +}; + +/** + * Test whether each provider of type + * SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and + * stopped with SBC hardware encoding config + */ +TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest, + OpenHearingAidSoftwareProvider) {} + +/** + * Test whether each provider of type + * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and + * stopped with different PCM config + */ +TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest, + StartAndEndHearingAidSessionWithPossiblePcmConfig) { + bool is_codec_config_valid; + std::unique_ptr<DataMQ> tempDataMQ; + auto hidl_cb = [&is_codec_config_valid, &tempDataMQ]( + BluetoothAudioStatus status, + const DataMQ::Descriptor& dataMQ) { + if (is_codec_config_valid) { + ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS); + ASSERT_TRUE(dataMQ.isHandleValid()); + tempDataMQ.reset(new DataMQ(dataMQ)); + } else { + EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION); + EXPECT_FALSE(dataMQ.isHandleValid()); + } + }; + AudioConfiguration audio_config = {}; + PcmParameters pcm_parameters = {}; + for (auto sample_rate : hearing_aid_sample_rates_) { + pcm_parameters.sampleRate = sample_rate; + for (auto bits_per_sample : hearing_aid_bits_per_samples_) { + pcm_parameters.bitsPerSample = bits_per_sample; + for (auto channel_mode : hearing_aid_channel_modes_) { + pcm_parameters.channelMode = channel_mode; + is_codec_config_valid = IsPcmParametersSupported(pcm_parameters); + audio_config.pcmConfig(pcm_parameters); + auto hidl_retval = + audio_provider_->startSession(audio_port_, audio_config, hidl_cb); + // HIDL calls should not be failed and callback has to be executed + ASSERT_TRUE(hidl_retval.isOk()); + if (is_codec_config_valid) { + EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid()); + } + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } // ChannelMode + } // BitsPerSampple + } // SampleRate +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment( + BluetoothAudioHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + BluetoothAudioHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp index 6054999a07..4de05c5de6 100644 --- a/camera/common/1.0/default/Exif.cpp +++ b/camera/common/1.0/default/Exif.cpp @@ -18,7 +18,7 @@ #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 -#include <cutils/log.h> +#include <android/log.h> #include <inttypes.h> #include <math.h> diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index 21dfd8894a..9e136811e0 100644 --- a/camera/device/3.2/default/CameraDeviceSession.cpp +++ b/camera/device/3.2/default/CameraDeviceSession.cpp @@ -44,13 +44,15 @@ static constexpr int METADATA_SHRINK_ABS_THRESHOLD = 4096; static constexpr int METADATA_SHRINK_REL_THRESHOLD = 2; HandleImporter CameraDeviceSession::sHandleImporter; +buffer_handle_t CameraDeviceSession::sEmptyBuffer = nullptr; + const int CameraDeviceSession::ResultBatcher::NOT_BATCHED; CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp<ICameraDeviceCallback>& callback) : - camera3_callback_ops({&sProcessCaptureResult, &sNotify}), + camera3_callback_ops({&sProcessCaptureResult, &sNotify, nullptr, nullptr}), mDevice(device), mDeviceVersion(device->common.version), mFreeBufEarly(shouldFreeBufEarly()), @@ -246,10 +248,50 @@ void CameraDeviceSession::overrideResultForPrecaptureCancelLocked( } } +Status CameraDeviceSession::importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + Mutex::Autolock _l(mInflightLock); + CirculatingBuffers& cbs = mCirculatingBuffers[streamId]; + if (cbs.count(bufId) == 0) { + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + sHandleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId); + return Status::INTERNAL_ERROR; + } else { + cbs[bufId] = importedBuf; + } + } + *outBufPtr = &cbs[bufId]; + return Status::OK; +} + Status CameraDeviceSession::importRequest( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, hidl_vec<int>& allFences) { + return importRequestImpl(request, allBufPtrs, allFences); +} + +Status CameraDeviceSession::importRequestImpl( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences, + bool allowEmptyBuf) { bool hasInputBuf = (request.inputBuffer.streamId != -1 && request.inputBuffer.bufferId != 0); size_t numOutputBufs = request.outputBuffers.size(); @@ -277,25 +319,15 @@ Status CameraDeviceSession::importRequest( } for (size_t i = 0; i < numBufs; i++) { - buffer_handle_t buf = allBufs[i]; - uint64_t bufId = allBufIds[i]; - CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]]; - if (cbs.count(bufId) == 0) { - if (buf == nullptr) { - ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); - return Status::ILLEGAL_ARGUMENT; - } - // Register a newly seen buffer - buffer_handle_t importedBuf = buf; - sHandleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; - } + Status st = importBuffer( + streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i], + // Disallow empty buf for input stream, otherwise follow + // the allowEmptyBuf argument. + (hasInputBuf && i == numOutputBufs) ? false : allowEmptyBuf); + if (st != Status::OK) { + // Detailed error logs printed in importBuffer + return st; } - allBufPtrs[i] = &cbs[bufId]; } // All buffers are imported. Now validate output buffer acquire fences @@ -1271,18 +1303,26 @@ Return<void> CameraDeviceSession::close() { ATRACE_END(); // free all imported buffers + Mutex::Autolock _l(mInflightLock); for(auto& pair : mCirculatingBuffers) { CirculatingBuffers& buffers = pair.second; for (auto& p2 : buffers) { sHandleImporter.freeBuffer(p2.second); } + buffers.clear(); } + mCirculatingBuffers.clear(); mClosed = true; } return Void(); } +uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t&, int) { + // No need to fill in bufferId by default + return BUFFER_ID_NO_BUFFER; +} + status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result) { uint32_t frameNumber = hal_result->frame_number; @@ -1396,6 +1436,14 @@ status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result, result.outputBuffers[i].streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; result.outputBuffers[i].buffer = nullptr; + if (hal_result->output_buffers[i].buffer != nullptr) { + result.outputBuffers[i].bufferId = getCapResultBufferId( + *(hal_result->output_buffers[i].buffer), + result.outputBuffers[i].streamId); + } else { + result.outputBuffers[i].bufferId = 0; + } + result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status; // skip acquire fence since it's of no use to camera service if (hal_result->output_buffers[i].release_fence != -1) { diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h index bcee259fbd..a96c245067 100644 --- a/camera/device/3.2/default/CameraDeviceSession.h +++ b/camera/device/3.2/default/CameraDeviceSession.h @@ -161,6 +161,7 @@ protected: std::map<uint32_t, bool> mInflightRawBoostPresent; ::android::hardware::camera::common::V1_0::helper::CameraMetadata mOverridenRequest; + static const uint64_t BUFFER_ID_NO_BUFFER = 0; // buffers currently ciculating between HAL and camera service // key: bufferId sent via HIDL interface // value: imported buffer_handle_t @@ -171,6 +172,7 @@ protected: std::map<int, CirculatingBuffers> mCirculatingBuffers; static HandleImporter sHandleImporter; + static buffer_handle_t sEmptyBuffer; bool mInitFail; bool mFirstRequest = false; @@ -301,11 +303,23 @@ protected: Status initStatus() const; // Validate and import request's input buffer and acquire fence - Status importRequest( + virtual Status importRequest( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, hidl_vec<int>& allFences); + Status importRequestImpl( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences, + // Optional argument for ICameraDeviceSession@3.5 impl + bool allowEmptyBuf = false); + + Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + static void cleanupInflightFences( hidl_vec<int>& allFences, size_t numFences); @@ -332,6 +346,11 @@ protected: static callbacks_process_capture_result_t sProcessCaptureResult; static callbacks_notify_t sNotify; + // By default camera service uses frameNumber/streamId pair to retrieve the buffer that + // was sent to HAL. Override this implementation if HAL is using buffers from buffer management + // APIs to send output buffer. + virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId); + status_t constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result); diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp index 389cecebf0..57081ca919 100644 --- a/camera/device/3.4/default/CameraDeviceSession.cpp +++ b/camera/device/3.4/default/CameraDeviceSession.cpp @@ -87,6 +87,14 @@ CameraDeviceSession::~CameraDeviceSession() { Return<void> CameraDeviceSession::configureStreams_3_4( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { + configureStreams_3_4_Impl(requestedConfiguration, _hidl_cb); + return Void(); +} + +void CameraDeviceSession::configureStreams_3_4_Impl( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb, + uint32_t streamConfigCounter) { Status status = initStatus(); HalStreamConfiguration outStreams; @@ -97,7 +105,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback", __FUNCTION__); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } } } @@ -109,7 +117,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", __FUNCTION__, mInflightBuffers.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (!mInflightAETriggerOverrides.empty()) { @@ -117,7 +125,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( " trigger overrides!", __FUNCTION__, mInflightAETriggerOverrides.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (!mInflightRawBoostPresent.empty()) { @@ -125,12 +133,12 @@ Return<void> CameraDeviceSession::configureStreams_3_4( " boost overrides!", __FUNCTION__, mInflightRawBoostPresent.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (status != Status::OK) { _hidl_cb(status, outStreams); - return Void(); + return; } const camera_metadata_t *paramBuffer = nullptr; @@ -139,11 +147,12 @@ Return<void> CameraDeviceSession::configureStreams_3_4( } camera3_stream_configuration_t stream_list{}; + stream_list.stream_configuration_counter = streamConfigCounter; hidl_vec<camera3_stream_t*> streams; stream_list.session_parameters = paramBuffer; if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) { _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } ATRACE_BEGIN("camera3->configure_streams"); @@ -168,7 +177,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( } _hidl_cb(status, outStreams); - return Void(); + return; } bool CameraDeviceSession::preProcessConfigurationLocked_3_4( diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h index fdc8a5afd2..00500b15f8 100644 --- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h +++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h @@ -87,6 +87,12 @@ protected: void postProcessConfigurationFailureLocked_3_4( const StreamConfiguration& requestedConfiguration); + void configureStreams_3_4_Impl( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb, + // Optional argument for ICameraDeviceSession@3.5 impl + uint32_t streamConfigCounter = 0); + Return<void> processCaptureRequest_3_4( const hidl_vec<V3_4::CaptureRequest>& requests, const hidl_vec<V3_2::BufferCache>& cachesToRemove, diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp index 963893afbd..0770f0418c 100644 --- a/camera/device/3.5/default/CameraDeviceSession.cpp +++ b/camera/device/3.5/default/CameraDeviceSession.cpp @@ -15,8 +15,10 @@ */ #define LOG_TAG "CamDevSession@3.5-impl" +#define ATRACE_TAG ATRACE_TAG_CAMERA #include <android/log.h> +#include <vector> #include <utils/Trace.h> #include "CameraDeviceSession.h" @@ -33,13 +35,26 @@ CameraDeviceSession::CameraDeviceSession( const sp<V3_2::ICameraDeviceCallback>& callback) : V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) { - mHasCallback_3_5 = false; + mCallback_3_5 = nullptr; auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { sp<ICameraDeviceCallback> callback3_5 = castResult; if (callback3_5 != nullptr) { - mHasCallback_3_5 = true; + mCallback_3_5 = callback3_5; + } + } + + if (mCallback_3_5 != nullptr) { + camera_metadata_entry bufMgrVersion = mDeviceInfo.find( + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION); + if (bufMgrVersion.count > 0) { + mSupportBufMgr = (bufMgrVersion.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + if (mSupportBufMgr) { + request_stream_buffers = sRequestStreamBuffers; + return_stream_buffers = sReturnStreamBuffers; + } } } } @@ -50,14 +65,297 @@ CameraDeviceSession::~CameraDeviceSession() { Return<void> CameraDeviceSession::configureStreams_3_5( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) { - return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb); + configureStreams_3_4_Impl(requestedConfiguration.v3_4, _hidl_cb, + requestedConfiguration.streamConfigCounter); + return Void(); } Return<void> CameraDeviceSession::signalStreamFlush( - const hidl_vec<int32_t>& /*requests*/, uint32_t /*streamConfigCounter*/) { + const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) { + std::vector<camera3_stream_t*> streams(streamIds.size()); + { + Mutex::Autolock _l(mInflightLock); + for (size_t i = 0; i < streamIds.size(); i++) { + int32_t id = streamIds[i]; + if (mStreamMap.count(id) == 0) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, id); + return Void(); + } + streams[i] = &mStreamMap[id]; + } + } + if (mDevice->ops->signal_stream_flush != nullptr) { + mDevice->ops->signal_stream_flush(mDevice, + streamConfigCounter, streams.size(), streams.data()); + } return Void(); } +Status CameraDeviceSession::importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) { + if (mSupportBufMgr) { + return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true); + } + return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false); +} + +void CameraDeviceSession::pushBufferId( + const buffer_handle_t& buf, uint64_t bufferId, int streamId) { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + + // emplace will return existing entry if there is one. + auto pair = mBufferIdMaps.emplace(streamId, BufferIdMap{}); + BufferIdMap& bIdMap = pair.first->second; + bIdMap[buf] = bufferId; +} + +uint64_t CameraDeviceSession::popBufferId( + const buffer_handle_t& buf, int streamId) { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + + auto streamIt = mBufferIdMaps.find(streamId); + if (streamIt == mBufferIdMaps.end()) { + return BUFFER_ID_NO_BUFFER; + } + BufferIdMap& bIdMap = streamIt->second; + auto it = bIdMap.find(buf); + if (it == bIdMap.end()) { + return BUFFER_ID_NO_BUFFER; + } + uint64_t bufId = it->second; + bIdMap.erase(it); + if (bIdMap.empty()) { + mBufferIdMaps.erase(streamIt); + } + return bufId; +} + +uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t& buf, int streamId) { + if (mSupportBufMgr) { + return popBufferId(buf, streamId); + } + return BUFFER_ID_NO_BUFFER; +} + +Camera3Stream* CameraDeviceSession::getStreamPointer(int32_t streamId) { + Mutex::Autolock _l(mInflightLock); + if (mStreamMap.count(streamId) == 0) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, streamId); + return nullptr; + } + return &mStreamMap[streamId]; +} + +void CameraDeviceSession::cleanupInflightBufferFences( + std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs) { + hidl_vec<int> hFences = fences; + cleanupInflightFences(hFences, fences.size()); + for (auto& p : bufs) { + popBufferId(p.first, p.second); + } +} + +camera3_buffer_request_status_t CameraDeviceSession::requestStreamBuffers( + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { + ATRACE_CALL(); + *num_returned_buf_reqs = 0; + hidl_vec<BufferRequest> hBufReqs(num_buffer_reqs); + for (size_t i = 0; i < num_buffer_reqs; i++) { + hBufReqs[i].streamId = + static_cast<Camera3Stream*>(buffer_reqs[i].stream)->mId; + hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested; + } + + ATRACE_BEGIN("HIDL requestStreamBuffers"); + BufferRequestStatus status; + hidl_vec<StreamBufferRet> bufRets; + auto err = mCallback_3_5->requestStreamBuffers(hBufReqs, + [&status, &bufRets] + (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) { + status = s; + bufRets = std::move(rets); + }); + if (!err.isOk()) { + ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + ATRACE_END(); + + if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) { + if (bufRets.size() != num_buffer_reqs) { + ALOGE("%s: expect %d buffer requests returned, only got %zu", + __FUNCTION__, num_buffer_reqs, bufRets.size()); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + for (size_t i = 0; i < num_buffer_reqs; i++) { + // maybe we can query all streams in one call to avoid frequent locking device here? + Camera3Stream* stream = getStreamPointer(bufRets[i].streamId); + if (stream == nullptr) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, bufRets[i].streamId); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + returned_buf_reqs[i].stream = stream; + } + + std::vector<int> importedFences; + std::vector<std::pair<buffer_handle_t, int>> importedBuffers; + for (size_t i = 0; i < num_buffer_reqs; i++) { + int streamId = bufRets[i].streamId; + switch (bufRets[i].val.getDiscriminator()) { + case StreamBuffersVal::hidl_discriminator::error: + returned_buf_reqs[i].num_output_buffers = 0; + switch (bufRets[i].val.error()) { + case StreamBufferRequestError::NO_BUFFER_AVAILABLE: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_NO_BUFFER_AVAILABLE; + break; + case StreamBufferRequestError::MAX_BUFFER_EXCEEDED: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_MAX_BUFFER_EXCEEDED; + break; + case StreamBufferRequestError::STREAM_DISCONNECTED: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_STREAM_DISCONNECTED; + break; + case StreamBufferRequestError::UNKNOWN_ERROR: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_UNKNOWN_ERROR; + break; + default: + ALOGE("%s: Unknown StreamBufferRequestError %d", + __FUNCTION__, bufRets[i].val.error()); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + break; + case StreamBuffersVal::hidl_discriminator::buffers: { + const hidl_vec<StreamBuffer>& hBufs = bufRets[i].val.buffers(); + camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers; + for (size_t b = 0; b < hBufs.size(); b++) { + const StreamBuffer& hBuf = hBufs[b]; + camera3_stream_buffer_t& outBuf = outBufs[b]; + // maybe add importBuffers API to avoid frequent locking device? + Status s = importBuffer(streamId, + hBuf.bufferId, hBuf.buffer.getNativeHandle(), + /*out*/&(outBuf.buffer), + /*allowEmptyBuf*/false); + if (s != Status::OK) { + ALOGE("%s: import stream %d bufferId %" PRIu64 " failed!", + __FUNCTION__, streamId, hBuf.bufferId); + cleanupInflightBufferFences(importedFences, importedBuffers); + // Buffer import should never fail - restart HAL since something is very + // wrong. + assert(false); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId); + importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId)); + + if (!sHandleImporter.importFence( + hBuf.acquireFence, + outBuf.acquire_fence)) { + ALOGE("%s: stream %d bufferId %" PRIu64 "acquire fence is invalid", + __FUNCTION__, streamId, hBuf.bufferId); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + importedFences.push_back(outBuf.acquire_fence); + outBuf.stream = returned_buf_reqs[i].stream; + outBuf.status = CAMERA3_BUFFER_STATUS_OK; + outBuf.release_fence = -1; + } + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_OK; + } break; + default: + ALOGE("%s: unknown StreamBuffersVal discrimator!", __FUNCTION__); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + } + + *num_returned_buf_reqs = num_buffer_reqs; + + return (status == BufferRequestStatus::OK) ? + CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL; + } + + switch (status) { + case BufferRequestStatus::FAILED_CONFIGURING: + return CAMERA3_BUF_REQ_FAILED_CONFIGURING; + case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS: + return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; + case BufferRequestStatus::FAILED_UNKNOWN: + default: + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } +} + +void CameraDeviceSession::returnStreamBuffers( + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers) { + ATRACE_CALL(); + hidl_vec<StreamBuffer> hBufs(num_buffers); + + for (size_t i = 0; i < num_buffers; i++) { + hBufs[i].streamId = + static_cast<Camera3Stream*>(buffers[i]->stream)->mId; + hBufs[i].buffer = nullptr; // use bufferId + hBufs[i].bufferId = popBufferId(*(buffers[i]->buffer), hBufs[i].streamId); + if (hBufs[i].bufferId == BUFFER_ID_NO_BUFFER) { + ALOGE("%s: unknown buffer is returned to stream %d", + __FUNCTION__, hBufs[i].streamId); + } + // ERROR since the buffer is not for application to consume + hBufs[i].status = BufferStatus::ERROR; + // skip acquire fence since it's of no use to camera service + if (buffers[i]->release_fence != -1) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = buffers[i]->release_fence; + hBufs[i].releaseFence.setTo(handle, /*shouldOwn*/true); + } + } + + mCallback_3_5->returnStreamBuffers(hBufs); + return; +} + +/** + * Static callback forwarding methods from HAL to instance + */ +camera3_buffer_request_status_t CameraDeviceSession::sRequestStreamBuffers( + const struct camera3_callback_ops *cb, + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + + if (num_buffer_reqs == 0 || buffer_reqs == nullptr || num_returned_buf_reqs == nullptr || + returned_buf_reqs == nullptr) { + ALOGE("%s: bad argument: numBufReq %d, bufReqs %p, numRetBufReq %p, retBufReqs %p", + __FUNCTION__, num_buffer_reqs, buffer_reqs, + num_returned_buf_reqs, returned_buf_reqs); + return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; + } + + return d->requestStreamBuffers(num_buffer_reqs, buffer_reqs, + num_returned_buf_reqs, returned_buf_reqs); +} + +void CameraDeviceSession::sReturnStreamBuffers( + const struct camera3_callback_ops *cb, + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + + d->returnStreamBuffers(num_buffers, buffers); +} + } // namespace implementation } // namespace V3_5 } // namespace device diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h index ec34769973..4f7284c5fe 100644 --- a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h +++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h @@ -21,6 +21,7 @@ #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h> #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h> #include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h> +#include <unordered_map> namespace android { namespace hardware { @@ -30,11 +31,14 @@ namespace V3_5 { namespace implementation { using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::device::V3_2::BufferStatus; using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::StreamBuffer; using ::android::hardware::camera::device::V3_5::StreamConfiguration; using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; using ::android::hardware::camera::device::V3_5::ICameraDeviceSession; using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream; using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::common::V1_0::helper::HandleImporter; using ::android::hardware::Return; @@ -44,6 +48,25 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::Mutex; + +/** + * Function pointer types with C calling convention to + * use for HAL callback functions. + */ +extern "C" { + typedef camera3_buffer_request_status_t (callbacks_request_stream_buffer_t)( + const struct camera3_callback_ops *, + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs); + + typedef void (callbacks_return_stream_buffer_t)( + const struct camera3_callback_ops *, + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers); +} + struct CameraDeviceSession : public V3_4::implementation::CameraDeviceSession { CameraDeviceSession(camera3_device_t*, @@ -62,12 +85,85 @@ protected: ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb); Return<void> signalStreamFlush( - const hidl_vec<int32_t>& requests, + const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter); + virtual Status importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) override; + + /** + * Static callback forwarding methods from HAL to instance + */ + static callbacks_request_stream_buffer_t sRequestStreamBuffers; + static callbacks_return_stream_buffer_t sReturnStreamBuffers; + + camera3_buffer_request_status_t requestStreamBuffers( + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs); + + void returnStreamBuffers( + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers); + + struct BufferHasher { + size_t operator()(const buffer_handle_t& buf) const { + if (buf == nullptr) + return 0; + + size_t result = 1; + result = 31 * result + buf->numFds; + for (int i = 0; i < buf->numFds; i++) { + result = 31 * result + buf->data[i]; + } + return result; + } + }; + + struct BufferComparator { + bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const { + if (buf1->numFds == buf2->numFds) { + for (int i = 0; i < buf1->numFds; i++) { + if (buf1->data[i] != buf2->data[i]) { + return false; + } + } + return true; + } + return false; + } + }; + + Camera3Stream* getStreamPointer(int32_t streamId); + + // Register buffer to mBufferIdMaps so we can find corresponding bufferId + // when the buffer is returned to camera service + void pushBufferId(const buffer_handle_t& buf, uint64_t bufferId, int streamId); + + // Method to pop buffer's bufferId from mBufferIdMaps + // BUFFER_ID_NO_BUFFER is returned if no matching buffer is found + uint64_t popBufferId(const buffer_handle_t& buf, int streamId); + + // Method to cleanup imported buffer/fences if requestStreamBuffers fails half way + void cleanupInflightBufferFences( + std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs); + + // Overrides the default constructCaptureResult behavior for buffer management APIs + virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId) override; + + std::mutex mBufferIdMapLock; // protecting mBufferIdMaps and mNextBufferId + typedef std::unordered_map<const buffer_handle_t, uint64_t, + BufferHasher, BufferComparator> BufferIdMap; + // stream ID -> per stream buffer ID map for buffers coming from requestStreamBuffers API + // Entries are created during requestStreamBuffers when a stream first request a buffer, and + // deleted in returnStreamBuffers/processCaptureResult* when all buffers are returned + std::unordered_map<int, BufferIdMap> mBufferIdMaps; - // Whether this camera device session is created with version 3.5 callback. - bool mHasCallback_3_5; + sp<ICameraDeviceCallback> mCallback_3_5; + bool mSupportBufMgr; private: diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal index 61a399eb1a..9bbc90dc28 100644 --- a/camera/metadata/3.4/types.hal +++ b/camera/metadata/3.4/types.hal @@ -73,8 +73,38 @@ enum CameraMetadataTag : @3.3::CameraMetadataTag { */ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_DEPTH_END, + /** android.depth.availableDynamicDepthStreamConfigurations [static, enum[], ndk_public] + * + * <p>The available dynamic depth dataspace stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, + + /** android.depth.availableDynamicDepthMinFrameDurations [static, int64[], ndk_public] + * + * <p>This lists the minimum frame duration for each + * format/size combination for dynamic depth output streams.</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, + + /** android.depth.availableDynamicDepthStallDurations [static, int64[], ndk_public] + * + * <p>This lists the maximum stall duration for each + * output format/size combination for dynamic depth streams.</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, + ANDROID_DEPTH_END_3_4, + /** android.logicalMultiCamera.activePhysicalId [dynamic, byte, public] + * + * <p>String containing the ID of the underlying active physical camera.</p> + */ + ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_LOGICAL_MULTI_CAMERA_END_3_3, + + ANDROID_LOGICAL_MULTI_CAMERA_END_3_4, + }; /* @@ -128,3 +158,11 @@ enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement : enum CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion : uint32_t { ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5, }; + +/** android.depth.availableDynamicDepthStreamConfigurations enumeration values + * @see ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS + */ +enum CameraMetadataEnumAndroidDepthAvailableDynamicDepthStreamConfigurations : uint32_t { + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_OUTPUT, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT, +}; diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp index 488b9afe58..e02cc7e490 100644 --- a/camera/provider/2.4/default/CameraProvider.cpp +++ b/camera/provider/2.4/default/CameraProvider.cpp @@ -41,11 +41,8 @@ const char *kLegacyProviderName = "legacy/0"; const char *kExternalProviderName = "external/0"; // "device@<version>/legacy/<id>" const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)"); -const char *kHAL3_2 = "3.2"; -const char *kHAL3_3 = "3.3"; const char *kHAL3_4 = "3.4"; const char *kHAL3_5 = "3.5"; -const char *kHAL1_0 = "1.0"; const int kMaxCameraDeviceNameLen = 128; const int kMaxCameraIdLen = 16; @@ -143,7 +140,6 @@ void CameraProvider::sCameraDeviceStatusChange( int new_status) { CameraProvider* cp = const_cast<CameraProvider*>( static_cast<const CameraProvider*>(callbacks)); - bool found = false; if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); @@ -155,17 +151,23 @@ void CameraProvider::sCameraDeviceStatusChange( snprintf(cameraId, sizeof(cameraId), "%d", camera_id); std::string cameraIdStr(cameraId); cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status; - if (cp->mCallbacks != nullptr) { - CameraDeviceStatus status = (CameraDeviceStatus) new_status; - for (auto const& deviceNamePair : cp->mCameraDeviceNames) { - if (cameraIdStr.compare(deviceNamePair.first) == 0) { - cp->mCallbacks->cameraDeviceStatusChange( - deviceNamePair.second, status); - found = true; - } + + if (cp->mCallbacks == nullptr) { + // For camera connected before mCallbacks is set, the corresponding + // addDeviceNames() would be called later in setCallbacks(). + return; + } + + bool found = false; + CameraDeviceStatus status = (CameraDeviceStatus)new_status; + for (auto const& deviceNamePair : cp->mCameraDeviceNames) { + if (cameraIdStr.compare(deviceNamePair.first) == 0) { + cp->mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status); + found = true; } + } - switch (status) { + switch (status) { case CameraDeviceStatus::PRESENT: case CameraDeviceStatus::ENUMERATING: if (!found) { @@ -176,7 +178,6 @@ void CameraProvider::sCameraDeviceStatusChange( if (found) { cp->removeDeviceNames(camera_id); } - } } } @@ -222,22 +223,6 @@ std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) { return cameraId; } -int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) { - std::string deviceVersion; - bool match = matchDeviceName(deviceName, &deviceVersion, nullptr); - if (!match) { - return -1; - } - if (deviceVersion == kHAL3_3) { - return CAMERA_DEVICE_API_VERSION_3_3; - } else if (deviceVersion == kHAL3_2) { - return CAMERA_DEVICE_API_VERSION_3_2; - } else if (deviceVersion == kHAL1_0) { - return CAMERA_DEVICE_API_VERSION_1_0; - } - return 0; -} - std::string CameraProvider::getHidlDeviceName( std::string cameraId, int deviceVersion) { // Maybe consider create a version check method and SortedVec to speed up? @@ -245,9 +230,16 @@ std::string CameraProvider::getHidlDeviceName( deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 && - deviceVersion != CAMERA_DEVICE_API_VERSION_3_5) { + deviceVersion != CAMERA_DEVICE_API_VERSION_3_5 && + deviceVersion != CAMERA_DEVICE_API_VERSION_3_6) { return hidl_string(""); } + + // Supported combinations: + // CAMERA_DEVICE_API_VERSION_1_0 -> ICameraDevice@1.0 + // CAMERA_DEVICE_API_VERSION_3_[2-4] -> ICameraDevice@[3.2|3.3] + // CAMERA_DEVICE_API_VERSION_3_5 + CAMERA_MODULE_API_VERSION_2_4 -> ICameraDevice@3.4 + // CAMERA_DEVICE_API_VERSION_3_[5-6] + CAMERA_MODULE_API_VERSION_2_5 -> ICameraDevice@3.5 bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0; int versionMajor = isV1 ? 1 : 3; int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion; @@ -257,6 +249,8 @@ std::string CameraProvider::getHidlDeviceName( } else { versionMinor = 4; } + } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) { + versionMinor = 5; } char deviceName[kMaxCameraDeviceNameLen]; snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s", @@ -356,7 +350,8 @@ int CameraProvider::checkCameraVersion(int id, camera_info info) { // device_version undefined in CAMERA_MODULE_API_VERSION_1_0, // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible - if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) { + uint16_t moduleVersion = mModule->getModuleApiVersion(); + if (moduleVersion >= CAMERA_MODULE_API_VERSION_2_0) { // Verify the device version is in the supported range switch (info.device_version) { case CAMERA_DEVICE_API_VERSION_1_0: @@ -366,6 +361,20 @@ int CameraProvider::checkCameraVersion(int id, camera_info info) { case CAMERA_DEVICE_API_VERSION_3_5: // in support break; + case CAMERA_DEVICE_API_VERSION_3_6: + /** + * ICameraDevice@3.5 contains APIs from both + * CAMERA_DEVICE_API_VERSION_3_6 and CAMERA_MODULE_API_VERSION_2_5 + * so we require HALs to uprev both for simplified supported combinations. + * HAL can still opt in individual new APIs indepedently. + */ + if (moduleVersion < CAMERA_MODULE_API_VERSION_2_5) { + ALOGE("%s: Device %d has unsupported version combination:" + "HAL version %x and module version %x", + __FUNCTION__, id, info.device_version, moduleVersion); + return NO_INIT; + } + break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: case CAMERA_DEVICE_API_VERSION_3_0: @@ -439,8 +448,22 @@ bool CameraProvider::setUpVendorTags() { // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback) { + if (callback == nullptr) { + return Status::ILLEGAL_ARGUMENT; + } + Mutex::Autolock _l(mCbLock); mCallbacks = callback; + + // Add and report all presenting external cameras. + for (auto const& statusPair : mCameraStatusMap) { + int id = std::stoi(statusPair.first); + auto status = static_cast<CameraDeviceStatus>(statusPair.second); + if (id >= mNumberOfLegacyCameras && status != CameraDeviceStatus::NOT_PRESENT) { + addDeviceNames(id, status, true); + } + } + return Status::OK; } @@ -452,6 +475,11 @@ Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) { Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { std::vector<hidl_string> deviceNameList; for (auto const& deviceNamePair : mCameraDeviceNames) { + if (std::stoi(deviceNamePair.first) >= mNumberOfLegacyCameras) { + // External camera devices must be reported through the device status change callback, + // not in this list. + continue; + } if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) { deviceNameList.push_back(deviceNamePair.second); } @@ -552,10 +580,11 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - // ICameraDevice 3.4 or upper sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl; + + // ICameraDevice 3.4 or upper if (deviceVersion >= kHAL3_4) { - ALOGV("Constructing v3.4 camera device"); + ALOGV("Constructing v3.4+ camera device"); if (deviceVersion == kHAL3_4) { deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h index 0f0959f1f0..10e9b0d276 100644 --- a/camera/provider/2.4/default/CameraProvider.h +++ b/camera/provider/2.4/default/CameraProvider.h @@ -98,7 +98,6 @@ private: // extract legacy camera ID/device version from a HIDL device name static std::string getLegacyCameraId(const hidl_string& deviceName); - static int getCameraDeviceVersion(const hidl_string& deviceName); // convert conventional HAL status to HIDL Status static Status getHidlStatus(int); diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 60db5dfafc..211240a06b 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -114,6 +114,8 @@ using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; using ::android::hardware::camera::device::V1_0::FrameCallbackFlag; using ::android::hardware::camera::device::V1_0::HandleTimestampMessage; using ::android::hardware::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement; +using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag; +using ::android::hardware::camera::device::V3_4::PhysicalCameraMetadata; using ::android::hardware::MessageQueue; using ::android::hardware::kSynchronizedReadWrite; using ::android::hidl::allocator::V1_0::IAllocator; @@ -587,8 +589,8 @@ public: }; struct DeviceCb : public V3_5::ICameraDeviceCallback { - DeviceCb(CameraHidlTest *parent, bool checkMonochromeResult) : mParent(parent), - mCheckMonochromeResult(checkMonochromeResult) {} + DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) : + mParent(parent), mDeviceVersion(deviceVersion), mStaticMetadata(staticMeta) {} Return<void> processCaptureResult_3_4( const hidl_vec<V3_4::CaptureResult>& results) override; @@ -607,10 +609,12 @@ public: void waitForBuffersReturned(); private: - bool processCaptureResultLocked(const CaptureResult& results); + bool processCaptureResultLocked(const CaptureResult& results, + hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata); CameraHidlTest *mParent; // Parent object - bool mCheckMonochromeResult; + int mDeviceVersion; + const camera_metadata_t *mStaticMetadata; bool hasOutstandingBuffersLocked(); /* members for requestStreamBuffers() and returnStreamBuffers()*/ @@ -755,6 +759,8 @@ public: void verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5, const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, bool expectedStatus); + void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata); void verifyBuffersReturned(sp<device::V3_2::ICameraDeviceSession> session, int deviceVerison, int32_t streamId, sp<DeviceCb> cb, @@ -1008,7 +1014,7 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult_3_4( bool notify = false; std::unique_lock<std::mutex> l(mParent->mLock); for (size_t i = 0 ; i < results.size(); i++) { - notify = processCaptureResultLocked(results[i].v3_2); + notify = processCaptureResultLocked(results[i].v3_2, results[i].physicalCameraMetadata); } l.unlock(); @@ -1027,8 +1033,9 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult( bool notify = false; std::unique_lock<std::mutex> l(mParent->mLock); + ::android::hardware::hidl_vec<PhysicalCameraMetadata> noPhysMetadata; for (size_t i = 0 ; i < results.size(); i++) { - notify = processCaptureResultLocked(results[i]); + notify = processCaptureResultLocked(results[i], noPhysMetadata); } l.unlock(); @@ -1039,7 +1046,8 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult( return Void(); } -bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) { +bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results, + hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata) { bool notify = false; uint32_t frameNumber = results.frameNumber; @@ -1080,6 +1088,20 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r ADD_FAILURE(); return notify; } + + std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata; + physResultMetadata.resize(physicalCameraMetadata.size()); + for (size_t i = 0; i < physicalCameraMetadata.size(); i++) { + physResultMetadata[i].resize(physicalCameraMetadata[i].fmqMetadataSize); + if (!request->resultQueue->read(physResultMetadata[i].data(), + physicalCameraMetadata[i].fmqMetadataSize)) { + ALOGE("%s: Frame %d: Cannot read physical camera metadata from fmq," + "size = %" PRIu64, __func__, frameNumber, + physicalCameraMetadata[i].fmqMetadataSize); + ADD_FAILURE(); + return notify; + } + } resultSize = resultMetadata.size(); } else if (results.result.size() > 0) { resultMetadata.setToExternal(const_cast<uint8_t *>( @@ -1137,8 +1159,20 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r request->collectedResult.sort(); // Verify final result metadata - if (mCheckMonochromeResult) { - mParent->verifyMonochromeCameraResult(request->collectedResult); + bool isAtLeast_3_5 = mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5; + if (isAtLeast_3_5) { + bool isMonochrome = Status::OK == + CameraHidlTest::isMonochromeCamera(mStaticMetadata); + if (isMonochrome) { + mParent->verifyMonochromeCameraResult(request->collectedResult); + } + + // Verify logical camera result metadata + bool isLogicalCamera = + Status::OK == CameraHidlTest::isLogicalMultiCamera(mStaticMetadata); + if (isLogicalCamera) { + mParent->verifyLogicalCameraResult(mStaticMetadata, request->collectedResult); + } } } @@ -3268,6 +3302,8 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { continue; } + outputPreviewStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputPreviewStreams, &previewThreshold)); ASSERT_NE(0u, outputPreviewStreams.size()); @@ -5056,7 +5092,7 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t ASSERT_EQ(Status::OK, s); staticMeta = clone_camera_metadata( reinterpret_cast<const camera_metadata_t*>(metadata.data())); - ASSERT_NE(nullptr, staticMeta); + ASSERT_NE(nullptr, staticMeta); }); ASSERT_TRUE(ret.isOk()); @@ -5068,9 +5104,7 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t *supportsPartialResults = (*partialResultCount > 1); } - bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) && - deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5; - sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags); + sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta); sp<ICameraDeviceSession> session; ret = device3_x->open( cb, @@ -5208,9 +5242,7 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev *supportsPartialResults = (*partialResultCount > 1); } - bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) && - deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5; - sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags); + sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta); ret = device3_x->open( cb, [&](auto status, const auto& newSession) { @@ -5439,6 +5471,22 @@ void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, }); ASSERT_TRUE(ret.isOk()); } + + // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in + // result keys. + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) { + camera_metadata_ro_entry entry; + int retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); + if ((0 == retcode) && (entry.count > 0)) { + ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count, + static_cast<int32_t>( + CameraMetadataTag::ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID)), + entry.data.i32 + entry.count); + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + } } void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMetadata& chars) { @@ -5473,6 +5521,24 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta ADD_FAILURE() << "ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION " << " per API contract should never be set by Hal!"; } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS" + << " per API contract should never be set by Hal!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS" + << " per API contract should never be set by Hal!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS" + << " per API contract should never be set by Hal!"; + } } void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars, @@ -5647,6 +5713,24 @@ void CameraHidlTest::verifyBuffersReturned( cb->waitForBuffersReturned(); } +void CameraHidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata) { + std::unordered_set<std::string> physicalIds; + Status rc = getPhysicalCameraIds(staticMetadata, &physicalIds); + ASSERT_TRUE(Status::OK == rc); + ASSERT_TRUE(physicalIds.size() > 1); + + camera_metadata_ro_entry entry; + // Check mainPhysicalId + entry = resultMetadata.find(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID); + if (entry.count > 0) { + std::string mainPhysicalId(reinterpret_cast<const char *>(entry.data.u8)); + ASSERT_NE(physicalIds.find(mainPhysicalId), physicalIds.end()); + } else { + ADD_FAILURE() << "Get LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID failed!"; + } +} + // Open a device session with empty callbacks and return static metadata. void CameraHidlTest::openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider, sp<ICameraDeviceSession> *session /*out*/, camera_metadata_t **staticMeta /*out*/, diff --git a/cas/1.1/Android.bp b/cas/1.1/Android.bp new file mode 100644 index 0000000000..bb0edb970c --- /dev/null +++ b/cas/1.1/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.cas@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ICas.hal", + "ICasListener.hal", + "IMediaCasService.hal", + ], + interfaces: [ + "android.hardware.cas@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/cas/1.1/ICas.hal b/cas/1.1/ICas.hal new file mode 100644 index 0000000000..027968e565 --- /dev/null +++ b/cas/1.1/ICas.hal @@ -0,0 +1,42 @@ +/* + * 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.1; + +import @1.0::HidlCasSessionId; +import @1.0::ICas; +import @1.0::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.0::ICas { + /** + * Send an scheme-specific session event to the CasPlugin. + * + * @param sessionId the id of an opened session. + * @param event an integer denoting a scheme-specific event to be sent. + * @param arg a scheme-specific integer argument for the event. + * @param data a byte array containing scheme-specific data for the event. + * @return status the status of the call. + */ + sendSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec<uint8_t> eventData) + generates (Status status); +}; diff --git a/cas/1.1/ICasListener.hal b/cas/1.1/ICasListener.hal new file mode 100644 index 0000000000..5ec1154a3f --- /dev/null +++ b/cas/1.1/ICasListener.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.cas@1.1; + +import @1.0::ICasListener; +import @1.0::HidlCasSessionId; + +interface ICasListener extends @1.0::ICasListener{ + /** + * Notify the listener of a scheme-specific session event from CA system. + * + * @param sessionId the id of an opened session. + * @param event an integer whose meaning is scheme-specific. + * @param arg an integer whose meaning is scheme-specific. + * @param data a byte array of data whose format and meaning are + * scheme-specific. + */ + onSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec<uint8_t> data); +}; diff --git a/cas/1.1/IMediaCasService.hal b/cas/1.1/IMediaCasService.hal new file mode 100644 index 0000000000..e82b54c9db --- /dev/null +++ b/cas/1.1/IMediaCasService.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.cas@1.1; + +import @1.1::ICas; +import @1.1::ICasListener; +import @1.0::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. + */ + +interface IMediaCasService extends @1.0::IMediaCasService { + /** + * Construct a new instance of a @1.1 ICAS CasPlugin given a CA_system_id. + * + * @param caSystemId the id of the CA system. + * @param listener the event listener to receive events coming from the CasPlugin. + * @return cas the newly created CasPlugin interface. + */ + createPluginExt(int32_t caSystemId, ICasListener listener) generates (ICas cas); +}; diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp new file mode 100644 index 0000000000..68a49cf5b1 --- /dev/null +++ b/cas/1.1/default/Android.bp @@ -0,0 +1,49 @@ +cc_defaults { + name: "cas_service_defaults@1.1", + 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.native@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "liblog", + "libutils", + ], + header_libs: [ + "libstagefright_foundation_headers", + "media_plugin_headers", + ], +} + +cc_binary { + name: "android.hardware.cas@1.1-service", + vintf_fragments: ["android.hardware.cas@1.1-service.xml"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service.rc"], +} + +cc_binary { + name: "android.hardware.cas@1.1-service-lazy", + vintf_fragments: ["android.hardware.cas@1.1-service-lazy.xml"], + overrides: ["android.hardware.cas@1.1-service"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} diff --git a/cas/1.1/default/CasImpl.cpp b/cas/1.1/default/CasImpl.cpp new file mode 100644 index 0000000000..4cc6017028 --- /dev/null +++ b/cas/1.1/default/CasImpl.cpp @@ -0,0 +1,222 @@ +/* + * 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-CasImpl" + +#include <android/hardware/cas/1.1/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); +} + +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); + } +} + +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<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.1/default/CasImpl.h b/cas/1.1/default/CasImpl.h new file mode 100644 index 0000000000..18aee9e457 --- /dev/null +++ b/cas/1.1/default/CasImpl.h @@ -0,0 +1,98 @@ +/* + * 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 <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; + +class SharedLibrary; + +class CasImpl : public 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); + + 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); + + // ICas inherits + + virtual Return<Status> setPrivateData(const HidlCasData& pvtData) override; + + virtual Return<void> openSession(openSession_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.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp new file mode 100644 index 0000000000..36dc1a51d0 --- /dev/null +++ b/cas/1.1/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.1/default/DescramblerImpl.h b/cas/1.1/default/DescramblerImpl.h new file mode 100644 index 0000000000..a1f66ae464 --- /dev/null +++ b/cas/1.1/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.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h new file mode 100644 index 0000000000..c4a48e2852 --- /dev/null +++ b/cas/1.1/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.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp new file mode 100644 index 0000000000..e2d3357023 --- /dev/null +++ b/cas/1.1/default/MediaCasService.cpp @@ -0,0 +1,126 @@ +/* + * 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 <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 { + +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 */) { + ALOGE("%s:Use createPluginExt to create plugin with cas@1.1", __FUNCTION__); + + sp<V1_0::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::OnEvent, &plugin) == OK && plugin != NULL) { + casImpl->init(library, plugin); + result = casImpl; + } + } + */ + 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); + + sp<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; + } + } + + 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.1/default/MediaCasService.h b/cas/1.1/default/MediaCasService.h new file mode 100644 index 0000000000..ec5a86d9b3 --- /dev/null +++ b/cas/1.1/default/MediaCasService.h @@ -0,0 +1,66 @@ +/* + * 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 "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 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.1/default/SharedLibrary.cpp b/cas/1.1/default/SharedLibrary.cpp new file mode 100644 index 0000000000..ffe4bb977a --- /dev/null +++ b/cas/1.1/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.1/default/SharedLibrary.h b/cas/1.1/default/SharedLibrary.h new file mode 100644 index 0000000000..f4d2ff6b9d --- /dev/null +++ b/cas/1.1/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.1/default/TypeConvert.cpp b/cas/1.1/default/TypeConvert.cpp new file mode 100644 index 0000000000..09ef41ae8f --- /dev/null +++ b/cas/1.1/default/TypeConvert.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. + */ + +//#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; +} + +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.1/default/TypeConvert.h b/cas/1.1/default/TypeConvert.h new file mode 100644 index 0000000000..c4a0119926 --- /dev/null +++ b/cas/1.1/default/TypeConvert.h @@ -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. + */ + +#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 <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); + +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.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc new file mode 100644 index 0000000000..9227b6f7e4 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc @@ -0,0 +1,9 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy + interface android.hardware.cas@1.1::IMediaCasService default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.cas</name> + <transport>hwbinder</transport> + <version>1.1</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc new file mode 100644 index 0000000000..4081fe1e64 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc @@ -0,0 +1,6 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.xml b/cas/1.1/default/android.hardware.cas@1.1-service.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.cas</name> + <transport>hwbinder</transport> + <version>1.1</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp new file mode 100644 index 0000000000..962530370c --- /dev/null +++ b/cas/1.1/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::IMediaCasService; +using android::hardware::cas::V1_1::implementation::MediaCasService; + +#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 = std::make_shared<LazyServiceRegistrar>(); + 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/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk index 6be6930023..425e376830 100644 --- a/compatibility_matrices/Android.mk +++ b/compatibility_matrices/Android.mk @@ -17,8 +17,9 @@ LOCAL_PATH := $(call my-dir) BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := $(LOCAL_PATH)/compatibility_matrix.mk +my_empty_manifest := $(LOCAL_PATH)/manifest.empty.xml -# Framework Compatibility Matrix (common to all FCM versions) +# System Compatibility Matrix (common to all FCM versions) include $(CLEAR_VARS) include $(LOCAL_PATH)/clear_vars.mk @@ -26,6 +27,7 @@ LOCAL_MODULE := framework_compatibility_matrix.device.xml LOCAL_MODULE_STEM := compatibility_matrix.device.xml # define LOCAL_MODULE_CLASS for local-generated-sources-dir. LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_RELATIVE_PATH := vintf ifndef DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE LOCAL_SRC_FILES := compatibility_matrix.empty.xml @@ -37,10 +39,9 @@ LOCAL_GENERATED_SOURCES := $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE) # Enforce that DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE does not specify required HALs # by checking it against an empty manifest. But the empty manifest needs to contain # BOARD_SEPOLICY_VERS to be compatible with DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE. -my_manifest_src_file := $(LOCAL_PATH)/manifest.empty.xml my_gen_check_manifest := $(local-generated-sources-dir)/manifest.check.xml -$(my_gen_check_manifest): PRIVATE_SRC_FILE := $(my_manifest_src_file) -$(my_gen_check_manifest): $(my_manifest_src_file) $(HOST_OUT_EXECUTABLES)/assemble_vintf +$(my_gen_check_manifest): PRIVATE_SRC_FILE := $(my_empty_manifest) +$(my_gen_check_manifest): $(my_empty_manifest) $(HOST_OUT_EXECUTABLES)/assemble_vintf BOARD_SEPOLICY_VERS=$(BOARD_SEPOLICY_VERS) \ VINTF_IGNORE_TARGET_FCM_VERSION=true \ $(HOST_OUT_EXECUTABLES)/assemble_vintf -i $(PRIVATE_SRC_FILE) -o $@ @@ -49,7 +50,6 @@ LOCAL_GEN_FILE_DEPENDENCIES += $(my_gen_check_manifest) LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(my_gen_check_manifest)" my_gen_check_manifest := -my_manifest_src_file := endif # DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE @@ -61,26 +61,65 @@ LOCAL_ASSEMBLE_VINTF_ENV_VARS := \ include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX) +# Product Compatibility Matrix + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/clear_vars.mk +LOCAL_MODULE := product_compatibility_matrix.xml + +ifndef DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE +my_framework_matrix_deps := +include $(BUILD_PHONY_PACKAGE) +else # DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE + +LOCAL_MODULE_STEM := compatibility_matrix.xml +LOCAL_PRODUCT_MODULE := true +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_RELATIVE_PATH := vintf + +# DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE specify an absolute path +LOCAL_GENERATED_SOURCES := $(DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE) + +# Enforce that DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE does not specify required HALs +# by checking it against an empty manifest. +LOCAL_GEN_FILE_DEPENDENCIES += $(my_empty_manifest) +LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(my_empty_manifest)" + +my_framework_matrix_deps := $(LOCAL_MODULE) + +include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX) + +endif # DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE + my_system_matrix_deps := \ framework_compatibility_matrix.legacy.xml \ framework_compatibility_matrix.1.xml \ framework_compatibility_matrix.2.xml \ framework_compatibility_matrix.3.xml \ framework_compatibility_matrix.current.xml \ - framework_compatibility_matrix.device.xml + framework_compatibility_matrix.device.xml \ -# Phony target that installs all framework compatibility matrix files +my_framework_matrix_deps += \ + $(my_system_matrix_deps) + +# Phony target that installs all system compatibility matrix files include $(CLEAR_VARS) -LOCAL_MODULE := framework_compatibility_matrix.xml +LOCAL_MODULE := system_compatibility_matrix.xml LOCAL_REQUIRED_MODULES := $(my_system_matrix_deps) include $(BUILD_PHONY_PACKAGE) +# Phony target that installs all framework compatibility matrix files (system + product) +include $(CLEAR_VARS) +LOCAL_MODULE := framework_compatibility_matrix.xml +LOCAL_REQUIRED_MODULES := $(my_framework_matrix_deps) +include $(BUILD_PHONY_PACKAGE) + # Final Framework Compatibility Matrix for OTA include $(CLEAR_VARS) include $(LOCAL_PATH)/clear_vars.mk LOCAL_MODULE := verified_assembled_system_matrix.xml LOCAL_MODULE_PATH := $(PRODUCT_OUT) -LOCAL_REQUIRED_MODULES := $(my_system_matrix_deps) +LOCAL_REQUIRED_MODULES := $(my_framework_matrix_deps) LOCAL_GENERATED_SOURCES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES)) LOCAL_ADD_VBMETA_VERSION_OVERRIDE := true @@ -97,4 +136,6 @@ include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX) BUILT_SYSTEM_MATRIX := $(LOCAL_BUILT_MODULE) my_system_matrix_deps := +my_framework_matrix_deps := +my_empty_manifest := BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := diff --git a/compatibility_matrices/CleanSpec.mk b/compatibility_matrices/CleanSpec.mk new file mode 100644 index 0000000000..9b150ede48 --- /dev/null +++ b/compatibility_matrices/CleanSpec.mk @@ -0,0 +1,47 @@ +# Copyright 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vintf/compatibility_matrix.device.xml) diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 049dfa4c34..89855a0e65 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -121,7 +121,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.cas</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IMediaCasService</name> <instance>default</instance> @@ -345,7 +345,8 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.radio</name> - <version>1.4</version> + <!-- Todo<b/123249760> Allow only 1.4 for Q--> + <version>1.3-4</version> <interface> <name>IRadio</name> <instance>slot1</instance> @@ -442,7 +443,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.usb</name> - <version>1.0-1</version> + <version>1.0-2</version> <interface> <name>IUsb</name> <instance>default</instance> diff --git a/compatibility_matrices/compatibility_matrix.mk b/compatibility_matrices/compatibility_matrix.mk index bafc84b57b..d22e51044d 100644 --- a/compatibility_matrices/compatibility_matrix.mk +++ b/compatibility_matrices/compatibility_matrix.mk @@ -17,7 +17,8 @@ ##### Input Variables: # LOCAL_MODULE: required. Module name for the build system. # LOCAL_MODULE_CLASS: optional. Default is ETC. -# LOCAL_MODULE_PATH: optional. Path of output file. Default is $(TARGET_OUT)/etc/vintf. +# LOCAL_MODULE_PATH / LOCAL_MODULE_RELATIVE_PATH: required. (Relative) path of output file. +# If not defined, LOCAL_MODULE_RELATIVE_PATH will be "vintf". # LOCAL_MODULE_STEM: optional. Name of output file. Default is $(LOCAL_MODULE). # LOCAL_SRC_FILES: required. Local source files provided to assemble_vintf # (command line argument -i). @@ -48,7 +49,9 @@ LOCAL_MODULE_CLASS := ETC endif ifndef LOCAL_MODULE_PATH -LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf +ifndef LOCAL_MODULE_RELATIVE_PATH +$(error Either LOCAL_MODULE_PATH or LOCAL_MODULE_RELATIVE_PATH must be defined.) +endif endif GEN := $(local-generated-sources-dir)/$(LOCAL_MODULE_STEM) diff --git a/configstore/1.2/ISurfaceFlingerConfigs.hal b/configstore/1.2/ISurfaceFlingerConfigs.hal index 7e5f706c02..431b3fc479 100644 --- a/configstore/1.2/ISurfaceFlingerConfigs.hal +++ b/configstore/1.2/ISurfaceFlingerConfigs.hal @@ -15,7 +15,7 @@ */ package android.hardware.configstore@1.2; -import android.hardware.graphics.common@1.1::PixelFormat; +import android.hardware.graphics.common@1.2::PixelFormat; import android.hardware.graphics.common@1.2::Dataspace; import @1.1::ISurfaceFlingerConfigs; import @1.0::OptionalBool; diff --git a/configstore/1.2/default/SurfaceFlingerConfigs.cpp b/configstore/1.2/default/SurfaceFlingerConfigs.cpp index 2daca30e28..8d710041a8 100644 --- a/configstore/1.2/default/SurfaceFlingerConfigs.cpp +++ b/configstore/1.2/default/SurfaceFlingerConfigs.cpp @@ -30,8 +30,8 @@ namespace configstore { namespace V1_2 { namespace implementation { -using ::android::hardware::graphics::common::V1_1::PixelFormat; using ::android::hardware::graphics::common::V1_2::Dataspace; +using ::android::hardware::graphics::common::V1_2::PixelFormat; // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation. Return<void> SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) { diff --git a/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp index 881b591284..d7f4dcf75f 100644 --- a/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp +++ b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp @@ -31,10 +31,10 @@ using ::android::hardware::Void; using ::android::hardware::configstore::V1_0::OptionalBool; using ::android::hardware::configstore::V1_0::OptionalInt64; using ::android::hardware::configstore::V1_0::OptionalUInt64; -using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs; using ::android::hardware::configstore::V1_2::DisplayPrimaries; -using ::android::hardware::graphics::common::V1_1::PixelFormat; +using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs; using ::android::hardware::graphics::common::V1_2::Dataspace; +using ::android::hardware::graphics::common::V1_2::PixelFormat; #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) diff --git a/current.txt b/current.txt index 3b873068d0..478cbc58c5 100644 --- a/current.txt +++ b/current.txt @@ -399,8 +399,9 @@ b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardwar 417ab60fe1ef786778047e4486f3d868ebce570d91addd8fe4251515213072de android.hardware.neuralnetworks@1.0::types e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types 1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse -271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types +ed9da80ec0c96991fd03f0a46107815d0e50f764656e49dba4980fa5c31d5bc3 android.hardware.radio@1.0::types 1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio +cd1757867a5e3a3faa362e785239515870d1a3c9ce756c6f0cf0f0fd8aac2547 android.hardware.radio@1.2::types e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types 3d01e29e8129186f7567c4f9c8bee7480a0768e587b1be9b28adb0a6cbec6bf2 android.hardware.tv.cec@1.0::types 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types diff --git a/drm/1.2/IDrmFactory.hal b/drm/1.2/IDrmFactory.hal index c94e4bbcd3..682889c22a 100644 --- a/drm/1.2/IDrmFactory.hal +++ b/drm/1.2/IDrmFactory.hal @@ -17,6 +17,7 @@ package android.hardware.drm@1.2; import @1.1::IDrmFactory; import @1.1::IDrmPlugin; +import @1.1::SecurityLevel; /** * IDrmFactory is the main entry point for interacting with a vendor's @@ -35,4 +36,16 @@ import @1.1::IDrmPlugin; */ interface IDrmFactory extends @1.1::IDrmFactory { + /** + * Determine if a specific security level is supported by the device. + * This method only differs from @1.0 isCryptoSchemeSupported + * by the addition of a security level. + * + * @param uuid identifies the crypto scheme in question + * @param mimeType identifies the mime type in question + * @param securityLevel specifies the security level required + * @return isSupported must be true only if the scheme is supported + */ + isCryptoSchemeSupported_1_2(uint8_t[16] uuid, string mimeType, + @1.1::SecurityLevel securityLevel) generates(bool isSupported); }; diff --git a/gnss/1.0/default/GnssBatching.cpp b/gnss/1.0/default/GnssBatching.cpp index 02b38cb635..f2e2e45025 100644 --- a/gnss/1.0/default/GnssBatching.cpp +++ b/gnss/1.0/default/GnssBatching.cpp @@ -20,7 +20,7 @@ #include <Gnss.h> // for wakelock consolidation #include <GnssUtils.h> -#include <cutils/log.h> // for ALOGE +#include <android/log.h> // for ALOGE #include <vector> namespace android { diff --git a/gnss/1.0/default/ThreadCreationWrapper.h b/gnss/1.0/default/ThreadCreationWrapper.h index df0a9e4a98..f401ce2cee 100644 --- a/gnss/1.0/default/ThreadCreationWrapper.h +++ b/gnss/1.0/default/ThreadCreationWrapper.h @@ -17,9 +17,9 @@ #ifndef ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H #define ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H +#include <log/log.h> #include <pthread.h> #include <vector> -#include <cutils/log.h> typedef void (*threadEntryFunc)(void* ret); diff --git a/gnss/2.0/IGnssMeasurementCallback.hal b/gnss/2.0/IGnssMeasurementCallback.hal index 226934e876..fc4446571e 100644 --- a/gnss/2.0/IGnssMeasurementCallback.hal +++ b/gnss/2.0/IGnssMeasurementCallback.hal @@ -23,48 +23,48 @@ import @1.1::IGnssMeasurementCallback; interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { /** * Enumeration of available values for the GNSS Measurement's code type. Similar to the - * Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table A2 at the Rinex 3.03 + * Attribute field described in RINEX 3.03, e.g., in Tables 4-10, and Table A2 at the RINEX 3.03 * Update 1 Document. */ enum GnssMeasurementCodeType : uint8_t { /** GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA. */ - CODE_TYPE_A = 0, + A = 0, /** GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB. */ - CODE_TYPE_B = 1, + B = 1, /** * GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS * L1 C/A, QZSS L1 C/A, IRNSS L5C. */ - CODE_TYPE_C = 2, + C = 2, /** * GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 * I, BDS B1 I, BDS B2 I, BDS B3 I. */ - CODE_TYPE_I = 3, + I = 3, /** GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), LEX(6) L. */ - CODE_TYPE_L = 4, + L = 4, /** GPS L1M, GPS L2M. */ - CODE_TYPE_M = 5, + M = 5, /** GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P. */ - CODE_TYPE_P = 6, + P = 6, /** * GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 * Q, BDS B1 Q, BDS B2 Q, BDS B3 Q. */ - CODE_TYPE_Q = 7, + Q = 7, /** GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), LEX(6) S. */ - CODE_TYPE_S = 8, + S = 8, /** GPS L1 Z-tracking, GPS L2 Z-tracking. */ - CODE_TYPE_W = 9, + W = 9, /** * GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO @@ -72,16 +72,366 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS * B3 (I+Q), IRNSS L5 (B+C). */ - CODE_TYPE_X = 10, + X = 10, /** GPS L1Y, GPS L2Y. */ - CODE_TYPE_Y = 11, + Y = 11, /** GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF. */ - CODE_TYPE_Z = 12, + Z = 12, /** GPS L1 codeless, GPS L2 codeless. */ - CODE_TYPE_CODELESS = 13 + N = 13, + + /** + * Other code type that does not belong to any of the above code types. + * + * This code type is used in the case that the above code types do not cover all the code + * types introduced in a new version of RINEX standard. When this code type is set, the + * field GnssMeasurement.otherCodeTypeName must specify the new code type. + */ + OTHER = 255 + }; + + /** + * Flags indicating the GNSS measurement state. + * + * <p>The expected behavior here is for GNSS HAL to set all the flags that apply. For example, + * if the state for a satellite is only C/A code locked and bit synchronized, and there is still + * millisecond ambiguity, the state must be set as: + * + * STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_MSEC_AMBIGUOUS + * + * <p>If GNSS is still searching for a satellite, the corresponding state must be set to + * STATE_UNKNOWN(0). + * + * <p>In @2.0::IGnssMeasurementCallback.GnssMeasurement, v1_1.v1_0.receivedSvTimeInNs, the + * received satellite time, is relative to the beginning of the system week for all + * constellations except for Glonass where it is relative to the beginning of the Glonass system + * day. + * + * <p>The table below indicates the valid range of the received GNSS satellite time. These + * ranges depend on the constellation and code being tracked and the state of the tracking + * algorithms given by the getState method. If the state flag is set, then the valid measurement + * range is zero to the value in the table. The state flag with the widest range indicates the + * range of the received GNSS satellite time value. + * + * <table> + * <thead> + * <tr> + * <td /> + * <td colspan="3"><strong>GPS/QZSS</strong></td> + * <td><strong>GLNS</strong></td> + * <td colspan="2"><strong>BDS</strong></td> + * <td colspan="3"><strong>GAL</strong></td> + * <td><strong>SBAS</strong></td> + * </tr> + * <tr> + * <td><strong>State Flag</strong></td> + * <td><strong>L1 C/A</strong></td> + * <td><strong>L5I</strong></td> + * <td><strong>L5Q</strong></td> + * <td><strong>L1OF</strong></td> + * <td><strong>B1I (D1)</strong></td> + * <td><strong>B1I (D2)</strong></td> + * <td><strong>E1B</strong></td> + * <td><strong>E1C</strong></td> + * <td><strong>E5AQ</strong></td> + * <td><strong>L1 C/A</strong></td> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td> + * <strong>STATE_UNKNOWN</strong> + * </td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_CODE_LOCK</strong> + * </td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>-</td> + * <td>-</td> + * <td>1 ms</td> + * <td>1 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SYMBOL_SYNC</strong> + * </td> + * <td>20 ms (optional)</td> + * <td>10 ms</td> + * <td>1 ms (optional)</td> + * <td>10 ms</td> + * <td>20 ms (optional)</td> + * <td>2 ms</td> + * <td>4 ms (optional)</td> + * <td>4 ms (optional)</td> + * <td>1 ms (optional)</td> + * <td>2 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BIT_SYNC</strong> + * </td> + * <td>20 ms</td> + * <td>20 ms</td> + * <td>1 ms (optional)</td> + * <td>20 ms</td> + * <td>20 ms</td> + * <td>-</td> + * <td>8 ms</td> + * <td>-</td> + * <td>1 ms (optional)</td> + * <td>4 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SUBFRAME_SYNC</strong> + * </td> + * <td>6s</td> + * <td>6s</td> + * <td>-</td> + * <td>2 s</td> + * <td>6 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_TOW_DECODED</strong> + * </td> + * <td colspan="2">1 week</td> + * <td>-</td> + * <td>1 day</td> + * <td colspan="2">1 week</td> + * <td colspan="2">1 week</td> + * <td>-</td> + * <td>1 week</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_TOW_KNOWN</strong> + * </td> + * <td colspan="3">1 week</td> + * <td>1 day</td> + * <td colspan="2">1 week</td> + * <td colspan="3">1 week</td> + * <td>1 week</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_STRING_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_TOD_DECODED</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 day</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_TOD_KNOWN</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 day</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BDS_D2_BIT_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BDS_D2_SUBFRAME_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>600 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1BC_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>4 ms</td> + * <td>4 ms</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1C_2ND_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_2ND_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>10 ms (optional)</td> + * <td>20 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms (optional)</td> + * <td>100 ms</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1B_PAGE_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SBAS_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 s</td> + * </tr> + * </tbody> + * </table> + * + * <p>Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has + * been determined from other sources. If TOW decoded is set then TOW Known must also be set. + * + * <p>Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be + * set accordingly, in the 'state' field. This value must be populated if 'state' != + * STATE_UNKNOWN. + * + * <p>Note on optional flags: + * <ul> + * <li> For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the + * same as the bit length. + * <li> For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are + * implied by STATE_CODE_LOCK. + * <li> STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC. + * <li> STATE_2ND_CODE_LOCK for E1C is optional since it is implied by + * STATE_GAL_E1C_2ND_CODE_LOCK. + * <li> For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by + * STATE_GAL_E1BC_CODE_LOCK. + * </ul> + * + */ + @export(name="", value_prefix="GNSS_MEASUREMENT_") + enum GnssMeasurementState : uint32_t { + STATE_UNKNOWN = 0, + STATE_CODE_LOCK = 1 << 0, + STATE_BIT_SYNC = 1 << 1, + STATE_SUBFRAME_SYNC = 1 << 2, + STATE_TOW_DECODED = 1 << 3, + STATE_MSEC_AMBIGUOUS = 1 << 4, + STATE_SYMBOL_SYNC = 1 << 5, + STATE_GLO_STRING_SYNC = 1 << 6, + STATE_GLO_TOD_DECODED = 1 << 7, + STATE_BDS_D2_BIT_SYNC = 1 << 8, + STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9, + STATE_GAL_E1BC_CODE_LOCK = 1 << 10, + STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11, + STATE_GAL_E1B_PAGE_SYNC = 1 << 12, + STATE_SBAS_SYNC = 1 << 13, + STATE_TOW_KNOWN = 1 << 14, + STATE_GLO_TOD_KNOWN = 1 << 15, + STATE_2ND_CODE_LOCK = 1 << 16, }; /** @@ -96,6 +446,10 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * quarter cycle offset as they do when transmitted from the satellites. If the measurement * is from a combination of the in-phase and quadrature phase components, then the alignment * of the phase measurement will be aligned to the in-phase component. + * + * In this version of the HAL, the field 'state' in the v1_1.v1_0 struct is deprecated, and + * is no longer used by the framework. The satellite sync state is instead reported in + * @2.0::IGnssMeasurementCallback.GnssMeasurement.state. */ @1.1::IGnssMeasurementCallback.GnssMeasurement v1_1; @@ -106,6 +460,27 @@ interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { * in-order to properly apply code specific corrections to the psuedorange measurements. */ GnssMeasurementCodeType codeType; + + /** + * The name of the code type when codeType is OTHER. + * + * This is used to specify the observation descriptor defined in GNSS Observation Data File + * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03, + * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for + * "A channel"). In the future, if for instance a code "G" was added in the official RINEX + * standard, "G" could be specified here. + */ + string otherCodeTypeName; + + /** + * Per satellite sync state. It represents the current sync state for the associated + * satellite. + * + * Based on the sync state, the receivedSvTimeInNs field must be interpreted accordingly. + * + * This value is mandatory. + */ + bitfield<GnssMeasurementState> state; }; /** diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp index dc23db3163..0f707b4d4a 100644 --- a/gnss/2.0/default/GnssMeasurement.cpp +++ b/gnss/2.0/default/GnssMeasurement.cpp @@ -26,7 +26,7 @@ namespace implementation { using GnssConstellationType = V1_0::GnssConstellationType; using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; -using GnssMeasurementState = V1_0::IGnssMeasurementCallback::GnssMeasurementState; +using GnssMeasurementState = V2_0::IGnssMeasurementCallback::GnssMeasurementState; sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr; @@ -97,11 +97,6 @@ GnssData GnssMeasurement::getMockMeasurement() { .svid = (int16_t)6, .constellation = GnssConstellationType::GLONASS, .timeOffsetNs = 0.0, - .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, .receivedSvTimeInNs = 8195997131077, .receivedSvTimeUncertaintyInNs = 15, .cN0DbHz = 30.0, @@ -116,8 +111,14 @@ GnssData GnssMeasurement::getMockMeasurement() { V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN}; V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0}; V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = { - .v1_1 = measurement_1_1, - .codeType = IGnssMeasurementCallback::GnssMeasurementCodeType::CODE_TYPE_C}; + .v1_1 = measurement_1_1, + .codeType = IGnssMeasurementCallback::GnssMeasurementCodeType::C, + .otherCodeTypeName = "", + .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}; hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1); measurements[0] = measurement_2_0; 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 552cf1b5b1..48f2be8802 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -185,10 +185,16 @@ TEST_F(GnssHalTest, TestGnssMeasurementCodeType) { ASSERT_TRUE(last_measurement_.measurements.size() > 0); for (auto measurement : last_measurement_.measurements) { ASSERT_TRUE( - (int)measurement.codeType >= - (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_A && - (int)measurement.codeType <= - (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_CODELESS); + ((int)measurement.codeType >= + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::A && + (int)measurement.codeType <= + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::N) || + (int)measurement.codeType == + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::OTHER); + if ((int)measurement.codeType == + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::OTHER) { + ASSERT_NE(measurement.otherCodeTypeName, ""); + } } iGnssMeasurement->close(); diff --git a/gnss/measurement_corrections/1.0/types.hal b/gnss/measurement_corrections/1.0/types.hal index 5f207347f2..edf26bf7c0 100644 --- a/gnss/measurement_corrections/1.0/types.hal +++ b/gnss/measurement_corrections/1.0/types.hal @@ -79,18 +79,35 @@ struct SingleSatCorrection { * toaGpsNanosecondsOfWeek */ struct MeasurementCorrections { - /** Represents latitude in degrees. */ + /** Represents latitude in degrees at which the corrections are computed.. */ double latitudeDegrees; - /** Represents longitude in degrees. */ + /** Represents longitude in degrees at which the corrections are computed.. */ double longitudeDegrees; /** - * Represents altitude in meters above the WGS 84 reference ellipsoid. + * Represents altitude in meters above the WGS 84 reference ellipsoid at which the corrections + * are computed. */ double altitudeMeters; - /** Time Of Applicability, GPS time of week */ + /** + * Represents the horizontal uncertainty (68% confidence) in meters on the device position at + * which the corrections are provided. + * + * This value is useful for example to judge how accurate the provided corrections are. + */ + double horizontalPositionUncertaintyMeters; + + /** + * Represents the vertical uncertainty (68% confidence) in meters on the device position at + * which the corrections are provided. + * + * This value is useful for example to judge how accurate the provided corrections are. + */ + double verticalPositionUncertaintyMeters; + + /** Time Of Applicability, GPS time of week in nanoseconds. */ uint64_t toaGpsNanosecondsOfWeek; /** diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc index 6eee71f6e7..a2a881a8f4 100644 --- a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc +++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc @@ -1,5 +1,6 @@ service vendor.gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service class hal animation + interface android.hardware.graphics.allocator@2.0::IAllocator default user system group graphics drmrpc capabilities SYS_NICE diff --git a/graphics/allocator/3.0/IAllocator.hal b/graphics/allocator/3.0/IAllocator.hal index 3651e91dad..34b08e7c61 100644 --- a/graphics/allocator/3.0/IAllocator.hal +++ b/graphics/allocator/3.0/IAllocator.hal @@ -30,6 +30,9 @@ interface IAllocator { /** * Allocates buffers with the properties specified by the descriptor. * + * Allocations should be optimized for usage bits provided in the + * descriptor. + * * @param descriptor Properties of the buffers to allocate. This must be * obtained from IMapper::createDescriptor(). * @param count The number of buffers to allocate. diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal index 392a12e2e4..3da6176342 100644 --- a/graphics/common/1.2/types.hal +++ b/graphics/common/1.2/types.hal @@ -25,7 +25,8 @@ import @1.1::PixelFormat; /** * Hdr */ -@export(name="android_hdr_v1_2_t", value_prefix="HAL_HDR_") +@export(name="android_hdr_v1_2_t", value_prefix="HAL_HDR_", + export_parent="false") enum Hdr : @1.0::Hdr { HDR10_PLUS = 4, }; @@ -41,6 +42,13 @@ enum Dataspace : @1.1::Dataspace { * Use full range, sRGB transfer and BT2020 standard */ DISPLAY_BT2020 = STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL, + + /** + * ISO 16684-1:2011(E) + * + * Embedded depth metadata following the dynamic depth specification. + */ + DYNAMIC_DEPTH = 0x1002, }; enum ColorMode : @1.1::ColorMode { @@ -96,3 +104,18 @@ struct HardwareBuffer { */ typedef int32_t[4] Rect; +/** + * Pixel formats for graphics buffers. + */ +@export(name="android_pixel_format_v1_2_t", value_prefix="HAL_PIXEL_FORMAT_", + export_parent="false") +enum PixelFormat : @1.1::PixelFormat { + /** + * 24-bit format that has 8-bit H, S, and V components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + HSV_888 = 0x37, +}; diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal index cf78dea532..a3b7792c05 100644 --- a/graphics/composer/2.3/IComposerClient.hal +++ b/graphics/composer/2.3/IComposerClient.hal @@ -17,7 +17,7 @@ package android.hardware.graphics.composer@2.3; import android.hardware.graphics.common@1.1::RenderIntent; -import android.hardware.graphics.common@1.1::PixelFormat; +import android.hardware.graphics.common@1.2::PixelFormat; import android.hardware.graphics.common@1.2::ColorMode; import android.hardware.graphics.common@1.2::Dataspace; import android.hardware.graphics.common@1.2::Hdr; diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h index edc203eb1d..a272e72d74 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h @@ -123,7 +123,7 @@ class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interfac Return<void> getDisplayedContentSamplingAttributes( uint64_t display, IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override { - common::V1_1::PixelFormat format; + PixelFormat format; common::V1_2::Dataspace dataspace; hidl_bitfield<IComposerClient::FormatColorComponent> componentMask; Error error = diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h index 882621f086..a0812ad9a7 100644 --- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h @@ -25,11 +25,11 @@ namespace composer { namespace V2_3 { namespace hal { -using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; +using common::V1_2::PixelFormat; using V2_1::Display; using V2_1::Error; using V2_1::Layer; diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h index 9fb6d4bf7d..41e333ac5e 100644 --- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h @@ -34,11 +34,11 @@ namespace passthrough { namespace detail { -using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; +using common::V1_2::PixelFormat; using V2_1::Display; using V2_1::Error; @@ -91,14 +91,16 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> { Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) override { - return getClientTargetSupport_2_2(display, width, height, format, + return getClientTargetSupport_2_2(display, width, height, + static_cast<common::V1_1::PixelFormat>(format), static_cast<common::V1_1::Dataspace>(dataspace)); } Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, Dataspace* outDataspace) override { return getReadbackBufferAttributes( - display, outFormat, reinterpret_cast<common::V1_1::Dataspace*>(outDataspace)); + display, reinterpret_cast<common::V1_1::PixelFormat*>(outFormat), + reinterpret_cast<common::V1_1::Dataspace*>(outDataspace)); } Error getDisplayIdentificationData(Display display, uint8_t* outPort, diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h index 7add322282..ad4ef0b51e 100644 --- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h +++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h @@ -32,11 +32,11 @@ namespace composer { namespace V2_3 { namespace vts { -using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::Hdr; +using common::V1_2::PixelFormat; using V2_1::Display; using V2_1::Error; using V2_3::IComposer; diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp index dca7406c10..de74e28cc7 100644 --- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp +++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp @@ -36,10 +36,10 @@ namespace vts { namespace { using common::V1_0::BufferUsage; -using common::V1_1::PixelFormat; using common::V1_1::RenderIntent; using common::V1_2::ColorMode; using common::V1_2::Dataspace; +using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; using mapper::V2_0::vts::Gralloc; @@ -492,9 +492,6 @@ TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) { } TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) { - using common::V1_1::PixelFormat; - using common::V1_2::Dataspace; - int constexpr invalid = -1; auto format = static_cast<PixelFormat>(invalid); auto dataspace = static_cast<Dataspace>(invalid); diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h index 08d604e906..c9836e5447 100644 --- a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h +++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h @@ -28,7 +28,7 @@ namespace passthrough { using V2_0::BufferDescriptor; using V2_0::Error; -using android::hardware::graphics::common::V1_0::BufferUsage; +using android::hardware::graphics::common::V1_1::BufferUsage; namespace detail { @@ -72,6 +72,8 @@ class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> { Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo, BufferDescriptor* outDescriptor) override { + if (gralloc1UsageUnsupported(descriptorInfo.usage)) + return Error::BAD_DESCRIPTOR; return createDescriptor( V2_0::IMapper::BufferDescriptorInfo{ descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount, @@ -163,6 +165,16 @@ class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> { return consumerUsage; } + static bool gralloc1UsageUnsupported(uint64_t usage) { + // Certain newer public usage bits should not be used with gralloc1. + // We use a blacklist instead of a whitelist here in order to avoid + // breaking private usage flags. + constexpr uint64_t unsupportedMask = BufferUsage::GPU_CUBE_MAP | + BufferUsage::GPU_MIPMAP_COMPLETE; + + return usage & unsupportedMask; + } + private: using BaseType2_0 = V2_0::passthrough::detail::Gralloc1HalImpl<Hal>; using BaseType2_0::createDescriptor; diff --git a/graphics/mapper/3.0/IMapper.hal b/graphics/mapper/3.0/IMapper.hal index e399045e7d..a0e4d7afc7 100644 --- a/graphics/mapper/3.0/IMapper.hal +++ b/graphics/mapper/3.0/IMapper.hal @@ -183,6 +183,9 @@ interface IMapper { * buffer content in an indeterminate state or returning an error are both * acceptable. * + * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must + * "lock in place". The buffers must be directly accessible via mapping. + * * The client must not modify the content of the buffer outside of * @p accessRegion, and the device need not guarantee that content outside * of @p accessRegion is valid for reading. The result of reading or writing @@ -193,6 +196,12 @@ interface IMapper { * memory. This address will represent the top-left corner of the entire * buffer, even if @p accessRegion does not begin at the top-left corner. * + * On success, bytesPerPixel must contain the number of bytes per pixel in + * the buffer. If the bytesPerPixel is unknown or variable, a value of -1 + * should be returned. bytesPerStride must contain the bytes per stride of + * the buffer. If the bytesPerStride is unknown or variable, a value of -1 + * should be returned. + * * @param buffer Buffer to lock. * @param cpuUsage CPU usage flags to request. See +ndk * libnativewindow#AHardwareBuffer_UsageFlags for possible values. @@ -211,13 +220,17 @@ interface IMapper { * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note * that locking may succeed at a later time. * @return data CPU-accessible pointer to the buffer data. + * @return bytesPerPixel the number of bytes per pixel in the buffer + * @return bytesPerStride the number of bytes per stride of the buffer */ lock(pointer buffer, uint64_t cpuUsage, Rect accessRegion, handle acquireFence) generates (Error error, - pointer data); + pointer data, + int32_t bytesPerPixel, + int32_t bytesPerStride); /** * Locks a YCbCr buffer for the specified CPU usage. @@ -272,5 +285,20 @@ interface IMapper { */ unlock(pointer buffer) generates (Error error, handle releaseFence); + /** + * Test whether the given BufferDescriptorInfo is allocatable. + * + * If this function returns true, it means that a buffer with the given + * description can be allocated on this implementation, unless resource + * exhaustion occurs. If this function returns false, it means that the + * allocation of the given description will never succeed. + * + * @param description the description of the buffer + * @return supported whether the description is supported + */ + isSupported(BufferDescriptorInfo description) + generates (Error error, + bool supported); + }; diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp index 842840353c..f2b7594b3f 100644 --- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp +++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp @@ -164,7 +164,8 @@ void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { } void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence) { + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride) { auto buffer = const_cast<native_handle_t*>(bufferHandle); NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); @@ -175,11 +176,17 @@ void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, acquireFenceHandle = h; } + *outBytesPerPixel = -1; + *outBytesPerStride = -1; + void* data = nullptr; mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpData) { + [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel, + int32_t tmpBytesPerStride) { ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer; data = tmpData; + *outBytesPerPixel = tmpBytesPerPixel; + *outBytesPerStride = tmpBytesPerStride; }); if (acquireFence >= 0) { @@ -264,6 +271,15 @@ void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* ou }); } +bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) { + bool supported = false; + mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported"; + supported = tmpSupported; + }); + return supported; +} + } // namespace vts } // namespace V3_0 } // namespace mapper diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h index c94961c489..ba79ca42b7 100644 --- a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h +++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h @@ -68,7 +68,8 @@ class Gralloc { // in and out of the mapper. The ownership of the fd is always transferred // with each of these functions. void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const IMapper::Rect& accessRegion, int acquireFence); + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride); YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, const IMapper::Rect& accessRegion, int acquireFence); int unlock(const native_handle_t* bufferHandle); @@ -78,6 +79,8 @@ class Gralloc { void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, uint32_t* outNumInts); + bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); + private: void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp index 430a526851..cfae635658 100644 --- a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp +++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp @@ -298,8 +298,15 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { static_cast<int32_t>(info.height)}; int fence = -1; uint8_t* data; + int32_t bytesPerPixel = -1; + int32_t bytesPerStride = -1; ASSERT_NO_FATAL_FAILURE( - data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence))); + data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); + + // Valid return values are -1 for unsupported or the number bytes for supported which is >=0 + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); // RGBA_8888 size_t strideInBytes = stride * 4; @@ -312,9 +319,13 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + bytesPerPixel = -1; + bytesPerStride = -1; + // lock again for reading ASSERT_NO_FATAL_FAILURE( - data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence))); + data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); for (uint32_t y = 0; y < info.height; y++) { for (size_t i = 0; i < writeInBytes; i++) { EXPECT_EQ(static_cast<uint8_t>(y), data[i]); @@ -322,6 +333,9 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { data += strideInBytes; } + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); if (fence >= 0) { close(fence); @@ -426,6 +440,40 @@ TEST_F(GraphicsMapperHidlTest, UnlockNegative) { #endif } +/** + * Test IMapper::isSupported with required format RGBA_8888 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) { + const auto& info = mDummyDescriptorInfo; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with required format YV12 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with optional format Y16 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::Y16; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); +} + } // namespace } // namespace vts } // namespace V3_0 diff --git a/health/storage/1.0/default/Storage.cpp b/health/storage/1.0/default/Storage.cpp index 2e53c50899..561deaaed6 100644 --- a/health/storage/1.0/default/Storage.cpp +++ b/health/storage/1.0/default/Storage.cpp @@ -36,27 +36,20 @@ using base::Timer; using base::Trim; using base::WriteStringToFd; using base::WriteStringToFile; +using fs_mgr::Fstab; +using fs_mgr::ReadDefaultFstab; std::string getGarbageCollectPath() { - std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(), - fs_mgr_free_fstab); - struct fstab_rec* rec = NULL; - - for (int i = 0; i < fstab->num_entries; i++) { - if (fs_mgr_has_sysfs_path(&fstab->recs[i])) { - rec = &fstab->recs[i]; - break; + Fstab fstab; + ReadDefaultFstab(&fstab); + + for (const auto& entry : fstab) { + if (!entry.sysfs_path.empty()) { + return entry.sysfs_path + "/manual_gc"; } } - if (!rec) { - return ""; - } - - std::string path; - path.append(rec->sysfs_path); - path = path + "/manual_gc"; - return path; + return ""; } Return<void> Storage::garbageCollect(uint64_t timeoutSeconds, diff --git a/input/classifier/1.0/Android.bp b/input/classifier/1.0/Android.bp index c3c6fc6123..6815a513c1 100644 --- a/input/classifier/1.0/Android.bp +++ b/input/classifier/1.0/Android.bp @@ -7,29 +7,12 @@ hidl_interface { enabled: true, }, srcs: [ - "types.hal", "IInputClassifier.hal", ], interfaces: [ + "android.hardware.input.common@1.0", "android.hidl.base@1.0", ], - types: [ - "Action", - "Axis", - "Button", - "Classification", - "EdgeFlag", - "Flag", - "Meta", - "MotionEvent", - "PointerCoords", - "PointerProperties", - "PolicyFlag", - "Source", - "SourceClass", - "ToolType", - "VideoFrame", - ], gen_java: true, } diff --git a/input/classifier/1.0/IInputClassifier.hal b/input/classifier/1.0/IInputClassifier.hal index edc113807a..7397fea127 100644 --- a/input/classifier/1.0/IInputClassifier.hal +++ b/input/classifier/1.0/IInputClassifier.hal @@ -16,6 +16,9 @@ package android.hardware.input.classifier@1.0; +import android.hardware.input.common@1.0::Classification; +import android.hardware.input.common@1.0::MotionEvent; + interface IInputClassifier { /** @@ -23,4 +26,16 @@ interface IInputClassifier { */ classify(MotionEvent event) generates (Classification classification); + /** + * Called by the framework to reset the HAL internal state. The reset may be called + * to prevent an inconsistent stream of events to be sent to the HAL. + */ + reset(); + + /** + * Called by the framework to reset the HAL internal state for a specific device. + * The reset may be called once device reset is received by the framework. + */ + resetDevice(int32_t deviceId); + }; diff --git a/input/classifier/1.0/default/InputClassifier.cpp b/input/classifier/1.0/default/InputClassifier.cpp index c463361dcb..a78bbc5c94 100644 --- a/input/classifier/1.0/default/InputClassifier.cpp +++ b/input/classifier/1.0/default/InputClassifier.cpp @@ -21,7 +21,7 @@ #include <log/log.h> #include <utils/Timers.h> -using namespace android::hardware::input::classifier::V1_0; +using namespace android::hardware::input::common::V1_0; namespace android { namespace hardware { @@ -57,6 +57,18 @@ Return<Classification> InputClassifier::classify(const MotionEvent& event) { return Classification::NONE; } +Return<void> InputClassifier::reset() { + // We don't have any internal state in this example implementation, + // so no work needed here. + return Void(); +} + +Return<void> InputClassifier::resetDevice(int32_t /*deviceId*/) { + // We don't have any internal per-device state in this example implementation, + // so no work needed here. + return Void(); +} + } // namespace implementation } // namespace V1_0 } // namespace classifier diff --git a/input/classifier/1.0/default/InputClassifier.h b/input/classifier/1.0/default/InputClassifier.h index 0858ecbae0..eef370e706 100644 --- a/input/classifier/1.0/default/InputClassifier.h +++ b/input/classifier/1.0/default/InputClassifier.h @@ -31,8 +31,12 @@ using ::android::hardware::Return; struct InputClassifier : public IInputClassifier { // Methods from ::android::hardware::input::classifier::V1_0::IInputClassifier follow. - Return<Classification> classify( - const ::android::hardware::input::classifier::V1_0::MotionEvent& event) override; + + Return<android::hardware::input::common::V1_0::Classification> classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override; + + Return<void> reset() override; + Return<void> resetDevice(int32_t deviceId) override; }; } // namespace implementation diff --git a/input/common/1.0/Android.bp b/input/common/1.0/Android.bp new file mode 100644 index 0000000000..68a77f13d9 --- /dev/null +++ b/input/common/1.0/Android.bp @@ -0,0 +1,34 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.input.common@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "Action", + "Axis", + "Button", + "Classification", + "EdgeFlag", + "Flag", + "Meta", + "MotionEvent", + "PointerCoords", + "PointerProperties", + "PolicyFlag", + "Source", + "SourceClass", + "ToolType", + "VideoFrame", + ], + gen_java: true, +} + diff --git a/input/classifier/1.0/types.hal b/input/common/1.0/types.hal index 244ecd93b8..1a07f3b76d 100644 --- a/input/classifier/1.0/types.hal +++ b/input/common/1.0/types.hal @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.hardware.input.classifier@1.0; +package android.hardware.input.common@1.0; /** @@ -435,12 +435,12 @@ struct PointerCoords { }; enum SourceClass: uint8_t { - NONE = 1 << 0, - BUTTON = 1 << 1, - POINTER = 1 << 2, - NAVIGATION = 1 << 3, - POSITION = 1 << 4, - JOYSTICK = 1 << 5, + NONE = 0 << 0, + BUTTON = 1 << 0, + POINTER = 1 << 1, + NAVIGATION = 1 << 2, + POSITION = 1 << 3, + JOYSTICK = 1 << 4, }; /** diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp index 6fabbde992..7d3e6f25dc 100644 --- a/keymaster/3.0/default/KeymasterDevice.cpp +++ b/keymaster/3.0/default/KeymasterDevice.cpp @@ -19,7 +19,7 @@ #include "KeymasterDevice.h" -#include <cutils/log.h> +#include <log/log.h> #include <AndroidKeymaster3Device.h> #include <hardware/keymaster0.h> diff --git a/light/2.0/default/Android.bp b/light/2.0/default/Android.bp index 4e1242701f..b3c7c452fd 100644 --- a/light/2.0/default/Android.bp +++ b/light/2.0/default/Android.bp @@ -31,13 +31,11 @@ cc_library_shared { } -cc_binary { - name: "android.hardware.light@2.0-service", +cc_defaults { + name: "light_service_defaults", relative_install_path: "hw", defaults: ["hidl_defaults"], vendor: true, - init_rc: ["android.hardware.light@2.0-service.rc"], - srcs: ["service.cpp"], shared_libs: [ "liblog", @@ -58,3 +56,18 @@ cc_binary { }, }, } + +cc_binary { + name: "android.hardware.light@2.0-service", + defaults: ["light_service_defaults"], + init_rc: ["android.hardware.light@2.0-service.rc"], + srcs: ["service.cpp"], +} + +cc_binary { + name: "android.hardware.light@2.0-service-lazy", + overrides: ["android.hardware.light@2.0-service"], + defaults: ["light_service_defaults"], + init_rc: ["android.hardware.light@2.0-service-lazy.rc"], + srcs: ["serviceLazy.cpp"], +} diff --git a/light/2.0/default/android.hardware.light@2.0-service-lazy.rc b/light/2.0/default/android.hardware.light@2.0-service-lazy.rc new file mode 100644 index 0000000000..8a3a59c26a --- /dev/null +++ b/light/2.0/default/android.hardware.light@2.0-service-lazy.rc @@ -0,0 +1,9 @@ +service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service-lazy + interface android.hardware.light@2.0::ILight default + oneshot + disabled + class hal + user system + group system + # shutting off lights while powering-off + shutdown critical diff --git a/light/2.0/default/service.cpp b/light/2.0/default/service.cpp index 0fc4795f27..b50a2034f4 100644 --- a/light/2.0/default/service.cpp +++ b/light/2.0/default/service.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.light@2.0-service" - #include <android/hardware/light/2.0/ILight.h> #include <hidl/LegacySupport.h> #include <hwbinder/ProcessState.h> diff --git a/light/2.0/default/serviceLazy.cpp b/light/2.0/default/serviceLazy.cpp new file mode 100644 index 0000000000..5324f465b3 --- /dev/null +++ b/light/2.0/default/serviceLazy.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/hardware/light/2.0/ILight.h> +#include <hidl/LegacySupport.h> + +using android::hardware::defaultLazyPassthroughServiceImplementation; +using android::hardware::light::V2_0::ILight; + +int main() { + return defaultLazyPassthroughServiceImplementation<ILight>(); +} diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp index c37c22b4e2..56c78b2e6e 100644 --- a/media/c2/1.0/Android.bp +++ b/media/c2/1.0/Android.bp @@ -13,6 +13,7 @@ hidl_interface { "IComponentListener.hal", "IComponentStore.hal", "IConfigurable.hal", + "IInputSink.hal", "IInputSurface.hal", "IInputSurfaceConnection.hal", ], diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal index deb9255ecd..7fd551fc2b 100644 --- a/media/c2/1.0/IComponent.hal +++ b/media/c2/1.0/IComponent.hal @@ -22,13 +22,19 @@ import android.hardware.media.omx@1.0::IGraphicBufferSource; import IConfigurable; import IComponentInterface; import IComponentListener; +import IInputSurface; +import IInputSurfaceConnection; /** - * Interface for a Codec 2.0 component corresponding to API level 1.0 or - * below. Components have two states: stopped and running. The running - * state has three sub-states: executing, tripped and error. + * Interface for a Codec2 component corresponding to API level 1.0 or below. + * Components have two states: stopped and running. The running state has three + * sub-states: executing, tripped and error. + * + * All methods in `IComponent` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. */ -interface IComponent extends IComponentInterface { +interface IComponent { // METHODS AVAILABLE WHEN RUNNING // ========================================================================= @@ -38,44 +44,42 @@ interface IComponent extends IComponentInterface { * * This method must be supported in running (including tripped) states. * - * This method must return within 1ms - * - * It is acceptable for this method to return OK and return an error value - * using the onWorkDone() callback. + * It is acceptable for this method to return `OK` and return an error value + * using the IComponentListener::onWorkDone() callback. * - * @param workBundle WorkBundle object containing Works to queue to the - * component. + * @param workBundle `WorkBundle` object containing a list of `Work` objects + * to queue to the component. * @return status Status of the call, which may be - * - OK - Works in \p workBundle were successfully queued. - * - BAD_INDEX - Some component(s) in some Work do(es) not exist. - * - CANNOT_DO - The components are not tunneled. - * - NO_MEMORY - Not enough memory to queue \p workBundle. - * - CORRUPTED - Some unknown error prevented queuing the Works. - * (unexpected). + * - `OK` - Works in @p workBundle were successfully queued. + * - `BAD_INDEX` - Some component id in some `Worklet` is not valid. + * - `CANNOT_DO` - The components are not tunneled but some `Work` object + * contains tunneling information. + * - `NO_MEMORY` - Not enough memory to queue @p workBundle. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ queue(WorkBundle workBundle) generates (Status status); /** - * Discards and abandons any pending work for the component. + * Discards and abandons any pending `Work` items for the component. * * This method must be supported in running (including tripped) states. * - * This method must return within 5ms. - * - * Work that could be immediately abandoned/discarded must be returned in - * \p flushedWorks; this can be done in an arbitrary order. + * `Work` that could be immediately abandoned/discarded must be returned in + * @p flushedWorkBundle. The order in which queued `Work` items are + * discarded can be arbitrary. * - * Work that could not be abandoned or discarded immediately must be marked - * to be discarded at the earliest opportunity, and must be returned via - * the onWorkDone() callback. This must be completed within 500ms. + * `Work` that could not be abandoned or discarded immediately must be + * marked to be discarded at the earliest opportunity, and must be returned + * via IComponentListener::onWorkDone(). This must be completed within + * 500ms. * * @return status Status of the call, which may be - * - OK - The component has been successfully flushed. - * - TIMED_OUT - The flush could not be completed within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented flushing from - * completion. (unexpected) - * @return flushedWorkBundle WorkBundle object containing flushed Works. + * - `OK` - The component has been successfully flushed. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return flushedWorkBundle `WorkBundle` object containing flushed `Work` + * items. */ flush( ) generates ( @@ -87,42 +91,39 @@ interface IComponent extends IComponentInterface { * Drains the component, and optionally downstream components. This is a * signalling method; as such it does not wait for any work completion. * - * Marks last work item as "drain-till-here", so component is notified not - * to wait for further work before it processes work already queued. This - * method can also be used to set the end-of-stream flag after work has been - * queued. Client can continue to queue further work immediately after this - * method returns. + * The last `Work` item is marked as "drain-till-here", so the component is + * notified not to wait for further `Work` before it processes what is + * already queued. This method can also be used to set the end-of-stream + * flag after `Work` has been queued. Client can continue to queue further + * `Work` immediately after this method returns. * * This method must be supported in running (including tripped) states. * - * This method must return within 1ms. - * - * Work that is completed must be returned via the onWorkDone() callback. + * `Work` that is completed must be returned via + * IComponentListener::onWorkDone(). * * @param withEos Whether to drain the component with marking end-of-stream. * @return status Status of the call, which may be - * - OK - The drain request has been successfully recorded. - * - TIMED_OUT - The flush could not be completed within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented flushing from completion. - * (unexpected) + * - `OK` - The drain request has been successfully recorded. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ drain(bool withEos) generates (Status status); /** * Starts using a surface for output. * - * @param blockPoolId The id of the BlockPool to be associated with the - * output surface. - * @param surface A surface to use for codec output. + * This method must not block. + * + * @param blockPoolId Id of the `C2BlockPool` to be associated with the + * output surface. + * @param surface Output surface. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - CANNOT_DO - The component does not support an output surface. - * - REFUSED - The output surface cannot be accessed. - * - TIMED_OUT - The component could not be connected within the time - * limit. (unexpected) - * - CORRUPTED - Some unknown error prevented connecting the component. - * (unexpected) + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an output surface. + * - `REFUSED` - The output surface cannot be accessed. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ setOutputSurface( uint64_t blockPoolId, @@ -132,65 +133,101 @@ interface IComponent extends IComponentInterface { ); /** - * Starts using a persistent OMX input surface for a component. + * Starts using an input surface. + * + * The component must be in running state. + * + * @param inputSurface Input surface to connect to. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an input surface. + * - `BAD_STATE` - The component is not in running state. + * - `DUPLICATE` - The component is already connected to an input surface. + * - `REFUSED` - The input surface is already in use. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object, which can be used to + * query and configure properties of the connection. This cannot be + * null. + */ + connectToInputSurface( + IInputSurface inputSurface + ) generates ( + Status status, + IInputSurfaceConnection connection + ); + + /** + * Starts using an OMX input surface. * * The component must be in running state. * - * @param producer Producer component of an OMX persistent input surface. - * @param source Source component of an OMX persistent input surface. + * This method is similar to connectToInputSurface(), but it takes an OMX + * input surface (as a pair of `IGraphicBufferProducer` and + * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`. + * + * @param producer Producer component of an OMX input surface. + * @param source Source component of an OMX input surface. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - CANNOT_DO - The component does not support an input surface. - * - BAD_STATE - Component is not in running state. - * - DUPLICATE - The component is already connected to an input surface. - * - REFUSED - The input surface is already in use. - * - NO_MEMORY - Not enough memory to start the component. - * - TIMED_OUT - The component could not be connected within the time - * limit. (unexpected) - * - CORRUPTED - Some unknown error prevented connecting the component. - * (unexpected) + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an OMX input surface. + * - `BAD_STATE` - The component is not in running state. + * - `DUPLICATE` - The component is already connected to an input surface. + * - `REFUSED` - The input surface is already in use. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object, which can be used to + * query and configure properties of the connection. This cannot be + * null. */ connectToOmxInputSurface( IGraphicBufferProducer producer, IGraphicBufferSource source - ) generates (Status status); + ) generates ( + Status status, + IInputSurfaceConnection connection + ); /** * Stops using an input surface. * - * This call is used for both Codec 2.0 and OMX input surfaces. - * * The component must be in running state. * * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - CANNOT_DO - The component does not support an input surface. - * - BAD_STATE - Component is not in running state. - * - NOT_FOUND - The component is not connected to an input surface. - * - TIMED_OUT - The component could not be connected within the time - * limit. (unexpected) - * - CORRUPTED - Some unknown error prevented connecting the component. - * (unexpected) + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an input surface. + * - `BAD_STATE` - The component is not in running state. + * - `NOT_FOUND` - The component is not connected to an input surface. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ disconnectFromInputSurface() generates (Status Status); /** - * Creates a local block pool backed by the given allocator and returns its - * identifier. + * Creates a local `C2BlockPool` backed by the given allocator and returns + * its id. * - * This call must return within 100 msec. + * The returned @p blockPoolId is the only way the client can refer to a + * `C2BlockPool` object in the component. The id can be passed to + * setOutputSurface() or used in some C2Param objects later. * - * @param allocatorId The Codec 2.0 allocator ID + * The created `C2BlockPool` object can be destroyed by calling + * destroyBlockPool(), reset() or release(). reset() and release() must + * destroy all `C2BlockPool` objects that have been created. + * + * @param allocatorId Id of a `C2Allocator`. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - NO_MEMORY - Not enough memory to create the pool. - * - BAD_VALUE - Invalid allocator. - * - TIMED_OUT - The pool could not be created within the time - * limit. (unexpected) - * - CORRUPTED - Some unknown error prevented creating the pool. - * (unexpected) - * @return blockPoolId The Codec 2.0 blockpool ID for the created pool. - * @return configurable Configuration interface for the created pool. + * - `OK` - The operation completed successfully. + * - `NO_MEMORY` - Not enough memory to create the pool. + * - `BAD_VALUE` - @p allocatorId is not recognized. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return blockPoolId Id of the created C2BlockPool object. This may be + * used in setOutputSurface() if the allocator + * @return configurable Configuration interface for the created pool. This + * must not be null. */ createBlockPool(uint32_t allocatorId) generates ( Status status, @@ -201,17 +238,13 @@ interface IComponent extends IComponentInterface { /** * Destroys a local block pool previously created by createBlockPool(). * - * This call must return within 100 msec. - * - * @param blockPoolId The block pool id previously returned by + * @param blockPoolId Id of a `C2BlockPool` that was previously returned by * createBlockPool(). * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - NOT_FOUND - The supplied blockPoolId is not valid. - * - TIMED_OUT - The pool could not be destroyedwithin the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented destruction of the pool. - * (unexpected) + * - `OK` - The operation completed successfully. + * - `NOT_FOUND` - The supplied blockPoolId is not valid. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ destroyBlockPool(uint64_t blockPoolId) generates (Status status); @@ -223,28 +256,24 @@ interface IComponent extends IComponentInterface { * * This method must be supported in stopped state as well as tripped state. * - * If the return value is OK, the component must be in the running state. - * If the return value is BAD_STATE or DUPLICATE, no state change is - * expected as a response to this call. - * Otherwise, the component must be in the stopped state. + * If the return value is `OK`, the component must be in the running state. + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. Otherwise, the component must be in + * the stopped state. * * If a component is in the tripped state and start() is called while the - * component configuration still results in a trip, start must succeed and - * a new onTripped callback must be used to communicate the configuration + * component configuration still results in a trip, start() must succeed and + * a new onTripped() callback must be used to communicate the configuration * conflict that results in the new trip. * - * This method must return within 500ms. - * * @return status Status of the call, which may be - * - OK - The component has started successfully. - * - BAD_STATE - Component is not in stopped or tripped state. - * - DUPLICATE - When called during another start call from another - * thread. - * - NO_MEMORY - Not enough memory to start the component. - * - TIMED_OUT - The component could not be started within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented starting the component. - * (unexpected) + * - `OK` - The component has started successfully. + * - `BAD_STATE` - Component is not in stopped or tripped state. + * - `DUPLICATE` - When called during another start call from another + * thread. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ start() generates (Status status); @@ -255,22 +284,22 @@ interface IComponent extends IComponentInterface { * * This method must return withing 500ms. * - * Upon this call, all pending work must be abandoned. - * If the return value is BAD_STATE or DUPLICATE, no state change is - * expected as a response to this call. - * For all other return values, the component must be in the stopped state. + * Upon this call, all pending `Work` must be abandoned. + * + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. For all other return values, the + * component must be in the stopped state. * * This does not alter any settings and tunings that may have resulted in a * tripped state. * * @return status Status of the call, which may be - * - OK - The component has stopped successfully. - * - BAD_STATE - Component is not in running state. - * - DUPLICATE - When called during another stop call from another thread. - * - TIMED_OUT - The component could not be stopped within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented starting the component. - * (unexpected) + * - `OK` - The component has stopped successfully. + * - `BAD_STATE` - Component is not in running state. + * - `DUPLICATE` - When called during another stop call from another + * thread. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ stop() generates (Status status); @@ -284,25 +313,24 @@ interface IComponent extends IComponentInterface { * * This method must return withing 500ms. * - * After this call returns all work must have been abandoned, all references - * must have been released. + * When this call returns, if @p status is `OK`, all `Work` items must + * have been abandoned, and all resources (including `C2BlockPool` objects + * previously created by createBlockPool()) must have been released. * - * If the return value is BAD_STATE or DUPLICATE, no state change is - * expected as a response to this call. - * For all other return values, the component shall be in the stopped state. + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. For all other return values, the + * component must be in the stopped state. * - * This brings settings back to their default - "guaranteeing" no tripped + * This brings settings back to their default, "guaranteeing" no tripped * state. * * @return status Status of the call, which may be - * - OK - The component has been reset. - * - BAD_STATE - Component is in released state. - * - DUPLICATE - When called during another reset call from another - * thread. - * - TIMED_OUT - The component could not be reset within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented resetting the component. - * (unexpected) + * - `OK` - The component has been reset. + * - `BAD_STATE` - Component is in released state. + * - `DUPLICATE` - When called during another reset call from another + * thread. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ reset() generates (Status status); @@ -311,19 +339,27 @@ interface IComponent extends IComponentInterface { * * This method must be supported in stopped state. * - * This method must return withing 500ms. Upon return all references must - * be abandoned. + * This method destroys the component. Upon return, if @p status is `OK` or + * `DUPLICATE`, all resources must have been released. * * @return status Status of the call, which may be - * - OK - The component has been released. - * - BAD_STATE - The component is running. - * - DUPLICATE - The component is already released. - * - TIMED_OUT - The component could not be released within the time - * limit. (unexpected) - * - CORRUPTED - Some unknown error prevented releasing the component. - * (unexpected) + * - `OK` - The component has been released. + * - `BAD_STATE` - The component is running. + * - `DUPLICATE` - The component is already released. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ release() generates (Status status); + /** + * Returns the @ref IComponentInterface instance associated to this + * component. + * + * An @p IConfigurable instance for the component can be obtained by calling + * IComponentInterface::getConfigurable() on the returned @p intf. + * + * @return intf `IComponentInterface` instance. This must not be null. + */ + getInterface() generates (IComponentInterface intf); }; diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal index d4b30b1b7b..a007d02fe3 100644 --- a/media/c2/1.0/IComponentInterface.hal +++ b/media/c2/1.0/IComponentInterface.hal @@ -19,21 +19,20 @@ package android.hardware.media.c2@1.0; import IConfigurable; /** - * Component interface object. This object contains all of the configuration of + * Component interface object. This object contains all of the configurations of * a potential or actual component. It can be created and used independently of - * an actual Codec 2.0 component instance to query support and parameters for - * various component settings and configurations for a potential component. - * Actual components also expose this interface. + * an actual Codec2 component to query supported parameters for various + * component settings, and configurations for a potential component. + * + * An actual component exposes this interface via IComponent::getInterface(). */ -interface IComponentInterface extends IConfigurable { - /* - * There are no additional methods to IConfigurable interface. - * - * Component interfaces have no states. +interface IComponentInterface { + /** + * Returns the @ref IConfigurable instance associated to this component + * interface. * - * The name of the component or component interface object is a unique name - * for that component or component interface 'class'; however, multiple - * instances of that component must have the same name. + * @return configurable `IConfigurable` instance. This must not be null. */ + getConfigurable() generates (IConfigurable configurable); }; diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal index eb71ecbdd5..70d5fb289e 100644 --- a/media/c2/1.0/IComponentListener.hal +++ b/media/c2/1.0/IComponentListener.hal @@ -17,54 +17,112 @@ package android.hardware.media.c2@1.0; /** - * This callback interface is used for handling notifications from IComponent. + * Callback interface for handling notifications from @ref IComponent. */ interface IComponentListener { /** - * Notify the listener that some works have been completed. + * Notify the listener that some `Work` items have been completed. + * + * All the input buffers in the returned `Work` objects must not be used by + * the component after onWorkDone() is called. + * + * @param workBundle List of completed `Work` objects. */ oneway onWorkDone(WorkBundle workBundle); /** * Notify the listener that the component is tripped. + * + * @param settingResults List of failures. */ oneway onTripped(vec<SettingResult> settingResults); /** * Notify the listener of an error. * - * @param status Error type. \p status may be `OK`, which means that an - * error has occurred, but the error type is unknown. - * @param errorCode Additional error code. The framework may not recognize - * this. + * @param status Error type. @p status may be `OK`, which means that an + * error has occurred, but the error type does not fit into the type + * `Status`. In this case, additional information is provided by + * @p errorCode. + * @param errorCode Additional error information. The framework may not + * recognize the meaning of this value. */ oneway onError(Status status, uint32_t errorCode); /** - * Information about rendering of a frame. + * Information about rendering of a frame to a `Surface`. */ struct RenderedFrame { /** - * Id of the buffer queue containing the rendered buffer. + * Id of the `BufferQueue` containing the rendered buffer. + * + * This value must have been obtained by an earlier call to + * IGraphicBufferProducer::getUniqueId(). */ uint64_t bufferQueueId; /** * Id of the slot of the rendered buffer. + * + * This value must have been obtained by an earlier call to + * IGraphicBufferProducer::dequeueBuffer() or + * IGraphicBufferProducer::attachBuffer(). */ int32_t slotId; /** - * Timestamp of the rendering (consistent with timestamps in - * the associated BufferQueue). + * Timestamp the rendering happened. + * + * The reference point for the timestamp is determined by the + * `BufferQueue` that performed the rendering. */ int64_t timestampNs; }; /** - * Notify the listener that frames are rendered. + * Notify the listener that frames have been rendered. * - * @param renderedFrames List of information about renderings of frames. + * @param renderedFrames List of @ref RenderedFrame objects. */ oneway onFramesRendered(vec<RenderedFrame> renderedFrames); + + /** + * Identifying information for an input buffer previously queued to the + * component via IComponent::queue(). + */ + struct InputBuffer { + /** + * This value comes from `Work::input.ordinal.frameIndex` in a `Work` + * object that was previously queued. + */ + uint64_t frameIndex; + /** + * This value is an index into `Work::input.buffers` (which is an array) + * in a `Work` object that was previously queued. + */ + uint32_t arrayIndex; + }; + + /** + * Notify the listener that some input buffers are no longer needed by the + * component, and hence can be released or reused by the client. + * + * Input buffers that are contained in a `Work` object returned by an + * earlier onWorkDone() call are assumed released, so they must not appear + * in any onInputBuffersReleased() calls. That means + * onInputBuffersReleased() must only report input buffers that are released + * before the output in the same `Work` item is produced. However, it is + * possible for an input buffer to be returned by onWorkDone() after it has + * been reported by onInputBuffersReleased(). + * + * @note onWorkDone() and onInputBuffersReleased() both notify the client + * that input buffers are no longer needed. However, in order to minimize + * IPC calls, onInputBuffersReleased() should be called only when + * onWorkDone() cannot be called, e.g., the component needs more input + * before an output can be produced. + * + * @param inputBuffers List of `InputBuffer` objects, identifying input + * buffers that are no longer needed by the component. + */ + oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers); }; diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal index 4bfa170283..2aa6a70b5d 100644 --- a/media/c2/1.0/IComponentStore.hal +++ b/media/c2/1.0/IComponentStore.hal @@ -23,27 +23,33 @@ import IComponent; import IConfigurable; import IInputSurface; -interface IComponentStore extends IConfigurable { +/** + * Entry point for Codec2 HAL. + * + * All methods in `IComponentStore` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. The only exceptions are getPoolClientManager() and getConfigurable(), + * which must always return immediately. + */ +interface IComponentStore { /** * Creates a component by name. * - * This method must return within 100ms. - * - * @param name Name of the component to create. This should match one of the + * @param name Name of the component to create. This must match one of the * names returned by listComponents(). - * @param listener The component listener to use for the component. - * @param pool The buffer pool client manager of the component listener. - * This must be null if the listener process does not own a buffer pool. + * @param listener Callback receiver. + * @param pool `IClientManager` object of the BufferPool in the client + * process. This may be null if the client does not own a BufferPool. * @return status Status of the call, which may be - * - OK - The component was created successfully. - * - NOT_FOUND - There is no component with the given name. - * - NO_MEMORY - Not enough memory to create the component. - * - TIMED_OUT - The component could not be created within the time limit. - * (unexpected) - * - CORRUPTED - Some unknown error prevented the creation of the - * component. (unexpected) - * @return comp The created component if `Status = OK`. + * - `OK` - The component was created successfully. + * - `NOT_FOUND` - There is no component with the given name. + * - `NO_MEMORY` - Not enough memory to create the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return comp The created component if @p status is `OK`. + * + * @sa IComponentListener. */ createComponent( string name, @@ -57,19 +63,15 @@ interface IComponentStore extends IConfigurable { /** * Creates a component interface by name. * - * This method must return within 100ms. - * * @param name Name of the component interface to create. This should match * one of the names returned by listComponents(). * @return status Status of the call, which may be - * - OK - The component interface was created successfully. - * - NOT_FOUND - There is no component interface with the given name. - * - NO_MEMORY - Not enough memory to create the component interface. - * - TIMED_OUT - The component interface could not be created within the - * time limit. (unexpected) - * - CORRUPTED - Some unknown error prevented the creation of the - * component interface. (unexpected) - * @return compIntf The created component interface if `Status = OK`. + * - `OK` - The component interface was created successfully. + * - `NOT_FOUND` - There is no component interface with the given name. + * - `NO_MEMORY` - Not enough memory to create the component interface. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return compIntf The created component interface if @p status is `OK`. */ createInterface( string name @@ -83,57 +85,49 @@ interface IComponentStore extends IConfigurable { */ struct ComponentTraits { /** - * Name of the component. + * Name of the component. This must be unique for each component. + * + * This name is use to identify the component to create in + * createComponent() and createComponentInterface(). */ string name; enum Domain : uint32_t { - AUDIO, + OTHER = 0, VIDEO, - OTHER = 0xffffffff, + AUDIO, + IMAGE, }; /** - * Component domain. The framework may not recognize `OTHER`. + * Component domain. */ Domain domain; - /** - * If #domain is `OTHER`, #domainOther can be used to provide additional - * information. Otherwise, #domainOther is ignored. The framework may - * not inspect this value. - */ - uint32_t domainOther; enum Kind : uint32_t { + OTHER = 0, DECODER, ENCODER, - OTHER = 0xffffffff, }; /** - * Component kind. The framework may not recognize `OTHER`. + * Component kind. */ Kind kind; - /** - * If #kind is `OTHER`, #kindOther can be used to provide additional - * information. Otherwise, #kindOther is ignored. The framework may not - * inspect this value. - */ - uint32_t kindOther; /** - * Rank used by MediaCodecList to determine component ordering. Lower + * Rank used by `MediaCodecList` to determine component ordering. Lower * value means higher priority. */ uint32_t rank; /** - * Media type. + * MIME type. */ string mediaType; /** * Aliases for component name for backward compatibility. * - * \note Multiple components can have the same alias (but not the same + * Multiple components can have the same alias (but not the same * component name) as long as their media types differ. */ vec<string> aliases; @@ -142,36 +136,51 @@ interface IComponentStore extends IConfigurable { /** * Returns the list of components supported by this component store. * - * This method must return within 500ms. - * - * @return traits List of component traits for all components supported by this store in no - * particular order. + * @return status Status of the call, which may be + * - `OK` - The operation was successful. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return traits List of component traits for all components supported by + * this store (in no particular order). */ - listComponents() generates (vec<ComponentTraits> traits); + listComponents() generates ( + Status status, + vec<ComponentTraits> traits + ); /** * Creates a persistent input surface that can be used as an input surface * for any IComponent instance * - * This method must return within 100ms. - * - * @return surface A persistent input surface + * @return status Status of the call, which may be + * - `OK` - The operation was successful. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return surface A persistent input surface. This may be null to indicate + * an error. */ - createInputSurface() generates (IInputSurface surface); + createInputSurface() generates ( + Status status, + IInputSurface surface + ); /** - * Returns a list of StructDescriptor object for a set of requested - * structures that this store is aware of. + * Returns a list of `StructDescriptor` objects for a set of requested + * C2Param structure indices that this store is aware of. * * This operation must be performed at best effort, e.g. the component * store must simply ignore all struct indices that it is not aware of. * - * @param indices struct indices to return des + * @param indices Indices of C2Param structures to describe. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - NOT_FOUND - Some indices were not known. - * - NO_MEMORY - Not enough memory to complete this method. - * @return structs List of StructDescriptor objects. + * - `OK` - The operation completed successfully. + * - `NOT_FOUND` - Some indices were not known. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return structs List of `StructDescriptor` objects. */ getStructDescriptors( vec<ParamIndex> indices @@ -181,33 +190,35 @@ interface IComponentStore extends IConfigurable { ); /** - * Returns information required for using BufferPool API in buffer passing. - * If the returned pool is not null, the client can call registerSender() to - * register its IAccessor instance, hence allowing the client to send - * buffers to components hosted by this process. - * - * @return pool If the component store supports receiving buffers via - * BufferPool API, \p pool must be a valid `IClientManager` instance. - * Otherwise, \p pool must be null. - */ - getPoolClientManager( - ) generates ( - IClientManager pool - ); - - /** - * The store must copy the contents of \p src into \p dst without changing - * the format of \p dst. + * Copies the contents of @p src into @p dst without changing the format of + * @p dst. * * @param src Source buffer. * @param dst Destination buffer. * @return status Status of the call, which may be - * - OK - The copy is successful. - * - CANNOT_DO - \p src and \p dst are not compatible. - * - REFUSED - No permission to copy. - * - CORRUPTED - The copy cannot be done. (unexpected) + * - `OK` - The copy is successful. + * - `CANNOT_DO` - @p src and @p dst are not compatible. + * - `REFUSED` - No permission to copy. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. */ copyBuffer(Buffer src, Buffer dst) generates (Status status); + /** + * Returns the `IClientManager` object for the component's BufferPool. + * + * @return pool If the component store supports receiving buffers via + * BufferPool API, @p pool must be a valid `IClientManager` instance. + * Otherwise, @p pool must be null. + */ + getPoolClientManager() generates (IClientManager pool); + + /** + * Returns the @ref IConfigurable instance associated to this component + * store. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); }; diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal index cd4dd10151..31dc4d3cba 100644 --- a/media/c2/1.0/IConfigurable.hal +++ b/media/c2/1.0/IConfigurable.hal @@ -17,43 +17,78 @@ package android.hardware.media.c2@1.0; /** - * Generic configuration interface used by all configurable Codec 2.0 - * components. + * Generic configuration interface presented by all configurable Codec2 objects. * - * This interface must be supported in all states of the inheriting - * object, and must not change the state of the inheriting object. + * This interface must be supported in all states of the owning object, and must + * not change the state of the owning object. */ interface IConfigurable { /** - * Returns the name of this object. This must match the name that was - * supplied during the creation of the object. + * Returns the id of the object. This must be unique among all objects of + * the same type hosted by the same store. * - * @return name Name of this object. + * @return id Id of the object. + */ + getId() generates (uint32_t id); + + /** + * Returns the name of the object. + * + * This must match the name that was supplied during the creation of the + * object. + * + * @return name Name of the object. */ getName() generates (string name); /** - * Queries a set of parameters from the object. Querying is performed at - * best effort: the object must query all supported parameters and skip - * unsupported ones, or parameters that could not be allocated. Any errors - * are communicated in the return value. + * Queries a set of parameters from the object. + * + * Querying is performed at best effort: the object must query all supported + * parameters and skip unsupported ones (which may include parameters that + * could not be allocated). Any errors are communicated in the return value. + * + * If @p mayBlock is false, this method must not block. All parameter + * queries that require blocking must be skipped. * - * \note Parameter values do not depend on the order of query. + * If @p mayBlock is true, a query may block, but the whole method call + * has to complete in a timely manner, or `status = TIMED_OUT` is returned. * - * This method must return within 1ms if \p mayBlock is DONT_BLOCK, and - * within 5ms otherwise. + * If @p mayBlock is false, this method must not block. Otherwise, this + * method is allowed to block for a certain period of time before completing + * the operation. If the operation is not completed in a timely manner, + * `status = TIMED_OUT` is returned. * - * @param indices List of param indices for params to be queried. + * @note The order of C2Param objects in @p param does not depend on the + * order of C2Param structure indices in @p indices. + * + * \par For IComponent + * + * When the object type is @ref IComponent, this method must be supported in + * any state except released. This call must not change the state nor the + * internal configuration of the component. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @param indices List of C2Param structure indices to query. * @param mayBlock Whether this call may block or not. * @return status Status of the call, which may be - * - OK - All parameters could be queried. - * - BAD_INDEX - All supported parameters could be queried, but some - * parameters were not supported. - * - NO_MEMORY - Could not allocate memory for a supported parameter. - * - BLOCKING - Querying some parameters requires blocking. - * - CORRUPTED - Some unknown error prevented the querying of the - * parameters. (unexpected) - * @return params List of params queried corresponding to \p indices. + * - `OK` - All parameters could be queried. + * - `BAD_INDEX` - All supported parameters could be queried, but some + * parameters were not supported. + * - `NO_MEMORY` - Could not allocate memory for a supported parameter. + * - `BLOCKING` - Querying some parameters requires blocking, but + * @p mayBlock is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return params Flattened representation of C2Param objects. + * + * @sa Params. */ query( vec<ParamIndex> indices, @@ -64,31 +99,60 @@ interface IConfigurable { ); /** - * Sets a set of parameters for the object. Tuning is performed at best - * effort: the object must update all supported configuration at best - * effort and skip unsupported parameters. Any errors are communicated in - * the return value and in \p failures. + * Sets a set of parameters for the object. + * + * Tuning is performed at best effort: the object must update all supported + * configurations at best effort and skip unsupported parameters. Any errors + * are communicated in the return value and in @p failures. + * + * A non-strict parameter update with an unsupported value shall cause an + * update to the closest supported value. A strict parameter update with an + * unsupported value shall be skipped and a failure shall be returned. * - * \note Parameter tuning DOES depend on the order of the tuning parameters. - * E.g. some parameter update may allow some subsequent parameter update. + * If @p mayBlock is false, this method must not block. An update that + * requires blocking shall be skipped and a failure shall be returned. * - * This method must return within 1ms if \p mayBlock is false, and within - * 5ms otherwise. + * If @p mayBlock is true, an update may block, but the whole method call + * has to complete in a timely manner, or `status = TIMED_OUT` is returned. + * + * The final values for all parameters set are propagated back to the caller + * in @p params. + * + * \par For IComponent + * + * When the object type is @ref IComponent, this method must be supported in + * any state except released. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @note Parameter tuning @e does depend on the order of the tuning + * parameters, e.g., some parameter update may enable some subsequent + * parameter update. * * @param inParams Requested parameter updates. * @param mayBlock Whether this call may block or not. * @return status Status of the call, which may be - * - OK - All parameters could be updated successfully. - * - BAD_INDEX - All supported parameters could be updated successfully, - * but some parameters were not supported. - * - NO_MEMORY - Some supported parameters could not be updated - * successfully because they contained unsupported values. - * These are returned in \p failures. - * - BLOCKING - Setting some parameters requires blocking. - * - CORRUPTED - Some unknown error prevented the update of the - * parameters. (unexpected) - * @return failures List of parameter failures. - * @return outParams Resulting values for the configured parameters. + * - `OK` - All parameters could be updated successfully. + * - `BAD_INDEX` - All supported parameters could be updated successfully, + * but some parameters were not supported. + * - `NO_MEMORY` - Some supported parameters could not be updated + * successfully because they contained unsupported values. + * These are returned in @p failures. + * - `BLOCKING` - Setting some parameters requires blocking, but + * @p mayBlock is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return failures List of update failures. + * @return outParams Flattened representation of configured parameters. The + * order of parameters in @p outParams is based on the order of + * requested updates in @p inParams. + * + * @sa SettingResult. */ config( Params inParams, @@ -103,22 +167,19 @@ interface IConfigurable { // ========================================================================= /** - * Returns a selected range of the set of supported parameters. - * - * The set of supported parameters are represented in a vector with a - * start index of 0, and the selected range are indices into this vector. - * Fewer than \p count parameters are returned if the selected range is - * not fully/not at all part of the available vector indices. + * Returns a list of supported parameters within a selected range of C2Param + * structure indices. * - * This method must return within 1ms. - * - * @param start start index of selected range - * @param count size of the selected + * @param start The first index of the selected range. + * @param count The length of the selected range. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - NO_MEMORY - Not enough memory to complete this method. - * @return params Vector containing the selected range of supported - * parameters. + * - `OK` - The operation completed successfully. + * - `NO_MEMORY` - Not enough memory to complete this method. + * @return params List of supported parameters in the selected range. This + * list may have fewer than @p count elements if some indices in the + * range are not supported. + * + * @sa ParamDescriptor. */ querySupportedParams( uint32_t start, @@ -131,23 +192,42 @@ interface IConfigurable { /** * Retrieves the supported values for the queried fields. * - * Upon return the object must fill in the supported - * values for the fields listed as well as a status for each field. - * Object shall process all fields queried even if some queries fail. + * The object must process all fields queried even if some queries fail. + * + * If @p mayBlock is false, this method must not block. Otherwise, this + * method is allowed to block for a certain period of time before completing + * the operation. If the operation cannot be completed in a timely manner, + * `status = TIMED_OUT` is returned. * - * This method must return within 1ms if \p mayBlock is false, and within - * 5ms otherwise. + * \par For IComponent * - * @param inFields Vector of field queries. + * When the object type is @ref IComponent, this method must be supported in + * any state except released. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @param inFields List of field queries. * @param mayBlock Whether this call may block or not. * @return status Status of the call, which may be - * - OK - The operation completed successfully. - * - BLOCKING - Querying some parameters requires blocking. - * - NO_MEMORY - Not enough memory to complete this method. - * - BAD_INDEX - At least one field was not recognized as a component - * field. - * @return outFields Vector containing supported values and query result - * for the selected fields. + * - `OK` - The operation completed successfully. + * - `BLOCKING` - Querying some parameters requires blocking, but + * @p mayBlock is false. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `BAD_INDEX` - At least one field was not recognized as a component + * field. + * - `BLOCKING` - Querying some fields requires blocking, but @p mayblock + * is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return outFields List of supported values and results for the + * supplied queries. + * + * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult. */ querySupportedValues( vec<FieldSupportedValuesQuery> inFields, diff --git a/media/c2/1.0/IInputSink.hal b/media/c2/1.0/IInputSink.hal new file mode 100644 index 0000000000..809c27a7aa --- /dev/null +++ b/media/c2/1.0/IInputSink.hal @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer; + +import IConfigurable; + +/** + * An `IInputSink` is a receiver of work items. + * + * An @ref IComponent instance can present itself as an `IInputSink` via a thin + * wrapper. + * + * @sa IInputSurface, IComponent. + */ +interface IInputSink { + /** + * Feeds work to the sink. + * + * @param workBundle `WorkBundle` object containing a list of `Work` objects + * to queue to the component. + * @return status Status of the call, which may be + * - `OK` - Works in @p workBundle were successfully queued. + * - `BAD_INDEX` - Some component id in some `Worklet` is not valid. + * - `CANNOT_DO` - Tunneling has not been set up for this sink, but some + * `Work` object contains tunneling information. + * - `NO_MEMORY` - Not enough memory to queue @p workBundle. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + queue(WorkBundle workBundle) generates (Status status); + + /** + * Returns the @ref IConfigurable instance associated to this sink. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); +}; + diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal index c083a21879..d11ce15e0e 100644 --- a/media/c2/1.0/IInputSurface.hal +++ b/media/c2/1.0/IInputSurface.hal @@ -19,43 +19,57 @@ package android.hardware.media.c2@1.0; import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer; import IConfigurable; -import IComponent; +import IInputSink; import IInputSurfaceConnection; /** - * Input surface that can be configured for the IComponent. + * Input surface for a Codec2 component. + * + * An <em>input surface</em> is an instance of `IInputSurface`, which may be + * created by calling IComponentStore::createInputSurface(). Once created, the + * client may + * 1. write data to it via the `IGraphicBufferProducer` interface; and + * 2. use it as input to a Codec2 encoder. + * + * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(), + * IComponent::connectToInputSurface(). */ -interface IInputSurface extends IGraphicBufferProducer { +interface IInputSurface { + /** + * Returns the producer interface into the internal buffer queue. + * + * @return producer `IGraphicBufferProducer` instance. This must not be + * null. + */ + getGraphicBufferProducer() generates (IGraphicBufferProducer producer); + + /** + * Returns the @ref IConfigurable instance associated to this input surface. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); /** - * Connects this input surface to a component. + * Connects the input surface to an input sink. * - * This call must return within 100 ms. + * This function is generally called from inside the implementation of + * IComponent::connectToInputSurface(), where @p sink is a thin wrapper of + * the component that consumes buffers from this surface. * - * @param component The component to connect to. This must have type - * IComponent. + * @param sink Input sink. See `IInputSink` for more information. * @return status Status of the call, which may be - * - OK - The operation succeeded. - * - BAD_STATE - The component is in running state. - * - DUPLICATE - The surface is already connected to a component. - * - NO_MEMORY - Could not allocate memory to connect to the component. - * - CORRUPTED - Some unknown error prevented the connection. (unexpected) - * @return connection Connection object that is used to disconnect - * from the component. + * - `OK` - Configuration successful. + * - `BAD_VALUE` - @p sink is invalid. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object. This must not be + * null if @p status is `OK`. */ - connectToComponent( - IComponent component + connect( + IInputSink sink ) generates ( Status status, IInputSurfaceConnection connection ); - - /** - * Returns the Codec 2.0 configuration object for this surface. - * - * @return configurable The configuration object for this surface. - */ - getConfigurable() generates (IConfigurable configurable); - }; diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal index 500091dbbc..035b1159b4 100644 --- a/media/c2/1.0/IInputSurfaceConnection.hal +++ b/media/c2/1.0/IInputSurfaceConnection.hal @@ -16,20 +16,33 @@ package android.hardware.media.c2@1.0; -interface IInputSurfaceConnection { +import IConfigurable; +/** + * Connection between a component and an input surface. + * + * An instance of `IInputSurfaceConnection` contains an `IConfigurable` + * interface for querying and configuring properties of the connection. + */ +interface IInputSurfaceConnection { /** - * Disconnects this input surface from the component. - * - * This call must return within 100 ms. + * Destroys the connection between an input surface and a component. * * @return status Status of the call, which may be - * - OK - The operation succeeded. - * - BAD_STATE - The component is not in running state. - * - NOT_FOUND - The surface is not connected to a component. - * - CORRUPTED - Some unknown error prevented the connection. (unexpected) + * - `OK` - The disconnection succeeded. + * - `BAD_STATE` - The component is not in running state. + * - `NOT_FOUND` - The surface is not connected to a component. + * - `CORRUPTED` - Some unknown error occurred. */ disconnect() generates (Status status); + /** + * Returns the @ref IConfigurable instance associated to this connection. + * + * This can be used to customize the connection. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); }; diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal index 252d781e7f..ec422b1f40 100644 --- a/media/c2/1.0/types.hal +++ b/media/c2/1.0/types.hal @@ -18,220 +18,278 @@ package android.hardware.media.c2@1.0; import android.hardware.media.bufferpool@2.0::BufferStatusMessage; +/** + * Common return values for Codec2 operations. + */ enum Status : int32_t { - /** operation completed successfully */ + /** Operation completed successfully. */ OK = 0, // bad input - /** argument has invalid value (user error) */ + /** Argument has invalid value (user error). */ BAD_VALUE = -22, - /** argument uses invalid index (user error) */ + /** Argument uses invalid index (user error). */ BAD_INDEX = -75, - /** argument/index is valid but not possible */ + /** Argument/Index is valid but not possible. */ CANNOT_DO = -2147483646, // bad sequencing of events - /** object already exists */ + /** Object already exists. */ DUPLICATE = -17, - /** object not found */ + /** Object not found. */ NOT_FOUND = -2, - /** operation is not permitted in the current state */ + /** Operation is not permitted in the current state. */ BAD_STATE = -38, - /** operation would block but blocking is not permitted */ + /** Operation would block but blocking is not permitted. */ BLOCKING = -9930, // bad environment - /** not enough memory to complete operation */ + /** Not enough memory to complete operation. */ NO_MEMORY = -12, - /** missing permission to complete operation */ + /** Missing permission to complete operation. */ REFUSED = -1, - /** operation did not complete within timeout */ + /** Operation did not complete within timeout. */ TIMED_OUT = -110, // missing functionality - /** operation is not implemented/supported (optional only) */ + /** Operation is not implemented/supported (optional only). */ OMITTED = -74, // unknown fatal - /** some unexpected error prevented the operation */ + /** Some unexpected error prevented the operation. */ CORRUPTED = -2147483648, // uninitialized - /** status has not been initialized */ + /** Status has not been initialized. */ NO_INIT = -19, }; /** - * Codec 2.0 parameter index + * C2Param structure index. + * + * This is a number that is unique for each C2Param structure type. + * + * @sa Codec 2.0 standard. */ typedef uint32_t ParamIndex; /** - * Codec 2.0 parameter structure + * Flattened representation of C2Param objects. + * + * The `Params` type is an array of bytes made up by concatenating a list of + * C2Param objects. The start index (offset into @ref Params) of each C2Param + * object in the list is divisible by 8. Up to 7 padding bytes may be added + * after each C2Param object to achieve this 64-bit alignment. * - * The description of a Params is provided by supplying a ParamIndex to - * IComponentStore::getStructDescriptors(). + * Each C2Param object has the following layout: + * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the + * type of the C2Param object. + * - 4 bytes: size of the C2Param object (unsigned 4-byte integer). + * - (size - 8) bytes: data of the C2Param object. + * + * In order to interpret each C2Param object correctly, its structure must be + * described by IComponentStore::getStructDescriptors(). + * + * @note Please refer to the Codec 2.0 standard for the list of standard + * parameter structures. + * + * @sa Codec 2.0 standard. */ typedef vec<uint8_t> Params; /** - * Struct uniquely specifying a field in an arbitrary parameter structure. + * Identifying information of a field relative to a known C2Param structure. + * + * Within a given C2Param structure, each field is uniquely identified by @ref + * FieldId. */ struct FieldId { - /** Offset of the field in bytes */ + /** Offset of the field in bytes. */ uint32_t offset; - /** Size of the field in bytes */ + /** Size of the field in bytes. */ uint32_t size; }; /** - * Struct representing a location of a field in a parameter with a given index. + * Reference to a field in a C2Param structure. */ struct ParamField { - /** Index of the parameter */ + /** Index of the C2Param structure. */ ParamIndex index; - /** Field identifier */ + /** Identifier of the field inside the C2Param structure. */ FieldId fieldId; }; /** - * Struct describing basic properties of a parameter with a given index. + * Usage description of a C2Param structure. + * + * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams(). */ struct ParamDescriptor { - /** Parameter index */ + /** + * Index of the C2Param structure being described. + */ ParamIndex index; enum Attrib : uint32_t { /** - * Parameter is required to be specified. + * The parameter is required to be specified. */ REQUIRED = 1u << 0, /** - * Parameter retains its value. + * The parameter retains its value. */ PERSISTENT = 1u << 1, /** - * Parameter is strict. + * The parameter is strict. */ STRICT = 1u << 2, /** - * Parameter is publicly read-only. + * The parameter is publicly read-only. */ READ_ONLY = 1u << 3, /** - * Parameter must not be visible to clients. + * The parameter must not be visible to clients. */ HIDDEN = 1u << 4, /** - * Parameter must not be used by framework (other than testing). + * The parameter must not be used by framework (other than testing). */ INTERNAL = 1u << 5, /** - * Parameter is publicly constant (hence read-only). + * The parameter is publicly constant (hence read-only). */ CONST = 1u << 6, }; - /** Parameter attributes */ bitfield<Attrib> attrib; - /** Parameter name */ + /** + * Name of the structure. This must be unique for each structure. + */ string name; - /** index of other parameters that this parameter depends on */ + /** + * Indices of other C2Param structures that this C2Param structure depends + * on. + */ vec<ParamIndex> dependencies; }; -// Generic way to describe supported numeric values for Codec 2.0 interfaces. +// Generic way to describe supported numeric values for Codec2 interfaces. /** - * An untyped value that can fit on 64 bits - the type of which is communicated - * via a separate channel (FieldType). + * An untyped value that can fit in 64 bits, the type of which is communicated + * via a separate channel (@ref FieldSupportedValues.type). */ typedef uint64_t PrimitiveValue; /* - * Generic supported values for a field. + * Description of supported values for a field. * - * This can be either a range or a set of values. The range can be linear or - * geometric with clear minimum and maximum values, and can have an optional - * step size or geometric ratio. Values can optionally represent flags. + * This can be a continuous range or a discrete set of values. */ struct FieldSupportedValues { + /** + * Used if #type is `RANGE`. + * + * If the `step` member is 0, and `num` and `denom` are both 1, the `Range` + * structure represents a closed interval bounded by `min` and `max`. + * + * Otherwise, the #Range structure represents a finite sequence of numbers + * produced from the following recurrence relation: + * + * @code + * v[0] = min + * v[i] = v[i - 1] * num / denom + step ; i >= 1 + * @endcode + * + * Both the ratio `num / denom` and the value `step` must be positive. The + * last number in the sequence described by this #Range structure is the + * largest number in the sequence that is smaller than or equal to `max`. + * + * @note + * The division in the formula may truncate the result if the data type of + * these values is an integral type. + */ struct Range { + /** + * Lower end of the range (inclusive). + */ PrimitiveValue min; + /** + * Upper end of the range (inclusive). + */ PrimitiveValue max; + /** + * The non-homogeneous term in the recurrence relation. + */ PrimitiveValue step; + /** + * The numerator of the scale coefficient in the recurrence relation. + */ PrimitiveValue num; + /** + * The denominator of the scale coefficient in the recurrence relation. + */ PrimitiveValue denom; }; enum Type : int32_t { /** No supported values */ - EMPTY, - /** Numeric range that can be continuous or discrete */ + EMPTY = 0, + /** Numeric range, described in a #Range structure */ RANGE, /** List of values */ VALUES, /** List of flags that can be OR-ed */ FLAGS, - /** Other representations */ - OTHER = 0xffffffff, }; /** - * Type of the supported values. The framework may not recognize `OTHER`. + * Type of the supported values. */ Type type; - /** - * Codec2.0 type code of the supported values. - * * If #type is `OTHER`, #typeOther can be used to give more information. - * In this case, the interpretation of this structure is - * implementation-defined. - * * For all other values of #type, #typeOther is not used. - * The framework may not inspect this value. - */ - int32_t typeOther; - - /* - * If #type = EMPTY, #range and #value are unused. - */ /** - * If #type = RANGE, #range will specify the range of possible values. + * When #type is #Type.RANGE, #range shall specify the range of possible + * values. * - * The intended type of members of #range will be clear in the context where - * FieldSupportedValues is used. + * The intended type of members of #range shall be clear in the context + * where `FieldSupportedValues` is used. */ Range range; /** - * If #type is `VALUES` or `FLAGS`, #value will list supported values. + * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported + * values/flags. * - * The intended type of components of #value will be clear in the context - * where FieldSupportedValues is used. + * The intended type of components of #value shall be clear in the context + * where `FieldSupportedValues` is used. */ vec<PrimitiveValue> values; }; /** - * Supported values for a specific field. + * Supported values for a field. * * This is a pair of the field specifier together with an optional supported * values object. This structure is used when reporting parameter configuration * failures and conflicts. */ struct ParamFieldValues { - /** the field or parameter */ + /** + * Reference to a field or a C2Param structure. + */ ParamField paramOrField; /** - * optional supported values for the field if paramOrField specifies an + * Optional supported values for the field if #paramOrField specifies an * actual field that is numeric (non struct, blob or string). Supported * values for arrays (including string and blobs) describe the supported * values for each element (character for string, and bytes for blobs). It @@ -241,18 +299,18 @@ struct ParamFieldValues { }; /** - * Field descriptor. + * Description of a field inside a C2Param structure. */ struct FieldDescriptor { - /** Field id */ + /** Location of the field in the C2Param structure */ FieldId fieldId; /** - * Possible types of a field. + * Possible types of the field. */ enum Type : uint32_t { - NO_INIT, + NO_INIT = 0, INT32, UINT32, CNTR32, @@ -261,186 +319,227 @@ struct FieldDescriptor { CNTR64, FLOAT, /** - * Fixed-size string (POD) + * Fixed-size string (POD). */ STRING = 0x100, /** - * blobs have no sub-elements and can be thought of as byte arrays. - * However, bytes cannot be individually addressed by clients. + * A blob has no sub-elements and can be thought of as an array of + * bytes. However, bytes cannot be individually addressed by clients. */ BLOB, /** - * Structs. Marked with this flag in addition to their coreIndex. + * The field is a structure that may contain other fields. */ - STRUCT_FLAG = 0x20000, + STRUCT = 0x20000, }; /** * Type of the field. */ bitfield<Type> type; - /** Extent of the field */ - uint32_t length; - /* - * Note: the last member of a param struct can be of arbitrary length (e.g. - * if it is T[] array, which extends to the last byte of the parameter.) - * This is marked with extent 0. + /** + * If #type is #Type.STRUCT, #structIndex is the C2Param structure index; + * otherwise, #structIndex is not used. */ + ParamIndex structIndex; - /** Name of the field */ + /** + * Extent of the field. + * - For a non-array field, #extent is 1. + * - For a fixed-length array field, #extent is the length. An array field + * of length 1 is indistinguishable from a non-array field. + * - For a variable-length array field, #extent is 0. This can only occur as + * the last member of a C2Param structure. + */ + uint32_t extent; + + /** + * Name of the field. This must be unique for each field in the same + * structure. + */ string name; - /** Named value type */ + + /** + * Named value type. This is used for defining an enum value for a numeric + * type. + */ struct NamedValue { + /** + * Name of the enum value. This must be unique for each enum value in + * the same field. + */ string name; + /** + * Underlying value of the enum value. Multiple enum names may have the + * same underlying value. + */ PrimitiveValue value; }; - /** Named values for the field */ + /** + * List of enum values. This is not used when #type is not one of the + * numeric types. + */ vec<NamedValue> namedValues; }; /** - * Struct descriptor. + * Description of a C2Param structure. It consists of an index and a list of + * `FieldDescriptor`s. */ struct StructDescriptor { - /** Struct type */ + /** + * Index of the structure. + */ ParamIndex type; - /** Field descriptors for each field */ + /** + * List of fields in the structure. + * + * Fields are ordered by their offsets. A field that is a structure is + * ordered before its members. + */ vec<FieldDescriptor> fields; }; /** - * Information describing the reason a parameter settings may fail, or - * may be overriden. + * Information describing the reason the parameter settings may fail, or may be + * overridden. */ struct SettingResult { - /** Failure code (of Codec 2.0 SettingResult failure type) */ + /** Failure code */ enum Failure : uint32_t { - /** Parameter is read-only and cannot be set. */ - READ_ONLY, - /** Parameter mismatches input data. */ - MISMATCH, - /** Parameter does not accept value. */ - BAD_VALUE, /** Parameter is not supported. */ BAD_TYPE, /** Parameter is not supported on the specific port. */ BAD_PORT, /** Parameter is not supported on the specific stream. */ BAD_INDEX, - /** Parameter is in conflict with an/other setting(s). */ + /** Parameter is read-only and cannot be set. */ + READ_ONLY, + /** Parameter mismatches input data. */ + MISMATCH, + /** Strict parameter does not accept value for the field at all. */ + BAD_VALUE, + /** + * Strict parameter field value is in conflict with an/other + * setting(s). + */ CONFLICT, /** - * Parameter is out of range due to other settings. (This failure mode - * can only be used for strict parameters.) + * Parameter field is out of range due to other settings. (This failure + * mode can only be used for strict calculated parameters.) */ UNSUPPORTED, /** + * Field does not access the requested parameter value at all. It has + * been corrected to the closest supported value. This failure mode is + * provided to give guidance as to what are the currently supported + * values for this field (which may be a subset of the at-all-potential + * values). + */ + INFO_BAD_VALUE, + /** * Requested parameter value is in conflict with an/other setting(s) * and has been corrected to the closest supported value. This failure - * mode is given to provide suggestion to the client as to how to enable - * the requested parameter value. */ - INFO_CONFLICT, - /** - * This failure mode is reported when all the above failure modes do not - * apply. + * mode is given to provide guidance as to what are the currently + * supported values as well as to optionally provide suggestion to the + * client as to how to enable the requested parameter value. */ - OTHER = 0xffffffff, + INFO_CONFLICT, }; - /** - * The failure type. The framework might not recognize `OTHER`. - */ Failure failure; - /** - * The failure code. - * * If #failure is `OTHER`, #failureOther can be used to give more - * information. - * * For all other values of #failure, #failureOther is not used. - * The framework may not inspect this value. - */ - uint32_t failureOther; /** - * Failing (or corrected) field. Currently supported values for the field. - * This is set if different from the globally supported values (e.g. due to - * restrictions by another param or input data) + * Failing (or corrected) field or parameter and optionally, currently + * supported values for the field. Values must only be set for field + * failures other than `BAD_VALUE`, and only if they are different from the + * globally supported values (e.g. due to restrictions by another parameter + * or input data). */ ParamFieldValues field; /** - * Conflicting parameters or fields with - * (optional) suggested values for any conflicting fields to avoid the conflict. + * Conflicting parameters or fields with (optional) suggested values for any + * conflicting fields to avoid the conflict. Values must only be set for + * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code. */ vec<ParamFieldValues> conflicts; }; /** - * Data structure for ordering Work objects. Each member is used for comparing - * urgency in the same fashion: a smaller value indicates that the associated - * Work object is more urgent. + * Ordering information of @ref FrameData objects. Each member is used for + * comparing urgency: a smaller difference from a reference value indicates that + * the associated Work object is more urgent. The reference value for each + * member is initialized the first time it is communicated between the client + * and the codec, and it may be updated to later values that are communicated. + * + * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual + * order it represents is derived by subtracting the reference value, then + * interpreting the result as a signed number with the same storage size (using + * two's complement). + * + * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the + * Codec 2.0 standard. */ struct WorkOrdinal { /** - * Timestamp in microseconds - can wrap around. + * Timestamp in microseconds. */ uint64_t timestampUs; /** - * Frame index - can wrap around. + * Frame index. */ uint64_t frameIndex; /** - * Component specific frame ordinal - can wrap around. + * Component specific frame ordinal. */ uint64_t customOrdinal; }; /** - * A structure that holds information of a Block. There are two types of Blocks: - * NATIVE and POOLED. Each type has its own way of identifying blocks. + * Storage type for `BaseBlock`. + * + * A `BaseBlock` is a representation of a codec memory block. Coded data, + * decoded data, codec-specific data, and other codec-related data are all sent + * in the form of BaseBlocks. */ -struct BaseBlock { - enum Type : int32_t { - NATIVE, - POOLED, - }; +safe_union BaseBlock { /** - * There are two types of blocks: NATIVE and POOLED. - */ - Type type; - - /** - * A "NATIVE" block is represented by a native handle. + * #nativeBlock is the opaque representation of a buffer. */ handle nativeBlock; - - /* - * A "POOLED" block is represented by `BufferStatusMessage`. + /** + * #pooledBlock is a reference to a buffer handled by a BufferPool. */ BufferStatusMessage pooledBlock; }; /** - * A Block in transfer consists of an index into an array of BaseBlock plus some - * extra information. One BaseBlock may occur in multiple blocks in one - * `WorkBundle`. + * Reference to a @ref BaseBlock within a @ref WorkBundle. + * + * `Block` contains additional attributes that `BaseBlock` does not. These + * attributes may differ among `Block` objects that refer to the same + * `BaseBlock` in the same `WorkBundle`. */ struct Block { /** - * Identity of the BaseBlock within a WorkBundle. This is an index into the - * `baseBlocks` array of a `WorkBundle` object. + * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into + * #WorkBundle.baseBlocks. */ uint32_t index; /** - * Metadata associated with the block. + * Metadata associated with this `Block`. */ Params meta; /** - * Fence for synchronizing block access. + * Fence for synchronizing `Block` access. */ handle fence; }; /** - * Type of buffers processed by a component. + * A codec buffer, which is a collection of @ref Block objects and metadata. + * + * This is a part of @ref FrameData. */ struct Buffer { /** @@ -454,23 +553,37 @@ struct Buffer { }; /** - * An extension of Buffer that also contains an index. + * An extension of @ref Buffer that also contains a C2Param structure index. + * + * This is a part of @ref FrameData. */ struct InfoBuffer { + /** + * A C2Param structure index. + */ ParamIndex index; + /** + * Associated @ref Buffer object. + */ Buffer buffer; }; /** - * This structure represents a frame with its metadata. A frame consists of an - * ordered set of buffers, configuration changes, and info buffers along with - * some non-configuration metadata. + * Data for an input frame or an output frame. + * + * This structure represents a @e frame with its metadata. A @e frame consists + * of an ordered set of buffers, configuration changes, and info buffers along + * with some non-configuration metadata. + * + * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0 + * standard. */ struct FrameData { enum Flags : uint32_t { /** - * For input frames: no output frame will be generated when processing + * For input frames: no output frame shall be generated when processing * this frame, but metadata must still be processed. + * * For output frames: this frame must be discarded but metadata is still * valid. */ @@ -482,92 +595,178 @@ struct FrameData { END_OF_STREAM = (1 << 1), /** * This frame must be discarded with its metadata. - * This flag is only set by components - e.g. as a response to the flush + * + * This flag is only set by components, e.g. as a response to the flush * command. */ DISCARD_FRAME = (1 << 2), /** + * This frame is not the last frame produced for the input. + * + * This flag is normally set by the component - e.g. when an input frame + * results in multiple output frames, this flag is set on all but the + * last output frame. + * + * Also, when components are chained, this flag should be propagated + * down the work chain. That is, if set on an earlier frame of a + * work-chain, it should be propagated to all later frames in that + * chain. Additionally, components down the chain could set this flag + * even if not set earlier, e.g. if multiple output frames are generated + * at that component for the input frame. + */ + FLAG_INCOMPLETE = (1 << 3), + /** * This frame contains only codec-specific configuration data, and no * actual access unit. * - * \deprecated Pass codec configuration with the codec-specific + * @deprecated Pass codec configuration with the codec-specific * configuration info together with the access unit. */ CODEC_CONFIG = (1u << 31), }; /** - * Frame flags. + * Frame flags, as described in #Flags. */ bitfield<Flags> flags; /** - * Ordinal of the frame. + * @ref WorkOrdinal of the frame. */ WorkOrdinal ordinal; /** - * Frame buffers. + * List of frame buffers. */ vec<Buffer> buffers; /** - * Params determining a configuration update. + * List of configuration updates. */ Params configUpdate; /** - * Info buffers. + * List of info buffers. */ vec<InfoBuffer> infoBuffers; }; /** - * Struct for + * In/out structure containing some instructions for and results from output + * processing. + * + * This is a part of @ref Work. One `Worklet` corresponds to one output + * @ref FrameData. The client must construct an original `Worklet` object inside + * a @ref Work object for each expected output before calling + * IComponent::queue(). */ struct Worklet { /** - * List of Params describing tunings. + * Component id. (Input) + * + * This is used only when tunneling is enabled. + * + * When used, this must match the return value from IConfigurable::getId(). + */ + uint32_t componentId; + + /** + * List of C2Param objects describing tunings to be applied before + * processing this `Worklet`. (Input) */ - vec<Params> tunings; + Params tunings; /** - * List of failures. + * List of failures. (Output) */ vec<SettingResult> failures; /** - * Output frame data. + * Output frame data. (Output) */ FrameData output; - - /* Note: Component id is not necessary as tunneling is not supported. */ }; /** - * This structure holds information about a single work item. It must be passed - * by the client to the component. + * A collection of input data to and output data from the component. + * + * A `Work` object holds information about a single work item. It is created by + * the client and passed to the component via IComponent::queue(). The component + * has two ways of returning a `Work` object to the client: + * 1. If the queued `Work` object has been successfully processed, + * IComponentListener::onWorkDone() shall be called to notify the listener, + * and the output shall be included in the returned `Work` object. + * 2. If the client calls IComponent::flush(), a `Work` object that has not + * been processed shall be returned. + * + * `Work` is a part of @ref WorkBundle. */ struct Work { /** - * FrameData for the input. Indices of Blocks inside #input refer to - * BaseBlocks in the member `blocks` of the containing `WorkBundle`. + * Additional work chain info not part of this work. + */ + Params chainInfo; + + /** + * @ref FrameData for the input. */ FrameData input; + /** - * Worklet. Indices of Blocks inside `worklet.output` refer to - * BaseBlocks in the member `blocks` of the containing `WorkBundle`. + * The chain of `Worklet`s. + * + * The length of #worklets is 1 when tunneling is not enabled. + * + * If #worklets has more than a single element, the tunnels between + * successive components of the work chain must have been successfully + * pre-registered at the time that the `Work` is submitted. Allocating the + * output buffers in the `Worklet`s is the responsibility of each component + * in the chain. + * + * Upon `Work` submission, #worklets must be an appropriately sized vector + * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a + * successful processing, all but the final `Worklet` in the returned + * #worklets must have @ref Worklet.hasOutput set to `false`. + */ + vec<Worklet> worklets; + + /** + * The number of `Worklet`s successfully processed in this chain. + * + * This must be initialized to 0 by the client when the `Work` is submitted, + * and it must contain the number of `Worklet`s that were successfully + * processed when the `Work` is returned to the client. + * + * #workletsProcessed cannot exceed the length of #worklets. If + * #workletsProcessed is smaller than the length of #worklets, #result + * cannot be `OK`. */ - Worklet worklet; + uint32_t workletsProcessed; + /** - * Whether the worklet was processed or not. + * The final outcome of the `Work` (corresponding to #workletsProcessed). + * + * The value of @ref Status.OK implies that all `Worklet`s have been + * successfully processed. */ - bool workletProcessed; Status result; }; /** - * This structure holds a list of Work objects and a list of BaseBlocks. + * List of `Work` objects. + * + * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and + * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of + * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work` + * objects together provides two benefits: + * 1. Batching of `Work` objects can reduce the number of IPC calls. + * 2. If multiple `Work` objects contain `Block`s that refer to the same + * `BaseBlock`, the number of `BaseBlock`s that is sent between processes + * is also reduced. + * + * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the + * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the + * data transferred over an IPC. */ struct WorkBundle { /** @@ -581,27 +780,48 @@ struct WorkBundle { }; /** - * This structure describes a query for supported values of a field. This is - * used as input to IConfigurable::queryFieldSupportedValues(). + * Query information for supported values of a field. This is used as input to + * IConfigurable::querySupportedValues(). */ struct FieldSupportedValuesQuery { + /** + * Identity of the field to query. + */ + ParamField field; + enum Type : uint32_t { - /** Query all possible values regardless of other settings */ + /** Query all possible values regardless of other settings. */ POSSIBLE, - /** Query currently possible values given dependent settings */ + /** Query currently possible values given dependent settings. */ CURRENT, }; - - ParamField field; + /** + * Type of the query. See #Type for more information. + */ Type type; }; /** * This structure is used to hold the result from - * IConfigurable::queryFieldSupportedValues(). + * IConfigurable::querySupportedValues(). */ struct FieldSupportedValuesQueryResult { + /** + * Result of the query. Possible values are + * - `OK`: The query was successful. + * - `BAD_STATE`: The query was requested when the `IConfigurable` instance + * was in a bad state. + * - `BAD_INDEX`: The requested field was not recognized. + * - `TIMED_OUT`: The query could not be completed in a timely manner. + * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the + * call to `querySupportedValues()` was `false`. + * - `CORRUPTED`: Some unknown error occurred. + */ Status status; + + /** + * Supported values. This is meaningful only when #status is `OK`. + */ FieldSupportedValues values; }; diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index dd6f9341d7..52d63286b7 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -22,6 +22,10 @@ cc_library_static { ], defaults: ["VtsHalTargetTestDefaults"], export_include_dirs: ["."], + shared_libs: [ + "libfmq", + "libnativewindow", + ], static_libs: [ "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", @@ -47,6 +51,10 @@ cc_defaults { "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", ], + shared_libs: [ + "libfmq", + "libnativewindow", + ], static_libs: [ "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp index 03afcd0751..c30702cd99 100644 --- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp +++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp @@ -135,14 +135,18 @@ ExecutionCallback::~ExecutionCallback() {} Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) { mErrorStatus = errorStatus; + mOutputShapes = {}; + mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; CallbackBase::notify(); return Void(); } Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus, - const hidl_vec<OutputShape>& outputShapes) { + const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { mErrorStatus = errorStatus; mOutputShapes = outputShapes; + mTiming = timing; CallbackBase::notify(); return Void(); } @@ -157,6 +161,11 @@ const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() { return mOutputShapes; } +Timing ExecutionCallback::getTiming() { + wait(); + return mTiming; +} + } // namespace implementation } // namespace V1_2 } // namespace neuralnetworks diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h index 46f29a60e7..4707d0a251 100644 --- a/neuralnetworks/1.0/vts/functional/Callbacks.h +++ b/neuralnetworks/1.0/vts/functional/Callbacks.h @@ -308,8 +308,20 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback { * of the output operand in the Request outputs vector. * outputShapes must be empty unless the status is either * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times must + * be reported as UINT64_MAX. A driver may choose to report + * any time as UINT64_MAX, indicating that particular measurement is + * not available. */ - Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes) override; + Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) override; + + // An overload of the latest notify interface to hide the version from ExecutionBuilder. + Return<void> notify(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { + return notify_1_2(status, outputShapes, timing); + } /** * Retrieves the error status returned from the asynchronous task launched @@ -350,9 +362,24 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback { */ const std::vector<OutputShape>& getOutputShapes(); + /** + * Retrieves the duration of execution ofthe asynchronous task launched + * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished + * asynchronously executing, this call will block until the asynchronous task + * notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, every time + * must be UINT64_MAX. + * + * @return timing Duration of the execution. Every time must be UINT64_MAX unless + * the status is NONE. + */ + Timing getTiming(); + private: - ErrorStatus mErrorStatus; - std::vector<OutputShape> mOutputShapes; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + std::vector<OutputShape> mOutputShapes = {}; + Timing mTiming = {}; }; diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index d45922e1c4..0724c09ece 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ +#include "GeneratedTestHarness.h" #include "Callbacks.h" +#include "ExecutionBurstController.h" #include "TestHarness.h" #include "Utils.h" @@ -77,43 +79,56 @@ void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* sr // Top level driver for models and examples generated by test_generator.py // Test driver for those generated from ml/nn/runtime/test/spec static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>& preparedModel, - const Request& request, + const Request& request, MeasureTiming, sp<ExecutionCallback>& callback) { return preparedModel->execute(request, callback); } static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, - const Request& request, + const Request& request, MeasureTiming measure, sp<ExecutionCallback>& callback) { - return preparedModel->execute_1_2(request, callback); + return preparedModel->execute_1_2(request, measure, callback); } static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&, - hidl_vec<OutputShape>*) { + MeasureTiming, hidl_vec<OutputShape>*, Timing*) { ADD_FAILURE() << "asking for synchronous execution at V1_0"; return ErrorStatus::GENERAL_FAILURE; } static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, - const Request& request, - hidl_vec<OutputShape>* outputShapes) { + const Request& request, MeasureTiming measure, + hidl_vec<OutputShape>* outputShapes, + Timing* timing) { ErrorStatus result; Return<void> ret = preparedModel->executeSynchronously( - request, [&result, &outputShapes](ErrorStatus error, const hidl_vec<OutputShape>& shapes) { - result = error; - *outputShapes = shapes; - }); + request, measure, + [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes, + const Timing& time) { + result = error; + *outputShapes = shapes; + *timing = time; + }); if (!ret.isOk()) { return ErrorStatus::GENERAL_FAILURE; } return result; } -enum class Synchronously { NO, YES }; +static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst( + const sp<V1_0::IPreparedModel>&) { + ADD_FAILURE() << "asking for burst execution at V1_0"; + return nullptr; +} +static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst( + const sp<V1_2::IPreparedModel>& preparedModel) { + return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true); +} +enum class Executor { ASYNC, SYNC, BURST }; +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; const float kDefaultAtol = 1e-5f; const float kDefaultRtol = 1e-5f; template <typename T_IPreparedModel> void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, - bool hasRelaxedFloat32Model = false, float fpAtol = kDefaultAtol, - float fpRtol = kDefaultRtol, Synchronously sync = Synchronously::NO, - bool testDynamicOutputShape = false) { + bool hasRelaxedFloat32Model, float fpAtol, float fpRtol, + Executor executor, MeasureTiming measure, OutputType outputType) { const uint32_t INPUT = 0; const uint32_t OUTPUT = 1; @@ -161,8 +176,20 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo // Go through all outputs, initialize RequestArgument descriptors resize_accordingly(golden, test); - for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { + bool sizeLargerThanOne = true; + for_all(golden, [&outputs_info, &outputSize, &outputType, &sizeLargerThanOne]( + int index, auto, auto s) { if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1); + if (index == 0) { + // On OutputType::INSUFFICIENT, set the output operand with index 0 with + // buffer size one byte less than needed. + if (outputType == OutputType::INSUFFICIENT) { + if (s > 1) + s -= 1; + else + sizeLargerThanOne = false; + } + } RequestArgument arg = { .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)}, .dimensions = {}, @@ -170,6 +197,9 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo outputs_info[index] = arg; outputSize += s; }); + // If output0 does not have size larger than one byte, + // we can not provide an insufficient buffer + if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return; // Compute offset for outputs 1 and so on { size_t offset = 0; @@ -206,48 +236,104 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo inputMemory->commit(); outputMemory->commit(); + const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}; + ErrorStatus executionStatus; hidl_vec<OutputShape> outputShapes; - if (sync == Synchronously::NO) { - SCOPED_TRACE("asynchronous"); - - // launch execution - sp<ExecutionCallback> executionCallback = new ExecutionCallback(); - ASSERT_NE(nullptr, executionCallback.get()); - Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel( - preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}, - executionCallback); - ASSERT_TRUE(executionLaunchStatus.isOk()); - EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus)); - - // retrieve execution status - executionCallback->wait(); - executionStatus = executionCallback->getStatus(); - outputShapes = executionCallback->getOutputShapes(); - } else { - SCOPED_TRACE("synchronous"); - - // execute - Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel( - preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools}, - &outputShapes); - ASSERT_TRUE(executionReturnStatus.isOk()); - executionStatus = static_cast<ErrorStatus>(executionReturnStatus); + Timing timing; + switch (executor) { + case Executor::ASYNC: { + SCOPED_TRACE("asynchronous"); + + // launch execution + sp<ExecutionCallback> executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return<ErrorStatus> executionLaunchStatus = + ExecutePreparedModel(preparedModel, request, measure, executionCallback); + ASSERT_TRUE(executionLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus)); + + // retrieve execution status + executionCallback->wait(); + executionStatus = executionCallback->getStatus(); + outputShapes = executionCallback->getOutputShapes(); + timing = executionCallback->getTiming(); + + break; + } + case Executor::SYNC: { + SCOPED_TRACE("synchronous"); + + // execute + Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel( + preparedModel, request, measure, &outputShapes, &timing); + ASSERT_TRUE(executionReturnStatus.isOk()); + executionStatus = static_cast<ErrorStatus>(executionReturnStatus); + + break; + } + case Executor::BURST: { + SCOPED_TRACE("burst"); + + // create burst + const std::unique_ptr<::android::nn::ExecutionBurstController> controller = + CreateBurst(preparedModel); + ASSERT_NE(nullptr, controller.get()); + + // create memory keys + std::vector<intptr_t> keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]); + } + + // execute burst + std::tie(executionStatus, outputShapes, timing) = + controller->compute(request, measure, keys); + + break; + } } - if (testDynamicOutputShape && executionStatus != ErrorStatus::NONE) { + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "execute model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " "execute model that it does not support." << std::endl; - return; + GTEST_SKIP(); + } + if (measure == MeasureTiming::NO) { + EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); + EXPECT_EQ(UINT64_MAX, timing.timeInDriver); + } else { + if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) { + EXPECT_LE(timing.timeOnDevice, timing.timeInDriver); + } } - ASSERT_EQ(ErrorStatus::NONE, executionStatus); + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == test.operandDimensions.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } // Go through all outputs, overwrite output dimensions with returned output shapes - if (testDynamicOutputShape) { - ASSERT_NE(outputShapes.size(), 0); + if (outputShapes.size() > 0) { for_each<uint32_t>(test.operandDimensions, [&outputShapes](int idx, std::vector<uint32_t>& dim) { dim = outputShapes[idx].dimensions; @@ -273,10 +359,55 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo template <typename T_IPreparedModel> void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, - bool hasRelaxedFloat32Model, Synchronously sync, - bool testDynamicOutputShape) { + bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure, + OutputType outputType) { EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol, - kDefaultRtol, sync, testDynamicOutputShape); + kDefaultRtol, executor, measure, outputType); +} + +void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, + std::function<bool(int)> is_ignored, + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape) { + if (testDynamicOutputShape) { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT); + } else { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + } } static void getPreparedModel(sp<PreparedModelCallback> callback, @@ -325,15 +456,15 @@ void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> c std::cout << "[ ] Early termination of test because vendor service cannot " "prepare model that it does not support." << std::endl; - return; + GTEST_SKIP(); } EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel.get()); float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f; EvaluatePreparedModel(preparedModel, is_ignored, examples, - /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Synchronously::NO, - /*testDynamicOutputShape=*/false); + /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC, + MeasureTiming::NO, OutputType::FULLY_SPECIFIED); } void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model, @@ -373,22 +504,18 @@ void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> c std::cout << "[ ] Early termination of test because vendor service cannot " "prepare model that it does not support." << std::endl; - return; + GTEST_SKIP(); } EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); ASSERT_NE(nullptr, preparedModel.get()); EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Synchronously::NO, - /*testDynamicOutputShape=*/false); + model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC, + MeasureTiming::NO, OutputType::FULLY_SPECIFIED); } -// TODO: Reduce code duplication. -void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, - std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, - bool testDynamicOutputShape) { - V1_2::Model model = create_model(); - +void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model, + sp<V1_2::IPreparedModel>* preparedModel) { // see if service can handle model bool fullySupportsModel = false; Return<void> supportedCall = device->getSupportedOperations_1_2( @@ -411,12 +538,11 @@ void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> c // retrieve prepared model preparedModelCallback->wait(); ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp<V1_2::IPreparedModel> preparedModel; - getPreparedModel(preparedModelCallback, &preparedModel); + getPreparedModel(preparedModelCallback, preparedModel); // early termination if vendor service cannot fully prepare model if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); + ASSERT_EQ(nullptr, preparedModel->get()); LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "prepare model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " @@ -425,14 +551,21 @@ void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> c return; } EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, preparedModel->get()); +} +// TODO: Reduce code duplication. +void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, + bool testDynamicOutputShape) { + V1_2::Model model = create_model(); + sp<V1_2::IPreparedModel> preparedModel = nullptr; + PrepareModel(device, model, &preparedModel); + if (preparedModel == nullptr) { + GTEST_SKIP(); + } EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Synchronously::NO, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Synchronously::YES, - testDynamicOutputShape); + model.relaxComputationFloat32toFloat16, testDynamicOutputShape); } } // namespace generated_tests diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..c7d23993f4 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,57 @@ +/* + * 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 VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H +#define VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H + +#include "TestHarness.h" + +#include <android/hardware/neuralnetworks/1.0/IDevice.h> +#include <android/hardware/neuralnetworks/1.1/IDevice.h> +#include <android/hardware/neuralnetworks/1.2/IDevice.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { + +namespace generated_tests { +using ::test_helper::MixedTypedExample; + +void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model, + sp<V1_2::IPreparedModel>* preparedModel); + +void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, + std::function<bool(int)> is_ignored, + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape); + +void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples); + +void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples); + +void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, + bool testDynamicOutputShape = false); + +} // namespace generated_tests + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp index 55e5861dec..d1c7de322f 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_0::IDevice>&, std::function<V1_0::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_0 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp index d98ea04310..4db12769a7 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_1 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp index 1df3218feb..e67ef8ed98 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_1 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp index d8762b093c..9057b9423b 100644 --- a/neuralnetworks/1.2/Android.bp +++ b/neuralnetworks/1.2/Android.bp @@ -8,6 +8,8 @@ hidl_interface { }, srcs: [ "types.hal", + "IBurstCallback.hal", + "IBurstContext.hal", "IDevice.hal", "IExecutionCallback.hal", "IPreparedModel.hal", @@ -20,6 +22,9 @@ hidl_interface { "android.hidl.safe_union@1.0", ], types: [ + "DeviceType", + "FmqRequestDatum", + "FmqResultDatum", "Model", "Operand", "OperandType", @@ -28,6 +33,7 @@ hidl_interface { "OperationType", "OperationTypeRange", "OutputShape", + "SymmPerChannelQuantParams", ], gen_java: false, } diff --git a/neuralnetworks/1.2/IBurstCallback.hal b/neuralnetworks/1.2/IBurstCallback.hal new file mode 100644 index 0000000000..3f82e3152b --- /dev/null +++ b/neuralnetworks/1.2/IBurstCallback.hal @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.2; + +import @1.0::ErrorStatus; + +/** + * Callback object used by a service to retreive memory objects based on unique + * identifiers ("slots"). + */ +interface IBurstCallback { + /** + * Get the memory regions that correspond to slot ids. The slot ids are are + * unique to the burst object. + * + * @param slots Values uniquely identifying memory regions within a Burst. + * @return status Indicates whether the memories were successfully returned; + * must be: + * - NONE if the memory region was successfully retrieved + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if a slot number is invalid + * @return buffers Memory buffers corresponding to the slot numbers. If an + * error occurs, an empty vector must be returned for + * buffers, otherwise slots.size() == buffers.size(). + */ + getMemories(vec<int32_t> slots) generates (ErrorStatus status, vec<memory> buffers); +}; diff --git a/neuralnetworks/1.2/IBurstContext.hal b/neuralnetworks/1.2/IBurstContext.hal new file mode 100644 index 0000000000..60bf53b1de --- /dev/null +++ b/neuralnetworks/1.2/IBurstContext.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.neuralnetworks@1.2; + +/** + * Context object to manage the resources of a burst. + */ +interface IBurstContext { + /** + * freeMemory is used by the client to signal to the service that a memory + * buffer corresponding to a slot number is no longer needed by the client. + * + * The slot ids are unique to the burst object. + * + * @param slot Value uniquely identifying a memory region. + */ + freeMemory(int32_t slot); +}; diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal index 6c3b4839e1..b9fa38870e 100644 --- a/neuralnetworks/1.2/IDevice.hal +++ b/neuralnetworks/1.2/IDevice.hal @@ -76,6 +76,21 @@ interface IDevice extends @1.1::IDevice { getType() generates (ErrorStatus status, DeviceType type); /** + * Gets information about extensions supported by the driver implementation. + * + * All extension operations and operands must be fully supported for the + * extension to appear in the list of supported extensions. + * + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * @return extensions A list of supported extensions. + */ + getSupportedExtensions() + generates (ErrorStatus status, vec<Extension> extensions); + + /** * Gets the supported operations in a model. * * getSupportedOperations indicates which operations of a model are fully @@ -98,6 +113,25 @@ interface IDevice extends @1.1::IDevice { generates (ErrorStatus status, vec<bool> supportedOperations); /** + * Gets whether the driver supports compilation caching. + * + * isCachingSupported indicates whether the driver supports compilation caching. + * Even if so, the driver may still choose not to cache certain compiled models. + * + * If the device reports the caching is not supported, the user may avoid calling + * IDevice::prepareModelFromCache and IPreparedModel::saveToCache. + * + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * @return supported A boolean indicating whether the driver supports compilation + * caching. Even on returning true, the driver may still choose + * not to cache certain compiled models. + */ + isCachingSupported() generates (ErrorStatus status, bool supported); + + /** * Creates a prepared model for execution. * * prepareModel is used to make any necessary transformations or alternative @@ -153,4 +187,84 @@ interface IDevice extends @1.1::IDevice { prepareModel_1_2(Model model, ExecutionPreference preference, IPreparedModelCallback callback) generates (ErrorStatus status); + + /** + * Creates a prepared model from cache files for execution. + * + * prepareModelFromCache is used to retrieve a prepared model directly from + * cache files to avoid slow model compilation time. There are exactly two + * cache file descriptors provided to the driver: modelCache and dataCache. + * + * The dataCache is for caching constant data, possibly including preprocessed + * and transformed tensor buffers. Any modification to the dataCache should + * have no worse effect than generating bad output values at execution time. + * + * The modelCache is for caching security-sensitive data such as compiled + * executable machine code in the device's native binary format. A modification + * to the modelCache may affect the driver's execution behavior, and a malicious + * client could make use of this to execute beyond the granted permission. Thus, + * the driver must always check whether the modelCache is corrupted before preparing + * the model from cache. + * + * The two file descriptors may be closed by the client once the asynchronous + * preparation has finished. The driver has to copy all the data it needs. + * + * The model is prepared asynchronously with respect to the caller. The + * prepareModelFromCache function must verify the inputs to the + * prepareModelFromCache function are correct, and that the security-sensitive + * cache has not been modified since it was last written by the driver. + * If there is an error, or if compilation caching is not supported, or if the + * security-sensitive cache has been modified, prepareModelFromCache must + * immediately invoke the callback with the appropriate ErrorStatus value and + * nullptr for the IPreparedModel, then return with the same ErrorStatus. If + * the inputs to the prepareModelFromCache function are valid, the security-sensitive + * cache is not modified, and there is no error, prepareModelFromCache must launch an + * asynchronous task to prepare the model in the background, and immediately return + * from prepareModelFromCache with ErrorStatus::NONE. If the asynchronous task + * fails to launch, prepareModelFromCache must immediately invoke the callback + * with ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then + * return with ErrorStatus::GENERAL_FAILURE. + * + * When the asynchronous task has finished preparing the model, it must + * immediately invoke the callback function provided as an input to + * prepareModelFromCache. If the model was prepared successfully, the + * callback object must be invoked with an error status of ErrorStatus::NONE + * and the produced IPreparedModel object. If an error occurred preparing + * the model, the callback object must be invoked with the appropriate + * ErrorStatus value and nullptr for the IPreparedModel. + * + * The only information that may be unknown to the model at this stage is + * the shape of the tensors, which may only be known at execution time. As + * such, some driver services may return partially prepared models, where + * the prepared model may only be finished when it is paired with a set of + * inputs to the model. Note that the same prepared model object may be + * used with different shapes of inputs on different (possibly concurrent) + * executions. + * + * @param modelCache A handle holding exactly one cache file descriptor for the + * security-sensitive cache. + * @param dataCache A handle holding exactly one cache file descriptor for the + * constants' cache. + * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN + * identifying the prepared model. It is the same token provided when saving + * the cache files with IPreparedModel::saveToCache. Tokens should be chosen + * to have a low rate of collision for a particular application. The driver + * cannot detect a collision; a collision will result in a failed execution + * or in a successful execution that produces incorrect output values. + * @param callback A callback object used to return the error status of + * preparing the model for execution and the prepared model if + * successful, nullptr otherwise. The callback object's notify function + * must be called exactly once, even if the model could not be prepared. + * @return status Error status of launching a task which prepares the model + * in the background; must be: + * - NONE if preparation task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if caching is not supported or if there is an + * unspecified error + * - INVALID_ARGUMENT if one of the input arguments is invalid + */ + prepareModelFromCache(handle modelCache, handle dataCache, + uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token, + IPreparedModelCallback callback) + generates (ErrorStatus status); }; diff --git a/neuralnetworks/1.2/IExecutionCallback.hal b/neuralnetworks/1.2/IExecutionCallback.hal index 47de1b60ec..7f6c9eeffe 100644 --- a/neuralnetworks/1.2/IExecutionCallback.hal +++ b/neuralnetworks/1.2/IExecutionCallback.hal @@ -18,7 +18,6 @@ package android.hardware.neuralnetworks@1.2; import @1.0::ErrorStatus; import @1.0::IExecutionCallback; -import OutputShape; /** * IExecutionCallback must be used to return the error status result from an @@ -50,6 +49,11 @@ interface IExecutionCallback extends @1.0::IExecutionCallback { * of the output operand in the Request outputs vector. * outputShapes must be empty unless the status is either * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times must + * be reported as UINT64_MAX. A driver may choose to report + * any time as UINT64_MAX, indicating that particular measurement is + * not available. */ - oneway notify_1_2(ErrorStatus status, vec<OutputShape> outputShapes); + oneway notify_1_2(ErrorStatus status, vec<OutputShape> outputShapes, Timing timing); }; diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal index 044ca289b9..757d5f1467 100644 --- a/neuralnetworks/1.2/IPreparedModel.hal +++ b/neuralnetworks/1.2/IPreparedModel.hal @@ -19,6 +19,8 @@ package android.hardware.neuralnetworks@1.2; import @1.0::ErrorStatus; import @1.0::IPreparedModel; import @1.0::Request; +import IBurstCallback; +import IBurstContext; import IExecutionCallback; /** @@ -57,6 +59,10 @@ interface IPreparedModel extends @1.0::IPreparedModel { * * @param request The input and output information on which the prepared * model is to be executed. + * @param measure Specifies whether or not to measure duration of the execution. + * The duration runs from the time the driver sees the call + * to the execute_1_2 function to the time the driver invokes + * the callback. * @param callback A callback object used to return the error status of * the execution. The callback object's notify function must * be called exactly once, even if the execution was @@ -70,7 +76,7 @@ interface IPreparedModel extends @1.0::IPreparedModel { * - INVALID_ARGUMENT if one of the input arguments is * invalid */ - execute_1_2(Request request, IExecutionCallback callback) + execute_1_2(Request request, MeasureTiming measure, IExecutionCallback callback) generates (ErrorStatus status); /** @@ -96,6 +102,10 @@ interface IPreparedModel extends @1.0::IPreparedModel { * * @param request The input and output information on which the prepared * model is to be executed. + * @param measure Specifies whether or not to measure duration of the execution. + * The duration runs from the time the driver sees the call + * to the executeSynchronously function to the time the driver + * returns from the function. * @return status Error status of the execution, must be: * - NONE if execution is performed successfully * - DEVICE_UNAVAILABLE if driver is offline or busy @@ -110,7 +120,99 @@ interface IPreparedModel extends @1.0::IPreparedModel { * of the output operand in the Request outputs vector. * outputShapes must be empty unless the status is either * NONE or OUTPUT_INSUFFICIENT_SIZE. + * @return Timing Duration of execution. Unless measure is YES and status is + * NONE, all times must be reported as UINT64_MAX. A driver may + * choose to report any time as UINT64_MAX, indicating that + * measurement is not available. */ - executeSynchronously(Request request) - generates (ErrorStatus status, vec<OutputShape> outputShapes); + executeSynchronously(Request request, MeasureTiming measure) + generates (ErrorStatus status, vec<OutputShape> outputShapes, Timing timing); + + /** + * Configure a Burst object used to execute multiple inferences on a + * prepared model in rapid succession. + * + * @param callback A callback object used to retrieve memory resources + * corresponding to a unique identifiers ("slots"). + * @param requestChannel Used by the client to send a serialized Request to + * the Burst for execution. requestChannel must not be + * used to pass a second Request object until a result + * has been received from resultChannel. + * @param resultChannel Used by the service to return the results of an + * execution to the client: the status of the execution + * and OutputShape of all output tensors. resultChannel + * must be used to return the results if a Request was + * sent through the requestChannel. + * @return status Error status of configuring the execution burst, must be: + * - NONE if the burst is successfully configured + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments is + * invalid + * @return context Object containing all resources (such as cached + * hidl_memory) related to a Burst if successful, otherwise + * nullptr. + */ + configureExecutionBurst(IBurstCallback callback, + fmq_sync<FmqRequestDatum> requestChannel, + fmq_sync<FmqResultDatum> resultChannel) + generates (ErrorStatus status, IBurstContext context); + + /* + * Saves the prepared model to cache files. + * + * saveToCache is used to save a prepared model to cache files for faster + * model compilation time when the same model preparation is requested in + * the future. There are exactly two cache file descriptors provided to the + * driver: modelCache and dataCache. + * + * The dataCache is for caching constant data, possibly including preprocessed + * and transformed tensor buffers. Any modification to the dataCache should + * have no worse effect than generating bad output values at execution time. + * + * The modelCache is for caching security-sensitive data such as compiled + * executable machine code in the device's native binary format. A modification + * to the modelCache may affect the driver's execution behavior, and a malicious + * client could make use of this to execute beyond the granted permission. Thus, + * the driver must always check whether the modelCache is corrupted before preparing + * the model from cache. + * + * The two file descriptors must point to two zero-length files with offset + * positioned at the beginning of the file. The file descriptors may be closed + * by the client once the method has returned. + * + * If the driver decides not to save the prepared model without looking at the + * input arguments to the saveToCache function, saveToCache must return with + * ErrorStatus::GENERAL_FAILURE. Otherwise, the saveToCache function must verify + * the input arguments to the saveToCache function are valid, and return with + * ErrorStatus::INVALID_ARGUMENT if not. If the inputs are valid but the driver + * could not save the prepared model, saveToCache must return with the appropriate + * ErrorStatus. Otherwise, it must write the cache files and return + * ErrorStatus::NONE. Unless saveToCache returns ErrorStatus::NONE, the contents + * of the cache files are undefined. + * + * @param modelCache A handle holding exactly one cache file descriptor for the + * security-sensitive cache. + * @param dataCache A handle holding exactly one cache file descriptor for the + * constants' cache. + * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN + * identifying the prepared model. The same token will be provided + * when retrieving the prepared model from cache files with + * IDevice::prepareModelFromCache. Tokens should be chosen to have + * a low rate of collision for a particular application. The driver + * cannot detect a collision; a collision will result in a failed + * execution or in a successful execution that produces incorrect + * output values. + * @return status Error status of saveToCache, must be: + * - NONE if saveToCache is performed successfully + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the driver could not save the + * prepared model or if there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments is invalid, + * unless the driver decides not to save the prepared model + * without looking at the input arguments + */ + saveToCache(handle modelCache, handle dataCache, + uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token) + generates (ErrorStatus status); }; diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index ac944c8e56..5b1c7f9f7f 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -17,6 +17,7 @@ package android.hardware.neuralnetworks@1.2; import @1.0::DataLocation; +import @1.0::ErrorStatus; import @1.0::OperandLifeTime; import @1.0::OperandType; import @1.0::PerformanceInfo; @@ -24,6 +25,13 @@ import @1.1::OperationType; import android.hidl.safe_union@1.0::Monostate; +enum Constant : uint32_t { + /** + * The byte size of the cache token. + */ + BYTE_SIZE_OF_CACHE_TOKEN = 32, +}; + enum OperandType : @1.0::OperandType { /** * An 8 bit boolean scalar value. @@ -39,7 +47,7 @@ enum OperandType : @1.0::OperandType { * used to convert the 16 bit number to a real value in the following way: * realValue = integerValue * scale. * - * scale is a 32 bit floating point with value greater then zero. + * scale is a 32 bit floating point with value greater than zero. */ TENSOR_QUANT16_SYMM = 7, /** A tensor of IEEE 754 16 bit floating point values. */ @@ -65,10 +73,11 @@ enum OperandType : @1.0::OperandType { * These fields are located inside Operand's extraParams union, inside the * SymmPerChannelQuantParams struct. * - * An Operand of this type must use 'channelQuant' field of its extraParams - * union. + * An Operand of this type must use the 'channelQuant' variant of its + * extraParams field. * - * The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0). + * The channel dimension of this tensor must be known, i.e. + * dimensions[channelDim] must be non-zero. * * The formula for real values: * realValue[..., C, ...] = @@ -88,11 +97,21 @@ enum OperandType : @1.0::OperandType { * real_value = (integer_value - zeroPoint) * scale. */ TENSOR_QUANT16_ASYMM = 12, + /** + * A tensor of 8 bit signed integers that represent real numbers. + * + * Attached to this tensor is a number representing real value scale that is + * used to convert the 8 bit number to a real value in the following way: + * realValue = integerValue * scale. + * + * scale is a 32 bit floating point with value greater than zero. + */ + TENSOR_QUANT8_SYMM = 13, /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::OPERAND_FUNDAMENTAL_MAX. + * OperandTypeRange::FUNDAMENTAL_MAX. */ /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::OPERAND_OEM_MAX. + * OperandTypeRange::OEM_MAX. */ }; @@ -100,10 +119,12 @@ enum OperandType : @1.0::OperandType { * The range of operand values in the OperandType enum. */ enum OperandTypeRange : uint32_t { - OPERAND_FUNDAMENTAL_MIN = 0, - OPERAND_FUNDAMENTAL_MAX = 12, - OPERAND_OEM_MIN = 10000, - OPERAND_OEM_MAX = 10001, + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 13, + OEM_MIN = 10000, + OEM_MAX = 10001, + BASE_MAX = 0xFFFF, }; /** @@ -113,17 +134,17 @@ enum OperandTypeRange : uint32_t { */ enum OperationType : @1.1::OperationType { // TODO(b/116445845): Sync docs when all ops are implemented. - ARGMAX = 38, - ARGMIN = 39, - PAD_V2 = 40, + ABS = 38, + ARGMAX = 39, + ARGMIN = 40, AXIS_ALIGNED_BBOX_TRANSFORM = 41, BIDIRECTIONAL_SEQUENCE_LSTM = 42, BIDIRECTIONAL_SEQUENCE_RNN = 43, BOX_WITH_NMS_LIMIT = 44, CAST = 45, CHANNEL_SHUFFLE = 46, - DETECTION_OUTPUT = 47, - EMBEDDING_LOOKUP_SPARSE = 48, + DETECTION_POSTPROCESSING = 47, + EQUAL = 48, EXP = 49, EXPAND_DIMS = 50, GATHER = 51, @@ -132,52 +153,48 @@ enum OperationType : @1.1::OperationType { GREATER_EQUAL = 54, GROUPED_CONV_2D = 55, HEATMAP_MAX_KEYPOINT = 56, - LESS = 57, - LESS_EQUAL = 58, - LOG = 59, - LOGICAL_AND = 60, - LOGICAL_NOT = 61, - LOGICAL_OR = 62, - LOG_SOFTMAX = 63, - MAXIMUM = 64, - MINIMUM = 65, - NEG = 66, - POW = 67, - PRELU = 68, - PRIOR_BOX = 69, - QUANTIZE = 70, - QUANTIZED_16BIT_LSTM = 71, - RANDOM_MULTINOMIAL = 72, - REDUCE_PROD = 73, - ROI_ALIGN = 74, - RSQRT = 75, - SELECT = 76, - SIN = 77, - SLICE = 78, - SPARSE_TO_DENSE = 79, - SPLIT = 80, - SQRT = 81, - TILE = 82, - TOPK_V2 = 83, - TRANSPOSE_CONV_2D = 84, - UNIDIRECTIONAL_SEQUENCE_LSTM = 85, - UNIDIRECTIONAL_SEQUENCE_RNN = 86, - DETECTION_POSTPROCESSING = 87, - ABS = 88, - ROI_POOLING = 89, - EQUAL = 90, - NOT_EQUAL = 91, - REDUCE_SUM = 92, - REDUCE_MAX = 93, - REDUCE_MIN = 94, - REDUCE_ANY = 95, - REDUCE_ALL = 96, - INSTANCE_NORMALIZATION = 97, + INSTANCE_NORMALIZATION = 57, + LESS = 58, + LESS_EQUAL = 59, + LOG = 60, + LOGICAL_AND = 61, + LOGICAL_NOT = 62, + LOGICAL_OR = 63, + LOG_SOFTMAX = 64, + MAXIMUM = 65, + MINIMUM = 66, + NEG = 67, + NOT_EQUAL = 68, + PAD_V2 = 69, + POW = 70, + PRELU = 71, + QUANTIZE = 72, + QUANTIZED_16BIT_LSTM = 73, + RANDOM_MULTINOMIAL = 74, + REDUCE_ALL = 75, + REDUCE_ANY = 76, + REDUCE_MAX = 77, + REDUCE_MIN = 78, + REDUCE_PROD = 79, + REDUCE_SUM = 80, + ROI_ALIGN = 81, + ROI_POOLING = 82, + RSQRT = 83, + SELECT = 84, + SIN = 85, + SLICE = 86, + SPLIT = 87, + SQRT = 88, + TILE = 89, + TOPK_V2 = 90, + TRANSPOSE_CONV_2D = 91, + UNIDIRECTIONAL_SEQUENCE_LSTM = 92, + UNIDIRECTIONAL_SEQUENCE_RNN = 93, /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF - * OperationTypeRange::OPERATION_FUNDAMENTAL_MAX. + * OperationTypeRange::FUNDAMENTAL_MAX. */ /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF - * OperationTypeRange::OPERATION_OEM_MAX. + * OperationTypeRange::OEM_MAX. */ }; @@ -185,10 +202,12 @@ enum OperationType : @1.1::OperationType { * The range of values in the OperationType enum. */ enum OperationTypeRange : uint32_t { - OPERATION_FUNDAMENTAL_MIN = 0, - OPERATION_FUNDAMENTAL_MAX = 97, - OPERATION_OEM_MIN = 10000, - OPERATION_OEM_MAX = 10000, + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 93, + OEM_MIN = 10000, + OEM_MAX = 10000, + BASE_MAX = 0xFFFF, }; /** @@ -217,6 +236,10 @@ enum DeviceType : int32_t { struct Operation { /** * The operation type. + * + * Besides the values listed in {@link OperationType}, any value above + * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. */ OperationType type; @@ -243,21 +266,16 @@ struct SymmPerChannelQuantParams { uint32_t channelDim; }; -// TODO(slavash): Operand Extension support -// /** -// * Parameters for an unknown (as of 1.2) operand extension. This is -// * a vendor-specific extension or a platform extension (backport of -// * functionality from newer NNAPI interface). -// */ -// struct OperandParamsUnknown { -// }; - /** * Describes one operand of the model's graph. */ struct Operand { /** - * Data type of the operand. + * The data type. + * + * Besides the values listed in {@link OperandType}, any value above + * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. */ OperandType type; @@ -347,25 +365,28 @@ struct Operand { DataLocation location; /** - * Union of extra parameters, used by some types of Operands that need additional - * information for the complete definition of an Operand. + * Additional parameters specific to a particular operand type. */ safe_union ExtraParams { /** - * Placeholder for operand with no extra parameters. + * No additional parameters. */ Monostate none; /** - * Used with TENSOR_QUANT8_SYMM_PER_CHANNEL operand type. + * Symmetric per-channel quantization parameters. + * + * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. */ SymmPerChannelQuantParams channelQuant; - // TODO(slavash): Operand Extension support - // /** - // * Used with Extension operand type. - // */ - // OperandParamsUnknown unknown; + /** + * Extension operand parameters. + * + * The framework treats this as an opaque data blob. + * The format is up to individual extensions. + */ + vec<uint8_t> extension; } extraParams; }; @@ -428,6 +449,63 @@ struct Model { * range and precision of the IEEE 754 32-bit floating-point format. */ bool relaxComputationFloat32toFloat16; + + /** + * The mapping between extension names and prefixes of operand and + * operation type values. + * + * An operand or operation whose numeric type value is above + * {@link OperandTypeRange::BASE_MAX} or + * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted + * as an extension operand. The low + * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value + * correspond to the type ID within the extension and the high + * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * the "prefix", which maps uniquely to the extension name. + * + * For example, if a model contains an operation whose value is + * 0xAAAABBBB and extensionNameToPrefix contains an entry with + * prefix=0xAAAA and name="vendor.test.test_extension", then + * the operation should be interpreted as the operation 0xBBBB + * of the extension named vendor.test.test_extension. + * + * This is a one-to-one correspondence. That is, there must be at most one + * prefix corresponding to each extension name and at most one extension + * name corresponding to each prefix. + */ + vec<ExtensionNameAndPrefix> extensionNameToPrefix; + + /** + * A correspondence between an extension name and a prefix of operand and + * operation type values. + */ + struct ExtensionNameAndPrefix { + /** + * The extension name. + * + * See {@link Extension::name}. + */ + string name; + + /** + * The unique extension identifier within the model. + * + * See {@link Model::extensionNameToPrefix}. + */ + uint16_t prefix; + }; + + /** + * Numeric values of extension operand and operation types have the + * following structure: + * - 16 high bits represent the "prefix", which corresponds uniquely to the + * extension name. + * - 16 low bits represent the type ID within the extension. + */ + enum ExtensionTypeEncoding : uint8_t { + HIGH_BITS_PREFIX = 16, + LOW_BITS_TYPE = 16, + }; }; /** @@ -444,3 +522,280 @@ struct OutputShape { */ bool isSufficient; }; + +/** + * Specifies whether or not to measure timing information during execution. + */ +enum MeasureTiming : int32_t { + NO = 0, + YES = 1, +}; + +/** + + * Timing information measured during execution. Each time is a duration from + * the beginning of some task to the end of that task, including time when that + * task is not active (for example, preempted by some other task, or + * waiting for some resource to become available). + * + * Times are measured in microseconds. + * When a time is not available, it must be reported as UINT64_MAX. + */ +struct Timing { + /** Execution time on device (not driver, which runs on host processor). */ + uint64_t timeOnDevice; + /** Execution time in driver (including time on device). */ + uint64_t timeInDriver; +}; + +/** + * FmqRequestDatum is a single element of a serialized representation of an + * execution request (a {@link @1.0::Request} object and a {@link MeasureTiming} + * value) which is sent across FastMessageQueue. + * + * The serialized representation for a particular execution is referred to later + * in these descriptions as a 'packet'. + * + * FastMessageQueue can only pass HIDL-defined types that do not involve nested + * buffers, handles, or interfaces. + * + * The request is serialized as follows: + * 1) 'packetInformation' + * 2) For each input operand: + * 2.1) 'inputOperandInformation' + * 2.2) For each dimension element of the operand: + * 2.2.1) 'inputOperandDimensionValue' + * 3) For each output operand: + * 3.1) 'outputOperandInformation' + * 3.2) For each dimension element of the operand: + * 3.2.1) 'outputOperandDimensionValue' + * 4) For each pool: + * 4.1) 'poolIdentifier' + * 5) 'measureTiming' + */ +safe_union FmqRequestDatum { + /** + * Type to describe the high-level layout of the packet. + */ + struct PacketInformation { + /** + * How many elements the packet contains, including the + * "packetInformation" datum. + */ + uint32_t packetSize; + + /** + * Number of input operands. + */ + uint32_t numberOfInputOperands; + + /** + * Number of output operands. + */ + uint32_t numberOfOutputOperands; + + /** + * Number of pool identifiers. + */ + uint32_t numberOfPools; + }; + + /** + * Type representing the information for each operand. + */ + struct OperandInformation { + /** + * If true, the argument does not have a value. This can be used for + * operations that take optional arguments. If true, the fields of + * 'location' are set to 0, 'numberOfDimensions' is set to 0, and the + * dimensions information is omitted from the serialization. + */ + bool hasNoValue; + + /** + * The location within one of the memory pools passed in the Request. + */ + DataLocation location; + + /** + * Number of subsequent elements that belong to the dimensions vector. + */ + uint32_t numberOfDimensions; + }; + + /** + * packetInformation is the first element of the packet and describes the + * remainder of the packet. + */ + PacketInformation packetInformation; + + /** + * Information for each input operand. + */ + OperandInformation inputOperandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t inputOperandDimensionValue; + + /** + * Information for each output operand. + */ + OperandInformation outputOperandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t outputOperandDimensionValue; + + /** + * Unique identifier for a pool. + * + * A {@link @1.0::Request} passes across one or more pools of shared memory + * for the inputs and outputs of an execution. However, these memory pools + * are not able to be sent across FastMessageQueue directly. Instead, the + * producing side of the FMQ represents each different pool with a unique + * identifier, and sends this identifier across the FMQ. Whenever the + * consuming side of the FMQ needs the memory corresponding to this unique + * identifier, it can pass the identifier to + * {@link IBurstCallback::getMemories} to retreive the memory. Although this + * HIDL Binder call is expensive compared to communication across FMQ, it is + * only needed in the cases when the consumer does not recognize the unique + * identifier. + */ + int32_t poolIdentifier; + + /** + * Specifies whether or not to measure duration of the execution. The + * duration runs from the time the driver dequeues the request from a + * FastMessageQueue to the time the driver enqueues results to a + * FastMessageQueue. + */ + MeasureTiming measureTiming; +}; + +/** + * FmqResultDatum is a single element of a serialized representation of the + * values returned from an execution ({@link @1.0::ErrorStatus}, + * vec<{@link OutputShape}>, and {@link Timing}) which is returned via + * FastMessageQueue. + * + * The serialized representation for a particular execution is referred to later + * in these descriptions as a 'packet'. + * + * FastMessageQueue can only pass HIDL-defined types that do not involve nested + * buffers, handles, or interfaces. + * + * The execution return values ({@link @1.0::ErrorStatus} and + * vec<{@link OutputShape}>) are serialized as follows: + * 1) 'packetInformation' + * 2) For each returned operand: + * 2.1) 'operandInformation' + * 2.2) For each dimension element of the operand: + * 2.2.1) 'operandDimensionValue' + * 3) 'executionTiming' + */ +safe_union FmqResultDatum { + /** + * Type to describe the high-level layout of the packet. + */ + struct PacketInformation { + /** + * How many elements the packet contains, including the + * "packetInformation" datum. + */ + uint32_t packetSize; + + /** + * Status of the execution. + */ + ErrorStatus errorStatus; + + /** + * Number of returned operands. + */ + uint32_t numberOfOperands; + }; + + /** + * Type representing the information for each operand. + */ + struct OperandInformation { + /** + * Indicates whether the operand's output buffer is large enough to + * store the operand's result data. + */ + bool isSufficient; + + /** + * Number of subsequent elements that belong to the dimensions vector. + */ + uint32_t numberOfDimensions; + }; + + /** + * packetInformation is the first element of the packet and describes the + * remainder of the packet. It additionally includes the status of the + * execution. + */ + PacketInformation packetInformation; + + /** + * Information for each returned operand. + */ + OperandInformation operandInformation; + + /** + * Element of the dimensions vector. + */ + uint32_t operandDimensionValue; + + /** + * Duration of execution. Unless measurement was requested and execution + * succeeds, all times must be reported as UINT64_MAX. A driver may choose + * to report any time as UINT64_MAX, indicating that measurement is not + * available. + */ + Timing executionTiming; +}; + +/** + * Information about an extension. + */ +struct Extension { + /** + * The extension name. + * + * The name must start with the reverse domain name of the vendor. + * Example: com.google.test_extension + */ + string name; + + /** + * Information about an extension operand type. + */ + struct OperandTypeInformation { + /** + * The extension operand type. + */ + uint16_t type; + + /** + * Indicates whether the extension operand type represents a tensor or + * a scalar. + */ + bool isTensor; + + /** + * The byte size of the operand (if scalar) or of a single element (if + * tensor). + */ + uint32_t byteSize; + }; + + /** + * Information about operand types defined by the extension. + */ + vec<OperandTypeInformation> operandTypes; +}; diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 0cb9e16fcf..510a0d5b3c 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -46,6 +46,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], srcs: [ "BasicTests.cpp", + "CompilationCachingTests.cpp", "GeneratedTests.cpp", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 8c3ad15e2a..2b88edd0f6 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -55,6 +55,29 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { }); EXPECT_TRUE(ret.isOk()); } + +// device supported extensions test +TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { + Return<void> ret = device->getSupportedExtensions( + [](ErrorStatus status, const hidl_vec<Extension>& extensions) { + EXPECT_EQ(ErrorStatus::NONE, status); + for (auto& extension : extensions) { + std::string extensionName = extension.name; + EXPECT_FALSE(extensionName.empty()); + EXPECT_NE(extensionName.find("."), std::string::npos) + << "Extension name must start with the reverse domain name of the " + "vendor"; + } + }); + EXPECT_TRUE(ret.isOk()); +} + +// isCachingSupported test +TEST_F(NeuralnetworksHidlTest, IsCachingSupported) { + Return<void> ret = device->isCachingSupported( + [](ErrorStatus status, bool) { EXPECT_EQ(ErrorStatus::NONE, status); }); + EXPECT_TRUE(ret.isOk()); +} } // namespace functional } // namespace vts } // namespace V1_2 diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp new file mode 100644 index 0000000000..454aa1f921 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -0,0 +1,652 @@ +/* + * 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 "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +#include "Callbacks.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" + +#include <android-base/logging.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> +#include <cstdio> +#include <cstdlib> +#include <random> + +#include <gtest/gtest.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_2 { +namespace vts { +namespace functional { + +using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::nn::allocateSharedMemory; +using ::test_helper::MixedTypedExample; + +namespace { + +// In frameworks/ml/nn/runtime/tests/generated/, creates a hidl model of mobilenet. +#include "examples/mobilenet_224_gender_basic_fixed.example.cpp" +#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp" + +// Prevent the compiler from complaining about an otherwise unused function. +[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; +[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape; + +enum class AccessMode { READ_ONLY, WRITE_ONLY }; + +void createCacheHandle(const std::vector<std::string>& files, AccessMode mode, + hidl_handle* handle) { + std::vector<int> fds; + for (const auto& file : files) { + int fd; + if (mode == AccessMode::READ_ONLY) { + fd = open(file.c_str(), O_RDONLY); + } else if (mode == AccessMode::WRITE_ONLY) { + fd = open(file.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); + } else { + FAIL(); + } + ASSERT_GE(fd, 0); + fds.push_back(fd); + } + native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0); + ASSERT_NE(cacheNativeHandle, nullptr); + for (uint32_t i = 0; i < fds.size(); i++) { + cacheNativeHandle->data[i] = fds[i]; + } + handle->setTo(cacheNativeHandle, /*shouldOwn=*/true); +} + +} // namespace + +// Tag for the compilation caching tests. +class CompilationCachingTest : public NeuralnetworksHidlTest { + protected: + void SetUp() override { + NeuralnetworksHidlTest::SetUp(); + + // Create cache directory. + char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX"; + char* cacheDir = mkdtemp(cacheDirTemp); + ASSERT_NE(cacheDir, nullptr); + mCache1 = cacheDir + mCache1; + mCache2 = cacheDir + mCache2; + mCache3 = cacheDir + mCache3; + + // Check if caching is supported. + bool isCachingSupported; + Return<void> ret = device->isCachingSupported( + [&isCachingSupported](ErrorStatus status, bool supported) { + EXPECT_EQ(ErrorStatus::NONE, status); + isCachingSupported = supported; + }); + EXPECT_TRUE(ret.isOk()); + if (isCachingSupported) { + mIsCachingSupported = true; + } else { + LOG(INFO) << "NN VTS: Early termination of test because vendor service does not " + "support compilation caching."; + std::cout << "[ ] Early termination of test because vendor service does not " + "support compilation caching." + << std::endl; + mIsCachingSupported = false; + } + + // Create empty cache files. + hidl_handle handle; + createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle); + } + + void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1, + const hidl_handle& cache2, ErrorStatus* status) { + // Save IPreparedModel to cache. + hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken); + Return<ErrorStatus> saveToCacheStatus = + preparedModel->saveToCache(cache1, cache2, cacheToken); + ASSERT_TRUE(saveToCacheStatus.isOk()); + *status = static_cast<ErrorStatus>(saveToCacheStatus); + } + + bool checkEarlyTermination(ErrorStatus status) { + if (status == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "save the prepared model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "save the prepared model that it does not support." + << std::endl; + return true; + } + return false; + } + + void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2, + sp<IPreparedModel>* preparedModel, ErrorStatus* status) { + // Launch prepare model from cache. + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken); + Return<ErrorStatus> prepareLaunchStatus = + device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) { + *preparedModel = nullptr; + *status = static_cast<ErrorStatus>(prepareLaunchStatus); + return; + } + + // Retrieve prepared model. + preparedModelCallback->wait(); + *status = preparedModelCallback->getStatus(); + *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + + std::string mCache1 = "/cache1"; + std::string mCache2 = "/cache2"; + std::string mCache3 = "/cache3"; + uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {}; + bool mIsCachingSupported; +}; + +TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (!mIsCachingSupported) { + EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } else { + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), + testModel.relaxComputationFloat32toFloat16, + /*testDynamicOutputShape=*/false); +} + +TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (!mIsCachingSupported) { + EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } else { + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0); + ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), + testModel.relaxComputationFloat32toFloat16, + /*testDynamicOutputShape=*/false); +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid NumFd. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + } + + // cache2 with invalid NumFd. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + } +} + +TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // cache1 with invalid NumFd. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + ASSERT_EQ(preparedModel, nullptr); + } + } + + // cache2 with invalid NumFd. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + ASSERT_EQ(preparedModel, nullptr); + } + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid access mode. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid access mode. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // cache1 with invalid access mode. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } + + // cache2 with invalid access mode. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid file descriptor offset. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid file descriptor offset. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid file size. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Write one byte and seek back to the beginning. + ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1); + ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid file size. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Write one byte and seek back to the beginning. + ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1); + ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +class CompilationCachingSecurityTest : public CompilationCachingTest, + public ::testing::WithParamInterface<uint32_t> { + protected: + void SetUp() { + CompilationCachingTest::SetUp(); + generator.seed(kSeed); + } + + // Get a random integer within a closed range [lower, upper]. + template <typename T> + T getRandomInt(T lower, T upper) { + std::uniform_int_distribution<T> dis(lower, upper); + return dis(generator); + } + + const uint32_t kSeed = GetParam(); + std::mt19937 generator; +}; + +TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly flip one single bit of the cache entry. + FILE* pFile = fopen(mCache1.c_str(), "r+"); + ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0); + long int fileSize = ftell(pFile); + ASSERT_GT(fileSize, 0); + ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0); + int readByte = fgetc(pFile); + ASSERT_NE(readByte, EOF); + ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0); + ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF); + fclose(pFile); + + // Retrieve preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly append bytes to the cache entry. + FILE* pFile = fopen(mCache1.c_str(), "a"); + uint32_t appendLength = getRandomInt(1, 256); + for (uint32_t i = 0; i < appendLength; i++) { + ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF); + } + fclose(pFile); + + // Retrieve preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongToken) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly flip one single bit in mToken. + uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1); + mToken[ind] ^= (1U << getRandomInt(0, 7)); + + // Retrieve the preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, + ::testing::Range(0U, 10U)); + +} // namespace functional +} // namespace vts +} // namespace V1_2 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp index 4bc891f3d1..2c3287ab35 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp index 956926aaff..990cab9161 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp index 425690f321..fa6d54d295 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 11284ce0e7..3b8e3dd4c2 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -128,10 +128,10 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const uint32_t invalidOperandTypes[] = { - static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MIN) - 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MAX) + 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MIN) - 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MAX) + 1, + static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN) - 1, + static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast<uint32_t>(OperandTypeRange::OEM_MIN) - 1, + static_cast<uint32_t>(OperandTypeRange::OEM_MAX) + 1, }; static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) { @@ -157,10 +157,12 @@ static uint32_t getInvalidRank(OperandType type) { case OperandType::UINT32: case OperandType::BOOL: return 1; + case OperandType::TENSOR_BOOL8: case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: @@ -193,12 +195,14 @@ static float getInvalidScale(OperandType type) { case OperandType::INT32: case OperandType::UINT32: case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: return 1.0f; case OperandType::TENSOR_INT32: return -1.0f; + case OperandType::TENSOR_QUANT8_SYMM: case OperandType::TENSOR_QUANT8_ASYMM: case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: @@ -228,6 +232,7 @@ static std::vector<int32_t> getInvalidZeroPoints(OperandType type) { case OperandType::INT32: case OperandType::UINT32: case OperandType::BOOL: + case OperandType::TENSOR_BOOL8: case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: @@ -235,6 +240,8 @@ static std::vector<int32_t> getInvalidZeroPoints(OperandType type) { return {1}; case OperandType::TENSOR_QUANT8_ASYMM: return {-1, 256}; + case OperandType::TENSOR_QUANT8_SYMM: + return {-129, -1, 1, 128}; case OperandType::TENSOR_QUANT16_ASYMM: return {-1, 65536}; case OperandType::TENSOR_QUANT16_SYMM: @@ -279,6 +286,7 @@ static void mutateOperand(Operand* operand, OperandType type) { newOperand.scale = 0.0f; newOperand.zeroPoint = 0; break; + case OperandType::TENSOR_BOOL8: case OperandType::TENSOR_FLOAT16: case OperandType::TENSOR_FLOAT32: newOperand.dimensions = @@ -292,6 +300,7 @@ static void mutateOperand(Operand* operand, OperandType type) { newOperand.zeroPoint = 0; break; case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: newOperand.dimensions = @@ -334,9 +343,14 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con // TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM). // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - DEQUANTIZE input can be any of + // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can + // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32. + // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32 // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL + // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL switch (operation.type) { case OperationType::LSH_PROJECTION: { if (operand == operation.inputs[1]) { @@ -351,11 +365,26 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con return true; } } break; + case OperationType::QUANTIZE: case OperationType::RANDOM_MULTINOMIAL: { - if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32) { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { return true; } } break; + case OperationType::DEQUANTIZE: { + if (operand == operation.inputs[0] && + (type == OperandType::TENSOR_QUANT8_ASYMM || + type == OperandType::TENSOR_QUANT8_SYMM || + type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) { + return true; + } + if (operand == operation.outputs[0] && + (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) { + return true; + } + } break; + case OperationType::TRANSPOSE_CONV_2D: case OperationType::GROUPED_CONV_2D: case OperationType::DEPTHWISE_CONV_2D: case OperationType::CONV_2D: { @@ -390,10 +419,9 @@ static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Mode ///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// static const uint32_t invalidOperationTypes[] = { - static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MIN) - 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MAX) + 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MIN) - 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MAX) + 1, + static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast<uint32_t>(OperationTypeRange::OEM_MIN) - 1, + static_cast<uint32_t>(OperationTypeRange::OEM_MAX) + 1, }; static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) { @@ -477,6 +505,15 @@ static bool removeOperandSkip(size_t operand, const Model& model) { } } } + // BIDIRECTIONAL_SEQUENCE_RNN can have either on or two outputs + // depending on a mergeOutputs parameter + if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) { + for (const size_t outOprand : operation.outputs) { + if (operand == outOprand) { + return true; + } + } + } } return false; } diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp index 1eaea4b9a6..d411da4819 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "ExecutionBurstController.h" #include "TestHarness.h" #include "Utils.h" @@ -42,6 +43,10 @@ using test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// +static bool badTiming(Timing timing) { + return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX; +} + static void createPreparedModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel) { ASSERT_NE(nullptr, preparedModel); @@ -98,33 +103,87 @@ static void validate(const sp<IPreparedModel>& preparedModel, const std::string& Request request, const std::function<void(Request*)>& mutation) { mutation(&request); + // We'd like to test both with timing requested and without timing + // requested. Rather than running each test both ways, we'll decide whether + // to request timing by hashing the message. We do not use std::hash because + // it is not guaranteed stable across executions. + char hash = 0; + for (auto c : message) { + hash ^= c; + }; + MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO; + + // asynchronous { SCOPED_TRACE(message + " [execute_1_2]"); sp<ExecutionCallback> executionCallback = new ExecutionCallback(); ASSERT_NE(nullptr, executionCallback.get()); Return<ErrorStatus> executeLaunchStatus = - preparedModel->execute_1_2(request, executionCallback); + preparedModel->execute_1_2(request, measure, executionCallback); ASSERT_TRUE(executeLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus)); executionCallback->wait(); ErrorStatus executionReturnStatus = executionCallback->getStatus(); const auto& outputShapes = executionCallback->getOutputShapes(); + Timing timing = executionCallback->getTiming(); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); ASSERT_EQ(outputShapes.size(), 0); + ASSERT_TRUE(badTiming(timing)); } + // synchronous { SCOPED_TRACE(message + " [executeSynchronously]"); Return<void> executeStatus = preparedModel->executeSynchronously( - request, [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - EXPECT_EQ(outputShapes.size(), 0); - }); + request, measure, + [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + }); ASSERT_TRUE(executeStatus.isOk()); } + + // burst + { + SCOPED_TRACE(message + " [burst]"); + + // create burst + std::unique_ptr<::android::nn::ExecutionBurstController> burst = + ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true); + ASSERT_NE(nullptr, burst.get()); + + // create memory keys + std::vector<intptr_t> keys(request.pools.size()); + for (size_t i = 0; i < keys.size(); ++i) { + keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]); + } + + // execute and verify + ErrorStatus error; + std::vector<OutputShape> outputShapes; + Timing timing; + std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + EXPECT_EQ(outputShapes.size(), 0); + EXPECT_TRUE(badTiming(timing)); + + // additional burst testing + if (request.pools.size() > 0) { + // valid free + burst->freeMemory(keys.front()); + + // negative test: invalid free of unknown (blank) memory + burst->freeMemory(intptr_t{}); + + // negative test: double free of memory + burst->freeMemory(keys.front()); + } + } } // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation, diff --git a/power/stats/1.0/default/Android.bp b/power/stats/1.0/default/Android.bp index b57466d18f..7a096391b7 100644 --- a/power/stats/1.0/default/Android.bp +++ b/power/stats/1.0/default/Android.bp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and cc_binary { - name: "android.hardware.power.stats@1.0-service", + name: "android.hardware.power.stats@1.0-service.mock", relative_install_path: "hw", init_rc: ["android.hardware.power.stats@1.0-service.rc"], srcs: ["service.cpp", "PowerStats.cpp"], @@ -31,4 +31,5 @@ cc_binary { "android.hardware.power.stats@1.0", ], vendor: true, + vintf_fragments: ["android.hardware.power.stats@1.0-service-mock.xml"], } diff --git a/power/stats/1.0/default/PowerStats.cpp b/power/stats/1.0/default/PowerStats.cpp index 350aa623ea..78766f2a17 100644 --- a/power/stats/1.0/default/PowerStats.cpp +++ b/power/stats/1.0/default/PowerStats.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "android.hardware.power.stats@1.0-service-mock" + #include "PowerStats.h" #include <android-base/file.h> #include <android-base/logging.h> diff --git a/power/stats/1.0/default/android.hardware.power.stats@1.0-service-mock.xml b/power/stats/1.0/default/android.hardware.power.stats@1.0-service-mock.xml new file mode 100644 index 0000000000..dc52f6651f --- /dev/null +++ b/power/stats/1.0/default/android.hardware.power.stats@1.0-service-mock.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.power.stats</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IPowerStats</name> + <instance>default</instance> + </interface> + </hal> +</manifest>
\ No newline at end of file diff --git a/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc b/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc index d7e546b75e..9377fc23f6 100644 --- a/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc +++ b/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc @@ -1,4 +1,5 @@ -service vendor.power.stats-hal-1-0 /vendor/bin/hw/android.hardware.power.stats@1.0-service +service vendor.power.stats-hal-1-0-mock /vendor/bin/hw/android.hardware.power.stats@1.0-service.mock + interface android.hardware.power.stats@1.0::IPowerStats default class hal user system group system diff --git a/power/stats/1.0/default/service.cpp b/power/stats/1.0/default/service.cpp index a516536d15..8eb53e8d96 100644 --- a/power/stats/1.0/default/service.cpp +++ b/power/stats/1.0/default/service.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power.stats@1.0-service" +#define LOG_TAG "android.hardware.power.stats@1.0-service-mock" #include <android/log.h> #include <hidl/HidlTransportSupport.h> @@ -82,7 +82,7 @@ class DefaultStateResidencyDataProvider : public IStateResidencyDataProvider { }; int main(int /* argc */, char** /* argv */) { - ALOGI("power.stats service 1.0 is starting."); + ALOGI("power.stats service 1.0 mock is starting."); PowerStats* service = new PowerStats(); if (service == nullptr) { diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal index 17718e040e..8393cf5e14 100644 --- a/radio/1.0/types.hal +++ b/radio/1.0/types.hal @@ -1230,85 +1230,108 @@ struct LastCallFailCauseInfo { struct GsmSignalStrength { uint32_t signalStrength; // Valid values are (0-61, 99) as defined in - // TS 27.007 8.69 - uint32_t bitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 + // TS 27.007 8.69; INT_MAX means invalid/unreported. + uint32_t bitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5; + // INT_MAX means invalid/unreported. int32_t timingAdvance; // Timing Advance in bit periods. 1 bit period = 48/13 us. - // INT_MAX denotes invalid value + // INT_MAX means invalid/unreported. }; struct WcdmaSignalStrength{ int32_t signalStrength; // Valid values are (0-31, 99) as defined in - // TS 27.007 8.5 - int32_t bitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 + // TS 27.007 8.5; INT_MAX means unreported. + int32_t bitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5; + // INT_MAX means invalid/unreported. }; struct CdmaSignalStrength { uint32_t dbm; // This value is the actual RSSI // value multiplied by -1. Example: If the // actual RSSI is -75, then this response value will - // be 75. + // be 75. INT_MAX means invalid/unreported. uint32_t ecio; // This value is the actual // Ec/Io multiplied by -10. Example: If the // actual Ec/Io is -12.5 dB, then this response value - // will be 125. + // will be 125. INT_MAX means invalid/unreported. }; struct EvdoSignalStrength { uint32_t dbm; // This value is the actual // RSSI value multiplied by -1. // Example: If the actual RSSI is -75, - // then this response value will be 75. + // then this response value will be 75; INT_MAX means + // invalid/unreported. uint32_t ecio; // This value is the actual // Ec/Io multiplied by -10. Example: If the // actual Ec/Io is -12.5 dB, then this response value - // will be 125. + // will be 125; INT_MAX means invalid/unreported. uint32_t signalNoiseRatio; // Valid values are 0-8. 8 is the highest signal to - // noise ratio. + // noise ratio; INT_MAX means invalid/unreported. }; struct LteSignalStrength { uint32_t signalStrength; // Valid values are (0-31, 99) as defined in - // TS 27.007 8.5 + // TS 27.007 8.5; INT_MAX means invalid/unreported. uint32_t rsrp; // The current Reference Signal Receive Power in dBm // multipled by -1. - // Range: 44 to 140 dBm - // INT_MAX: 0x7FFFFFFF denotes invalid value. + // Range: 44 to 140 dBm; + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP TS 36.133 9.1.4 uint32_t rsrq; // The current Reference Signal Receive Quality in dB // multiplied by -1. - // Range: 20 to 3 dB. - // INT_MAX: 0x7FFFFFFF denotes invalid value. + // Range: 20 to 3 dB; + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP TS 36.133 9.1.7 int32_t rssnr; // The current reference signal signal-to-noise ratio in // 0.1 dB units. // Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB). - // INT_MAX : 0x7FFFFFFF denotes invalid value. + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP TS 36.101 8.1.1 uint32_t cqi; // The current Channel Quality Indicator. // Range: 0 to 15. - // INT_MAX : 0x7FFFFFFF denotes invalid value. + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP TS 36.101 9.2, 9.3, A.4 uint32_t timingAdvance; // timing advance in micro seconds for a one way trip // from cell to device. // Approximate distance is calculated using // 300m/us * timingAdvance. // Range: 0 to 1282 inclusive. - // INT_MAX : 0x7FFFFFFF denotes unknown value. + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP 36.213 section 4.2.3 }; struct TdScdmaSignalStrength { uint32_t rscp; // The Received Signal Code Power in dBm multiplied by -1. // Range : 25 to 120 - // INT_MAX: 0x7FFFFFFF denotes invalid value. + // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value. // Reference: 3GPP TS 25.123, section 9.1.1.1 }; struct SignalStrength { + /** + * If GSM measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ GsmSignalStrength gw; + /** + * If CDMA measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ CdmaSignalStrength cdma; + /** + * If EvDO measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ EvdoSignalStrength evdo; + /** + * If LTE measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ LteSignalStrength lte; + /** + * If TD-SCDMA measurements are provided, this structure must contain valid measurements; + * otherwise all fields should be set to INT_MAX to mark them as invalid. + */ TdScdmaSignalStrength tdScdma; }; diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal index 4715facfa0..2dceeb158d 100644 --- a/radio/1.2/types.hal +++ b/radio/1.2/types.hal @@ -427,11 +427,13 @@ struct WcdmaSignalStrength { /** * CPICH RSCP as defined in TS 25.215 5.1.1 * Valid values are (0-96, 255) as defined in TS 27.007 8.69 + * INT_MAX denotes that the value is invalid/unreported. */ uint32_t rscp; /** * Ec/No value as defined in TS 25.215 5.1.5 * Valid values are (0-49, 255) as defined in TS 27.007 8.69 + * INT_MAX denotes that the value is invalid/unreported. */ uint32_t ecno; @@ -441,26 +443,53 @@ struct TdscdmaSignalStrength { /** * UTRA carrier RSSI as defined in TS 25.225 5.1.4 * Valid values are (0-31, 99) as defined in TS 27.007 8.5 + * INT_MAX denotes that the value is invalid/unreported. */ uint32_t signalStrength; /** * Transport Channel BER as defined in TS 25.225 5.2.5 * Valid values are (0-7, 99) as defined in TS 27.007 8.5 + * INT_MAX denotes that the value is invalid/unreported. */ uint32_t bitErrorRate; /** * P-CCPCH RSCP as defined in TS 25.225 5.1.1 * Valid values are (0-96, 255) as defined in TS 27.007 8.69 + * INT_MAX denotes that the value is invalid/unreported. */ uint32_t rscp; }; struct SignalStrength { + /** + * If GSM measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ GsmSignalStrength gsm; + /** + * If CDMA measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ CdmaSignalStrength cdma; + /** + * If EvDO measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ EvdoSignalStrength evdo; + /** + * If LTE measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ LteSignalStrength lte; + /** + * If TD-SCDMA measurements are provided, this structure must contain valid measurements; + * otherwise all fields should be set to INT_MAX to mark them as invalid. + */ TdScdmaSignalStrength tdScdma; + /** + * If WCDMA measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ WcdmaSignalStrength wcdma; }; diff --git a/radio/1.3/IRadio.hal b/radio/1.3/IRadio.hal index 2d643812bb..cc5b8605bc 100644 --- a/radio/1.3/IRadio.hal +++ b/radio/1.3/IRadio.hal @@ -60,4 +60,15 @@ interface IRadio extends @1.2::IRadio { * Response function is IRadioResponse.enableModemResponse() */ oneway enableModem(int32_t serial, bool on); -}; + + /** + * Request status of logical modem associated with the given serial number. It returns + * isEnabled=true if the logical modem is in low power mode without any activity, while + * the SIM card remains visible. + * + * @param serial Serial number of request. + * + * Response function is IRadioResponse.getModemStackStatusResponse() + */ + oneway getModemStackStatus(int32_t serial); +};
\ No newline at end of file diff --git a/radio/1.3/IRadioResponse.hal b/radio/1.3/IRadioResponse.hal index abdf2ee52c..c3bbe659e6 100644 --- a/radio/1.3/IRadioResponse.hal +++ b/radio/1.3/IRadioResponse.hal @@ -43,7 +43,17 @@ interface IRadioResponse extends @1.2::IRadioResponse { * Valid errors returned: * RadioError:NONE * RadioError:RADIO_NOT_AVAILABLE - * RadioError:INTERNAL_ERR + * RadioError:MODEM_ERR */ oneway enableModemResponse(RadioResponseInfo info); + + /** + * @param info Response info struct containing response type, serial no. and error + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:MODEM_ERR + */ + oneway getModemStackStatusResponse(RadioResponseInfo info, bool isEnabled); }; diff --git a/radio/1.3/types.hal b/radio/1.3/types.hal new file mode 100644 index 0000000000..aa16cc7703 --- /dev/null +++ b/radio/1.3/types.hal @@ -0,0 +1,27 @@ +/* + * 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.3; + +import @1.0::RadioResponseType; +import @1.0::RadioError; + +struct RadioResponseInfoModem { + RadioResponseType type; // Response type + int32_t serial; // Serial number of the request + RadioError error; // Response error + bool isEnabled; // whether modem is enabled or not +};
\ No newline at end of file diff --git a/radio/1.3/vts/OWNERS b/radio/1.3/vts/OWNERS new file mode 100644 index 0000000000..d64206467a --- /dev/null +++ b/radio/1.3/vts/OWNERS @@ -0,0 +1,10 @@ +# Telephony team +amitmahajan@google.com +sanketpadawe@google.com +shuoq@google.com +sasindran@google.com +nazaninb@google.com + +# VTS team +yuexima@google.com +yim@google.com diff --git a/radio/1.3/vts/functional/Android.bp b/radio/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..67aff6ee26 --- /dev/null +++ b/radio/1.3/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: "VtsHalRadioV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "radio_hidl_hal_api.cpp", + "radio_hidl_hal_test.cpp", + "radio_response.cpp", + "radio_indication.cpp", + "VtsHalRadioV1_3TargetTest.cpp", + ], + static_libs: [ + "RadioVtsTestUtilBase", + "android.hardware.radio@1.3", + "android.hardware.radio@1.2", + "android.hardware.radio@1.1", + "android.hardware.radio@1.0", + ], + header_libs: ["radio.util.header@1.0"], + test_suites: ["general-tests"], +} diff --git a/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp b/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp new file mode 100644 index 0000000000..7d2623eb32 --- /dev/null +++ b/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp @@ -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. + */ + +#include <radio_hidl_hal_utils_v1_3.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; +} diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp new file mode 100644 index 0000000000..6208c677f5 --- /dev/null +++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp @@ -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. + */ + +#include <radio_hidl_hal_utils_v1_3.h> +#include <vector> + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) + +/* + * Test IRadio.enableMddem() for the response returned. + */ +TEST_F(RadioHidlTest_v1_3, enableModem) { + serial = GetRandomSerialNumber(); + + bool responseToggle = radioRsp_v1_3->enableModemResponseToggle; + Return<void> res = radio_v1_3->enableModem(serial, true); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); + ALOGI("getModemStackStatus, rspInfo.error = %s\n", + toString(radioRsp_v1_3->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_3->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR})); + + // checking if getModemStackStatus returns true, as modem was enabled above + if (RadioError::NONE == radioRsp_v1_3->rspInfo.error) { + // wait until modem enabling is finished + while (responseToggle == radioRsp_v1_3->enableModemResponseToggle) { + sleep(1); + } + Return<void> resEnabled = radio_v1_3->getModemStackStatus(serial); + ASSERT_OK(resEnabled); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); + ALOGI("getModemStackStatus, rspInfo.error = %s\n", + toString(radioRsp_v1_3->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_3->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR})); + // verify that enableModem did set isEnabled correctly + EXPECT_EQ(true, radioRsp_v1_3->isModemEnabled); + } +} + +/* + * Test IRadio.getModemStackStatus() for the response returned. + */ +TEST_F(RadioHidlTest_v1_3, getModemStackStatus) { + serial = GetRandomSerialNumber(); + + Return<void> res = radio_v1_3->getModemStackStatus(serial); + ASSERT_OK(res); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); + ALOGI("getModemStackStatus, rspInfo.error = %s\n", + toString(radioRsp_v1_3->rspInfo.error).c_str()); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_3->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR})); +} diff --git a/radio/1.3/vts/functional/radio_hidl_hal_test.cpp b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp new file mode 100644 index 0000000000..a876b1a3f1 --- /dev/null +++ b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp @@ -0,0 +1,87 @@ +/* + * 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_3.h> + +void RadioHidlTest_v1_3::SetUp() { + radio_v1_3 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_3::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_3::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + if (radio_v1_3 == NULL) { + sleep(60); + radio_v1_3 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_3::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_3::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + } + ASSERT_NE(nullptr, radio_v1_3.get()); + + radioRsp_v1_3 = new (std::nothrow) RadioResponse_v1_3(*this); + ASSERT_NE(nullptr, radioRsp_v1_3.get()); + + count_ = 0; + + radioInd_v1_3 = new (std::nothrow) RadioIndication_v1_3(*this); + ASSERT_NE(nullptr, radioInd_v1_3.get()); + + radio_v1_3->setResponseFunctions(radioRsp_v1_3, radioInd_v1_3); + + updateSimCardStatus(); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error); + + /* Enforce Vts Testing with Sim Status Present only. */ + EXPECT_EQ(CardState::PRESENT, cardStatus.base.cardState); +} + +/* + * Notify that the response message is received. + */ +void RadioHidlTest_v1_3::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_3::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_3::updateSimCardStatus() { + serial = GetRandomSerialNumber(); + radio_v1_3->getIccCardStatus(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); +}
\ No newline at end of file diff --git a/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h b/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h new file mode 100644 index 0000000000..1d03a99e01 --- /dev/null +++ b/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h @@ -0,0 +1,658 @@ +/* + * 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/1.2/types.h> +#include <android/hardware/radio/1.3/IRadio.h> +#include <android/hardware/radio/1.3/IRadioIndication.h> +#include <android/hardware/radio/1.3/IRadioResponse.h> + +#include "vts_test_util.h" + +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_bitfield; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +#define TIMEOUT_PERIOD 75 +#define RADIO_SERVICE_NAME "slot1" + +class RadioHidlTest_v1_3; +extern ::android::hardware::radio::V1_2::CardStatus cardStatus; + +/* Callback class for radio response v1_3*/ +class RadioResponse_v1_3 : public ::android::hardware::radio::V1_3::IRadioResponse { + protected: + RadioHidlTest_v1_3& parent_v1_3; + + public: + RadioResponseInfo rspInfo; + // Modem + bool isModemEnabled; + bool enableModemResponseToggle = false; + + // Data + ::android::hardware::radio::V1_2::DataRegStateResult dataRegResp; + + RadioResponse_v1_3(RadioHidlTest_v1_3& parent_v1_3); + virtual ~RadioResponse_v1_3() = 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 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<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, + 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 RadioCapability& rc); + + Return<void> setRadioCapabilityResponse(const RadioResponseInfo& info, + const 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> 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); +}; + +/* Callback class for radio indication */ +class RadioIndication_v1_3 : public ::android::hardware::radio::V1_3::IRadioIndication { + protected: + RadioHidlTest_v1_3& parent_v1_3; + + public: + RadioIndication_v1_3(RadioHidlTest_v1_3& parent_v1_3); + virtual ~RadioIndication_v1_3() = default; + + /* 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); + + /* 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<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, 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 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_3::IRadio>(); + } + + private: + RadioHidlEnvironment() {} +}; + +// The main test class for Radio HIDL. +class RadioHidlTest_v1_3 : public ::testing::VtsHalHidlTargetTestBase { + protected: + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + /* Serial number for radio request */ + int serial; + + /* 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_3::IRadio> radio_v1_3; + + /* radio response handle */ + sp<RadioResponse_v1_3> radioRsp_v1_3; + + /* radio indication handle */ + sp<RadioIndication_v1_3> radioInd_v1_3; +};
\ No newline at end of file diff --git a/radio/1.3/vts/functional/radio_indication.cpp b/radio/1.3/vts/functional/radio_indication.cpp new file mode 100644 index 0000000000..034825eef1 --- /dev/null +++ b/radio/1.3/vts/functional/radio_indication.cpp @@ -0,0 +1,288 @@ +/* + * 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_3.h> + +RadioIndication_v1_3::RadioIndication_v1_3(RadioHidlTest_v1_3& parent) : parent_v1_3(parent) {} + +/* 1.2 Apis */ +Return<void> RadioIndication_v1_3::networkScanResult_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cellInfoList_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::currentLinkCapacityEstimate( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::currentPhysicalChannelConfigs( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::currentSignalStrength_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) { + return Void(); +} + +/* 1.1 Apis */ +Return<void> RadioIndication_v1_3::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::networkScanResult( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::keepaliveStatus(RadioIndicationType /*type*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +/* 1.0 Apis */ +Return<void> RadioIndication_v1_3::radioStateChanged(RadioIndicationType /*type*/, + RadioState /*radioState*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::callStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::networkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::newSms(RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::newSmsStatusReport( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::newSmsOnSim(RadioIndicationType /*type*/, + int32_t /*recordNumber*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/, + const ::android::hardware::hidl_string& /*msg*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::nitzTimeReceived( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/, + uint64_t /*receivedTime*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::currentSignalStrength( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::dataCallListChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<SetupDataCallResult>& /*dcList*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::suppSvcNotify(RadioIndicationType /*type*/, + const SuppSvcNotification& /*suppSvc*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::stkSessionEnd(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::stkProactiveCommand( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::stkEventNotify(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::simSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::simRefresh(RadioIndicationType /*type*/, + const SimRefreshResult& /*refreshResult*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::callRing(RadioIndicationType /*type*/, bool /*isGsm*/, + const CdmaSignalInfoRecord& /*record*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::simStatusChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaNewSms(RadioIndicationType /*type*/, + const CdmaSmsMessage& /*msg*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::newBroadcastSms( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::restrictedStateChanged(RadioIndicationType /*type*/, + PhoneRestrictedState /*state*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::enterEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaCallWaiting(RadioIndicationType /*type*/, + const CdmaCallWaiting& /*callWaitingRecord*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaOtaProvisionStatus(RadioIndicationType /*type*/, + CdmaOtaProvisionStatus /*status*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaInfoRec(RadioIndicationType /*type*/, + const CdmaInformationRecords& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::indicateRingbackTone(RadioIndicationType /*type*/, + bool /*start*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::resendIncallMute(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaSubscriptionSourceChanged( + RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cdmaPrlChanged(RadioIndicationType /*type*/, + int32_t /*version*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::exitEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::rilConnected(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::voiceRadioTechChanged(RadioIndicationType /*type*/, + RadioTechnology /*rat*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::cellInfoList( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::imsNetworkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::subscriptionStatusChanged(RadioIndicationType /*type*/, + bool /*activate*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::srvccStateNotify(RadioIndicationType /*type*/, + SrvccState /*state*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::hardwareConfigChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::radioCapabilityIndication(RadioIndicationType /*type*/, + const RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::onSupplementaryServiceIndication( + RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::stkCallControlAlphaNotify( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::lceData(RadioIndicationType /*type*/, + const LceDataInfo& /*lce*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::pcoData(RadioIndicationType /*type*/, + const PcoDataInfo& /*pco*/) { + return Void(); +} + +Return<void> RadioIndication_v1_3::modemReset(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*reason*/) { + return Void(); +}
\ No newline at end of file diff --git a/radio/1.3/vts/functional/radio_response.cpp b/radio/1.3/vts/functional/radio_response.cpp new file mode 100644 index 0000000000..900794ec1b --- /dev/null +++ b/radio/1.3/vts/functional/radio_response.cpp @@ -0,0 +1,786 @@ +/* + * 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_3.h> + +::android::hardware::radio::V1_2::CardStatus cardStatus; + +RadioResponse_v1_3::RadioResponse_v1_3(RadioHidlTest_v1_3& parent) : parent_v1_3(parent) {} + +/* 1.0 Apis */ +Return<void> RadioResponse_v1_3::getIccCardStatusResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::supplyNetworkDepersonalizationResponse( + const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCurrentCallsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::dialResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getIMSIForAppResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::hangupConnectionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::hangupWaitingOrBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::hangupForegroundResumeBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::switchWaitingOrHoldingAndActiveResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::conferenceResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::rejectCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getLastCallFailCauseResponse( + const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getSignalStrengthResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getVoiceRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getDataRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::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_3::setRadioPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setupDataCallResponse(const RadioResponseInfo& info, + const SetupDataCallResult& /*dcResponse*/) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::iccIOForAppResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/, + int32_t /*m*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setClirResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCallForwardStatusResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>& + /*callForwardInfos*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCallForwardResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCallWaitingResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/, int32_t /*serviceClass*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCallWaitingResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::acknowledgeLastIncomingGsmSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::acceptCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::deactivateDataCallResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*response*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*retry*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/, + bool /*manual*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setNetworkSelectionModeAutomaticResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setNetworkSelectionModeManualResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getAvailableNetworksResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::startDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::stopDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getBasebandVersionResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::separateConnectionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setMuteResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getMuteResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getClipResponse(const RadioResponseInfo& /*info*/, + ClipStatus /*status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getDataCallListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<SetupDataCallResult>& /*dcResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendOemRilRequestRawResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendOemRilRequestStringsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setSuppServiceNotificationsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::writeSmsToSimResponse(const RadioResponseInfo& /*info*/, + int32_t /*index*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setBandModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getAvailableBandModesResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<RadioBandMode>& /* bandModes */) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::sendEnvelopeResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_string& /*commandResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendTerminalResponseToSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::handleStkCallSetupRequestFromSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setPreferredNetworkTypeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/, + PreferredNetworkType /*nw_type*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getNeighboringCidsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCdmaRoamingPreferenceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/, + CdmaRoamingType /*type*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setTTYModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getTTYModeResponse(const RadioResponseInfo& /*info*/, + TtyMode /*mode*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setPreferredVoicePrivacyResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::acknowledgeLastIncomingCdmaSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getGsmBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setGsmBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCdmaBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCdmaBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::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_3::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/, + uint32_t /*index*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::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_3::exitEmergencyCallbackModeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getSmscAddressResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setSmscAddressResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::reportStkServiceIsRunningResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::requestIsimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::acknowledgeIncomingGsmSmsWithPduResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getVoiceRadioTechnologyResponse(const RadioResponseInfo& /*info*/, + RadioTechnology /*rat*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getCellInfoListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setInitialAttachApnResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getImsRegistrationStateResponse( + const RadioResponseInfo& /*info*/, bool /*isRegistered*/, + RadioTechnologyFamily /*ratFamily*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendImsSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::iccTransmitApduBasicChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::iccOpenLogicalChannelResponse( + const RadioResponseInfo& /*info*/, int32_t /*channelId*/, + const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::iccTransmitApduLogicalChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::nvReadItemResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::nvWriteItemResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::nvResetConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setDataAllowedResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getHardwareConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::requestIccSimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setDataProfileResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::requestShutdownResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getRadioCapabilityResponse(const RadioResponseInfo& /*info*/, + const RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setRadioCapabilityResponse(const RadioResponseInfo& /*info*/, + const RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::startLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::stopLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::pullLceDataResponse(const RadioResponseInfo& /*info*/, + const LceDataInfo& /*lceInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getModemActivityInfoResponse( + const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/, + int32_t /*numAllowed*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::getAllowedCarriersResponse( + const RadioResponseInfo& /*info*/, bool /*allAllowed*/, + const CarrierRestrictions& /*carriers*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setIndicationFilterResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::acknowledgeRequest(int32_t /*serial*/) { + return Void(); +} + +/* 1.1 Apis */ +Return<void> RadioResponse_v1_3::setCarrierInfoForImsiEncryptionResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::startNetworkScanResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::stopNetworkScanResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::startKeepaliveResponse(const RadioResponseInfo& /*info*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_3::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +/* 1.2 Apis */ +Return<void> RadioResponse_v1_3::setSignalStrengthReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::setLinkCapacityReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getIccCardStatusResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::CardStatus& card_status) { + rspInfo = info; + cardStatus = card_status; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getCurrentCallsResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& /*calls*/) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getSignalStrengthResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getCellInfoListResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getVoiceRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) { + rspInfo = info; + parent_v1_3.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_3::getDataRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse) { + rspInfo = info; + dataRegResp = dataRegResponse; + parent_v1_3.notify(info.serial); + return Void(); +} + +/* 1.3 Api */ +Return<void> RadioResponse_v1_3::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) { + rspInfo = info; + return Void(); +} + +Return<void> RadioResponse_v1_3::enableModemResponse(const RadioResponseInfo& info) { + rspInfo = info; + enableModemResponseToggle = !enableModemResponseToggle; + return Void(); +} + +Return<void> RadioResponse_v1_3::getModemStackStatusResponse(const RadioResponseInfo& info, + const bool enabled) { + rspInfo = info; + isModemEnabled = enabled; + return Void(); +} diff --git a/radio/1.4/Android.bp b/radio/1.4/Android.bp index 9fd037434d..e8b87778d5 100644 --- a/radio/1.4/Android.bp +++ b/radio/1.4/Android.bp @@ -25,8 +25,10 @@ hidl_interface { "CardStatus", "CarrierRestrictionsWithPriority", "CellConfigLte", + "CellIdentityNr", "CellInfo", "CellInfoLte", + "CellInfoNr", "DataCallFailCause", "DataConnActiveStatus", "DataProfileInfo", @@ -39,6 +41,7 @@ hidl_interface { "LteVopsInfo", "NetworkScanResult", "NrIndicators", + "NrSignalStrength", "PdpProtocolType", "PhysicalChannelConfig", "RadioAccessFamily", @@ -46,6 +49,7 @@ hidl_interface { "RadioFrequencyInfo", "RadioTechnology", "SetupDataCallResult", + "SignalStrength", "SimLockMultiSimPolicy", ], gen_java: true, diff --git a/radio/1.4/IRadio.hal b/radio/1.4/IRadio.hal index dd69607e5e..8ef1f962e3 100644 --- a/radio/1.4/IRadio.hal +++ b/radio/1.4/IRadio.hal @@ -128,6 +128,10 @@ interface IRadio extends @1.3::IRadio { * does not support the emergency service category or emergency uniform resource names, the * field 'categories' or 'urns' may be ignored. * + * 'fromEmergencyDialer' indicates if this request originated from emergency dialer/shortcut, + * which means an explicit intent from the user to dial an emergency number. The modem must + * treat this as an actual emergency dial and not try to disambiguate. + * * If 'isTesting' is true, this request is for testing purpose, and must not be sent to a real * emergency service; otherwise it's for a real emergency call request. * @@ -142,12 +146,14 @@ interface IRadio extends @1.3::IRadio { * of the call. * @param urns the emergency Uniform Resource Names (URN) * @param routing @1.4::EmergencyCallRouting the emergency call routing information. + * @param fromEmergencyDialer Flag indicating if this request originated from emergency dialer. + * @param isTesting Flag indicating if this request is for testing purpose. * * Response function is IRadioResponse.emergencyDialResponse() */ oneway emergencyDial(int32_t serial, Dial dialInfo, bitfield<EmergencyServiceCategory> categories, vec<string> urns, - EmergencyCallRouting routing, bool isTesting); + EmergencyCallRouting routing, bool fromEmergencyDialer, bool isTesting); /** * Starts a network scan @@ -209,4 +215,13 @@ interface IRadio extends @1.3::IRadio { * Response callback is IRadioResponse.getAllowedCarriersResponse_1_3() */ oneway getAllowedCarriers_1_4(int32_t serial); + + /** + * Requests current signal strength and associated information. Must succeed if radio is on. + * + * @param serial Serial number of request. + * + * Response function is IRadioResponse.getSignalStrengthResponse_1_4() + */ + oneway getSignalStrength_1_4(int32_t serial); }; diff --git a/radio/1.4/IRadioIndication.hal b/radio/1.4/IRadioIndication.hal index 58b7b70d34..3c61f962d5 100644 --- a/radio/1.4/IRadioIndication.hal +++ b/radio/1.4/IRadioIndication.hal @@ -89,4 +89,12 @@ interface IRadioIndication extends @1.3::IRadioIndication { * 3. Unsolicited disconnect from either modem or network side. */ oneway dataCallListChanged_1_4(RadioIndicationType type, vec<SetupDataCallResult> dcList); + + /** + * Indicates current signal strength of the radio. + * + * @param type Type of radio indication + * @param signalStrength SignalStrength information + */ + oneway currentSignalStrength_1_4(RadioIndicationType type, SignalStrength signalStrength); }; diff --git a/radio/1.4/IRadioResponse.hal b/radio/1.4/IRadioResponse.hal index 77aad03730..f43295ae71 100644 --- a/radio/1.4/IRadioResponse.hal +++ b/radio/1.4/IRadioResponse.hal @@ -24,6 +24,7 @@ import @1.4::CellInfo; import @1.4::DataRegStateResult; import @1.4::RadioAccessFamily; import @1.4::SetupDataCallResult; +import @1.4::SignalStrength; import @1.4::SimLockMultiSimPolicy; /** @@ -40,7 +41,6 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:DIAL_MODIFIED_TO_SS * RadioError:DIAL_MODIFIED_TO_DIAL * RadioError:INVALID_ARGUMENTS - * RadioError:NO_MEMORY * RadioError:NO_RESOURCES * RadioError:INTERNAL_ERR * RadioError:FDN_CHECK_FAILURE @@ -51,7 +51,6 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:DEVICE_IN_USE * RadioError:ABORTED * RadioError:INVALID_MODEM_STATE - * RadioError:CANCELLED */ oneway emergencyDialResponse(RadioResponseInfo info); @@ -66,7 +65,6 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:RADIO_NOT_AVAILABLE * RadioError:DEVICE_IN_USE * RadioError:INTERNAL_ERR - * RadioError:NO_MEMORY * RadioError:MODEM_ERR * RadioError:INVALID_ARGUMENTS */ @@ -105,9 +103,7 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:NONE * RadioError:RADIO_NOT_AVAILABLE * RadioError:INTERNAL_ERR - * RadioError:NO_MEMORY * RadioError:NO_RESOURCES - * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED */ oneway getIccCardStatusResponse_1_4(RadioResponseInfo info, CardStatus cardStatus); @@ -119,14 +115,11 @@ interface IRadioResponse extends @1.3::IRadioResponse { * Valid errors returned: * RadioError:NONE * RadioError:RADIO_NOT_AVAILABLE - * RadioError:NO_MEMORY * RadioError:INTERNAL_ERR - * RadioError:SYSTEM_ERR * RadioError:INVALID_ARGUMENTS * RadioError:MODEM_ERR * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES - * RadioError:CANCELLED */ oneway getPreferredNetworkTypeBitmapResponse(RadioResponseInfo info, bitfield<RadioAccessFamily> networkTypeBitmap); @@ -141,14 +134,11 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:RADIO_NOT_AVAILABLE * RadioError:OPERATION_NOT_ALLOWED * RadioError:MODE_NOT_SUPPORTED - * RadioError:NO_MEMORY * RadioError:INTERNAL_ERR - * RadioError:SYSTEM_ERR * RadioError:INVALID_ARGUMENTS * RadioError:MODEM_ERR * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES - * RadioError:CANCELLED */ oneway setPreferredNetworkTypeBitmapResponse(RadioResponseInfo info); @@ -160,9 +150,7 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:NONE * RadioError:RADIO_NOT_AVAILABLE * RadioError:INTERNAL_ERR - * RadioError:NO_MEMORY * RadioError:NO_RESOURCES - * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED * RadioError:SIM_ABSENT */ @@ -182,9 +170,7 @@ interface IRadioResponse extends @1.3::IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:INVALID_ARGUMENTS * RadioError:INTERNAL_ERR - * RadioError:NO_MEMORY * RadioError:NO_RESOURCES - * RadioError:CANCELLED * RadioError:SIM_ABSENT */ oneway setupDataCallResponse_1_4(RadioResponseInfo info, SetupDataCallResult dcResponse); @@ -215,4 +201,14 @@ interface IRadioResponse extends @1.3::IRadioResponse { */ oneway getAllowedCarriersResponse_1_4(RadioResponseInfo info, CarrierRestrictionsWithPriority carriers, SimLockMultiSimPolicy multiSimPolicy); + + /** + * @param signalStrength Current signal strength + * + * Valid errors returned: + * RadioError:NONE + * RadioError:RADIO_NOT_AVAILABLE + * RadioError:INTERNAL_ERR + */ + oneway getSignalStrengthResponse_1_4(RadioResponseInfo info, SignalStrength signalStrength); }; diff --git a/radio/1.4/types.hal b/radio/1.4/types.hal index 76e8403ab2..2747732730 100644 --- a/radio/1.4/types.hal +++ b/radio/1.4/types.hal @@ -20,12 +20,16 @@ import @1.0::ApnAuthType; import @1.0::ApnTypes; import @1.0::Carrier; import @1.0::CellInfoType; +import @1.0::CdmaSignalStrength; import @1.0::DataCallFailCause; import @1.0::DataProfileId; import @1.0::DataProfileInfoType; +import @1.0::EvdoSignalStrength; +import @1.0::GsmSignalStrength; +import @1.0::LteSignalStrength; import @1.0::RadioAccessFamily; import @1.0::RadioCapabilityPhase; -import @1.0::RadioCapabilityStatus ; +import @1.0::RadioCapabilityStatus; import @1.0::RadioError; import @1.0::RadioTechnology; import @1.0::RegState; @@ -39,10 +43,17 @@ import @1.2::CellInfoLte; import @1.2::CellInfoTdscdma; import @1.2::CellInfoWcdma; import @1.2::CardStatus; -import @1.2::CellIdentity; import @1.2::CellConnectionStatus; +import @1.2::CellIdentityCdma; +import @1.2::CellIdentityGsm; +import @1.2::CellIdentityLte; +import @1.2::CellIdentityTdscdma; +import @1.2::CellIdentityWcdma; +import @1.2::CellIdentityOperatorNames; import @1.2::DataRegStateResult; import @1.2::PhysicalChannelConfig; +import @1.2::TdscdmaSignalStrength; +import @1.2::WcdmaSignalStrength; import android.hidl.safe_union@1.0::Monostate; @@ -188,12 +199,12 @@ enum EmergencyCallRouting : int32_t { }; enum RadioTechnology : @1.0::RadioTechnology { - /** 5G NR. */ + /** 5G NR. This is only use in 5G Standalone mode. */ NR = 20, }; enum RadioAccessFamily : @1.0::RadioAccessFamily { - /** 5G NR. */ + /** 5G NR. This is only use in 5G Standalone mode. */ NR = 1 << RadioTechnology:NR, }; @@ -230,7 +241,7 @@ enum DataCallFailCause : @1.0::DataCallFailCause { * Network has already initiated the activation, modification, or deactivation of bearer * resources that was requested by the UE. */ - COLLISION_WITH_NW_INIT_REQ = 0x38, + COLLISION_WITH_NETWORK_INITIATED_REQUEST = 0x38, /** * Network supports IPv4v6 PDP type only. Non-IP type is not allowed. In LTE mode of operation, * this is a PDN throttling cause code, meaning the UE may throttle further requests to the @@ -244,7 +255,7 @@ enum DataCallFailCause : @1.0::DataCallFailCause { */ ONLY_NON_IP_ALLOWED = 0x3A, /** - * QCI indicated in the UE request cannot be supported. + * QCI (QoS Class Identifier) indicated in the UE request cannot be supported. */ UNSUPPORTED_QCI_VALUE = 0x3B, /** @@ -258,7 +269,7 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * Not receiving either a PCSCF or a DNS address, one of them being mandatory. */ - INVALID_PCSCF_DNS_ADDR = 0x7C, + INVALID_PCSCF_OR_DNS_ADDRESS = 0x7C, /** * Emergency call bring up on a different ePDG. */ @@ -266,128 +277,136 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * UE performs a detach or disconnect PDN action based on TE requirements. */ - UE_INIT_DETACH_OR_DISCONNECT = 0x80, + UE_INITIATED_DETACH_OR_DISCONNECT = 0x80, /** - * Reason unspecified for foreign agent rejected MIP registration. + * Reason unspecified for foreign agent rejected MIP (Mobile IP) registration. */ MIP_FA_REASON_UNSPECIFIED = 0x7D0, /** - * Foreign agent administratively prohibited MIP registration. + * Foreign agent administratively prohibited MIP (Mobile IP) registration. */ MIP_FA_ADMIN_PROHIBITED = 0x7D1, /** - * Foreign agent rejected MIP registration because of insufficient resources. + * Foreign agent rejected MIP (Mobile IP) registration because of insufficient resources. */ MIP_FA_INSUFFICIENT_RESOURCES = 0x7D2, /** - * Foreign agent rejected MIP registration because of MN-AAA authenticator was wrong. + * Foreign agent rejected MIP (Mobile IP) registration because of MN-AAA authenticator was + * wrong. */ - MIP_FA_MOBILE_NODE_AUTH_FAILURE = 0x7D3, + MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7D3, /** - * Foreign agent rejected MIP registration because of home agent authentication failure. + * Foreign agent rejected MIP (Mobile IP) registration because of home agent authentication + * failure. */ - MIP_FA_HA_AUTH_FAILURE = 0x7D4, + MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 0x7D4, /** - * Foreign agent rejected MIP registration because of requested lifetime was too long. + * Foreign agent rejected MIP (Mobile IP) registration because of requested lifetime was too + * long. */ - MIP_FA_REQ_LIFETIME_TOO_LONG = 0x7D5, + MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 0x7D5, /** - * Foreign agent rejected MIP registration because of malformed request. + * Foreign agent rejected MIP (Mobile IP) registration because of malformed request. */ MIP_FA_MALFORMED_REQUEST = 0x7D6, /** - * Foreign agent rejected MIP registration because of malformed reply. + * Foreign agent rejected MIP (Mobile IP) registration because of malformed reply. */ MIP_FA_MALFORMED_REPLY = 0x7D7, /** - * Foreign agent rejected MIP registration because of requested encapsulation was unavailable. + * Foreign agent rejected MIP (Mobile IP) registration because of requested encapsulation was + * unavailable. */ MIP_FA_ENCAPSULATION_UNAVAILABLE = 0x7D8, /** - * Foreign agent rejected MIP registration of VJ Header Compression was unavailable. + * Foreign agent rejected MIP (Mobile IP) registration of VJ Header Compression was unavailable. */ - MIP_FA_VJHC_UNAVAILABLE = 0x7D9, + MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 0x7D9, /** - * Foreign agent rejected MIP registration because of reverse tunnel was unavailable. + * Foreign agent rejected MIP (Mobile IP) registration because of reverse tunnel was + * unavailable. */ - MIP_FA_REV_TUNNEL_UNAVAILABLE = 0x7DA, + MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 0x7DA, /** - * Foreign agent rejected MIP registration because of reverse tunnel was mandatory but not - * requested by device. + * Foreign agent rejected MIP (Mobile IP) registration because of reverse tunnel was mandatory + * but not requested by device. */ - MIP_FA_REV_TUNNEL_IS_MAND_AND_T_BIT_NOT_SET = 0x7DB, + MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 0x7DB, /** - * Foreign agent rejected MIP registration because of delivery style was not supported. + * Foreign agent rejected MIP (Mobile IP) registration because of delivery style was not + * supported. */ - MIP_FA_DELIVERY_STYLE_NOT_SUPP = 0x7DC, + MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 0x7DC, /** - * Foreign agent rejected MIP registration because of missing NAI. + * Foreign agent rejected MIP (Mobile IP) registration because of missing NAI (Network Access + * Identifier). */ MIP_FA_MISSING_NAI = 0x7DD, /** - * Foreign agent rejected MIP registration because of missing Home Agent. + * Foreign agent rejected MIP (Mobile IP) registration because of missing Home Agent. */ - MIP_FA_MISSING_HA = 0x7DE, + MIP_FA_MISSING_HOME_AGENT = 0x7DE, /** - * Foreign agent rejected MIP registration because of missing Home Address. + * Foreign agent rejected MIP (Mobile IP) registration because of missing Home Address. */ - MIP_FA_MISSING_HOME_ADDR = 0x7DF, + MIP_FA_MISSING_HOME_ADDRESS = 0x7DF, /** - * Foreign agent rejected MIP registration because of unknown challenge. + * Foreign agent rejected MIP (Mobile IP) registration because of unknown challenge. */ MIP_FA_UNKNOWN_CHALLENGE = 0x7E0, /** - * Foreign agent rejected MIP registration because of missing challenge. + * Foreign agent rejected MIP (Mobile IP) registration because of missing challenge. */ MIP_FA_MISSING_CHALLENGE = 0x7E1, /** - * Foreign agent rejected MIP registration because of stale challenge. + * Foreign agent rejected MIP (Mobile IP) registration because of stale challenge. */ MIP_FA_STALE_CHALLENGE = 0x7E2, /** - * Reason unspecified for home agent rejected MIP registration. + * Reason unspecified for home agent rejected MIP (Mobile IP) registration. */ MIP_HA_REASON_UNSPECIFIED = 0x7E3, /** - * Home agent administratively prohibited MIP registration. + * Home agent administratively prohibited MIP (Mobile IP) registration. */ MIP_HA_ADMIN_PROHIBITED = 0x7E4, /** - * Home agent rejected MIP registration because of insufficient resources. + * Home agent rejected MIP (Mobile IP) registration because of insufficient resources. */ MIP_HA_INSUFFICIENT_RESOURCES = 0x7E5, /** - * Home agent rejected MIP registration because of MN-HA authenticator was wrong. + * Home agent rejected MIP (Mobile IP) registration because of MN-HA authenticator was wrong. */ - MIP_HA_MOBILE_NODE_AUTH_FAILURE = 0x7E6, + MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7E6, /** - * Home agent rejected MIP registration because of foreign agent authentication failure. + * Home agent rejected MIP (Mobile IP) registration because of foreign agent authentication + * failure. */ - MIP_HA_FA_AUTH_FAILURE = 0x7E7, + MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 0x7E7, /** - * Home agent rejected MIP registration because of registration id mismatch. + * Home agent rejected MIP (Mobile IP) registration because of registration id mismatch. */ MIP_HA_REGISTRATION_ID_MISMATCH = 0x7E8, /** - * Home agent rejected MIP registration because of malformed request. + * Home agent rejected MIP (Mobile IP) registration because of malformed request. */ MIP_HA_MALFORMED_REQUEST = 0x7E9, /** - * Home agent rejected MIP registration because of unknown home agent address. + * Home agent rejected MIP (Mobile IP) registration because of unknown home agent address. */ - MIP_HA_UNKNOWN_HA_ADDR = 0x7EA, + MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 0x7EA, /** - * Home agent rejected MIP registration because of reverse tunnel was unavailable. + * Home agent rejected MIP (Mobile IP) registration because of reverse tunnel was unavailable. */ - MIP_HA_REV_TUNNEL_UNAVAILABLE = 0x7EB, + MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 0x7EB, /** - * Home agent rejected MIP registration because of reverse tunnel is mandatory but not - * requested by device. + * Home agent rejected MIP (Mobile IP) registration because of reverse tunnel is mandatory but + * not requested by device. */ - MIP_HA_REV_TUNNEL_IS_MANDATORY_AND_T_BIT_NOT_SET = 0x7EC, + MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 0x7EC, /** - * Home agent rejected MIP registration because of encapsulation unavailable. + * Home agent rejected MIP (Mobile IP) registration because of encapsulation unavailable. */ MIP_HA_ENCAPSULATION_UNAVAILABLE = 0x7ED, /** @@ -397,29 +416,29 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * Brought down by the network. */ - NW_INITIATED_TERMINATION = 0x7EF, + NETWORK_INITIATED_TERMINATION = 0x7EF, /** * Another application in modem preempts the data call. */ MODEM_APP_PREEMPTED = 0x7F0, /** - * V4 PDN is in throttled state due to network providing only V6 address during the previous + * IPV4 PDN is in throttled state due to network providing only IPV6 address during the previous * VSNCP bringup (subs_limited_to_v6). */ - ERR_PDN_IPV4_CALL_DISALLOWED = 0x7F1, + PDN_IPV4_CALL_DISALLOWED = 0x7F1, /** - * V4 PDN is in throttled state due to previous VSNCP bringup failure(s). + * IPV4 PDN is in throttled state due to previous VSNCP bringup failure(s). */ - ERR_PDN_IPV4_CALL_THROTTLED = 0x7F2, + PDN_IPV4_CALL_THROTTLED = 0x7F2, /** - * V6 PDN is in throttled state due to network providing only V4 address during the previous + * IPV6 PDN is in throttled state due to network providing only IPV4 address during the previous * VSNCP bringup (subs_limited_to_v4). */ - ERR_PDN_IPV6_CALL_DISALLOWED = 0x7F3, + PDN_IPV6_CALL_DISALLOWED = 0x7F3, /** - * V6 PDN is in throttled state due to previous VSNCP bringup failure(s). + * IPV6 PDN is in throttled state due to previous VSNCP bringup failure(s). */ - ERR_PDN_IPV6_CALL_THROTTLED = 0x7F4, + PDN_IPV6_CALL_THROTTLED = 0x7F4, /** * Modem restart. */ @@ -435,7 +454,7 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * Physical link is in the process of cleanup. */ - PHYS_LINK_CLOSE_IN_PROGRESS = 0x7F8, + PHYSICAL_LINK_CLOSE_IN_PROGRESS = 0x7F8, /** * Interface bring up is attempted for an APN that is yet to be handed over to target RAT. */ @@ -447,11 +466,11 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * Card was refreshed or removed. */ - SIM_CARD_EVT = 0x7FB, + SIM_CARD_CHANGED = 0x7FB, /** * Device is going into lower power mode or powering down. */ - LPM_OR_PWR_DOWN = 0x7FC, + LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC, /** * APN has been disabled. */ @@ -463,7 +482,7 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * IPv6 address transfer failed. */ - IPV6_ADDR_TRANSFER_FAILED = 0x7FF, + IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF, /** * Target RAT swap failed. */ @@ -485,12 +504,12 @@ enum DataCallFailCause : @1.0::DataCallFailCause { * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum * number of IPv4 data connections. */ - MAX_V4_CONNECTIONS = 0x804, + MAX_IPV4_CONNECTIONS = 0x804, /** * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum * number of IPv6 data connections. */ - MAX_V6_CONNECTIONS = 0x805, + MAX_IPV6_CONNECTIONS = 0x805, /** * New PDN bring up is rejected during interface selection because the UE has already allotted * the available interfaces for other PDNs. @@ -512,835 +531,834 @@ enum DataCallFailCause : @1.0::DataCallFailCause { /** * The current interface is being in use. */ - IFACE_IN_USE = 0x80A, + INTERFACE_IN_USE = 0x80A, /** * PDN connection to the APN is disallowed on the roaming network. */ - APN_DISALLOWED_ON_ROAMING = 0x80C, + APN_DISALLOWED_ON_ROAMING = 0x80B, /** * APN-related parameters are changed. */ - APN_PARAM_CHANGED = 0x80D, + APN_PARAMETERS_CHANGED = 0x80C, /** * PDN is attempted to be brought up with NULL APN but NULL APN is not supported. */ - NULL_APN_DISALLOWED = 0x80E, + NULL_APN_DISALLOWED = 0x80D, /** * Thermal level increases and causes calls to be torn down when normal mode of operation is * not allowed. */ - THERMAL_MITIGATION = 0x80F, + THERMAL_MITIGATION = 0x80E, /** * PDN Connection to a given APN is disallowed because data is disabled from the device user * interface settings. */ - DATA_SETTINGS_DISABLED = 0x810, + DATA_SETTINGS_DISABLED = 0x80F, /** * PDN Connection to a given APN is disallowed because data roaming is disabled from the device * user interface settings and the UE is roaming. */ - DATA_ROAMING_SETTINGS_DISABLED = 0x811, + DATA_ROAMING_SETTINGS_DISABLED = 0x810, /** - * Default data subscription switch occurs. + * DDS (Default data subscription) switch occurs. */ - DDS_CALL_ABORT = 0x812, + DDS_SWITCHED = 0x811, /** * PDN being brought up with an APN that is part of forbidden APN Name list. */ - INVALID_APN_NAME = 0x813, + FORBIDDEN_APN_NAME = 0x812, /** * Default data subscription switch is in progress. */ - DDS_SWITCH_IN_PROGRESS = 0x814, + DDS_SWITCH_IN_PROGRESS = 0x813, /** * Roaming is disallowed during call bring up. */ - CALL_DISALLOWED_IN_ROAMING = 0x815, + CALL_DISALLOWED_IN_ROAMING = 0x814, /** * UE is unable to bring up a non-IP data call because the device is not camped on a NB1 cell. */ - NON_IP_NOT_SUPPORTED = 0x816, + NON_IP_NOT_SUPPORTED = 0x815, /** * Non-IP PDN is in throttled state due to previous VSNCP bringup failure(s). */ - ERR_PDN_NON_IP_CALL_THROTTLED = 0x817, + PDN_NON_IP_CALL_THROTTLED = 0x816, /** * Non-IP PDN is in disallowed state due to the network providing only an IP address. */ - ERR_PDN_NON_IP_CALL_DISALLOWED = 0x818, + PDN_NON_IP_CALL_DISALLOWED = 0x817, /** * Device in CDMA locked state. */ - CDMA_LOCK = 0x819, + CDMA_LOCK = 0x818, /** * Received an intercept order from the base station. */ - CDMA_INTERCEPT = 0x81A, + CDMA_INTERCEPT = 0x819, /** * Receiving a reorder from the base station. */ - CDMA_REORDER = 0x81B, + CDMA_REORDER = 0x81A, /** - * Receiving a release from the base station with a SO Reject reason. + * Receiving a release from the base station with a SO (Service Option) Reject reason. */ - CDMA_REL_SO_REJ = 0x81C, + CDMA_RELEASE_DUE_TO_SO_REJECTION = 0x81B, /** * Receiving an incoming call from the base station. */ - CDMA_INCOM_CALL = 0x81D, + CDMA_INCOMING_CALL = 0x81C, /** - * RL/FL fade or receiving a call release from the base station. + * Received an alert stop from the base station due to incoming only. */ - CDMA_ALERT_STOP = 0x81E, + CDMA_ALERT_STOP = 0x81D, /** * Channel acquisition failures. This indicates that device has failed acquiring all the * channels in the PRL. */ - CHANNEL_ACQUISITION_FAILURE = 0x81F, + CHANNEL_ACQUISITION_FAILURE = 0x81E, /** * Maximum access probes transmitted. */ - MAX_ACCESS_PROBE = 0x820, + MAX_ACCESS_PROBE = 0x81F, /** * Concurrent service is not supported by base station. */ - CCS_NOT_SUPPORTED_BY_BS = 0x821, + CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820, /** * There was no response received from the base station. */ - NO_RESPONSE_FROM_BS = 0x822, + NO_RESPONSE_FROM_BASE_STATION = 0x821, /** * The base station rejecting the call. */ - REJECTED_BY_BS = 0x823, + REJECTED_BY_BASE_STATION = 0x822, /** * The concurrent services requested were not compatible. */ - CCS_INCOMPATIBLE = 0x824, + CONCURRENT_SERVICES_INCOMPATIBLE = 0x823, /** * Device does not have CDMA service. */ - NO_CDMA_SRV = 0x825, + NO_CDMA_SERVICE = 0x824, /** * RUIM not being present. */ - UIM_NOT_PRESENT = 0x826, + RUIM_NOT_PRESENT = 0x825, /** * Receiving a retry order from the base station. */ - CDMA_RETRY_ORDER = 0x827, + CDMA_RETRY_ORDER = 0x826, /** * Access blocked by the base station. */ - ACCESS_BLOCK = 0x828, + ACCESS_BLOCK = 0x827, /** * Access blocked by the base station for all mobile devices. */ - ACCESS_BLOCK_ALL = 0x829, + ACCESS_BLOCK_ALL = 0x828, /** * Maximum access probes for the IS-707B call. */ - IS707B_MAX_ACC = 0x82A, + IS707B_MAX_ACCESS_PROBES = 0x829, /** * Put device in thermal emergency. */ - THERMAL_EMERGENCY = 0x82B, + THERMAL_EMERGENCY = 0x82A, /** * In favor of a voice call or SMS when concurrent voice and data are not supported. */ - CCS_NOT_ALLOWED = 0x82C, + CONCURRENT_SERVICES_NOT_ALLOWED = 0x82B, /** * The other clients rejected incoming call. */ - INCOM_REJ = 0x82D, + INCOMING_CALL_REJECTED = 0x82C, /** * No service on the gateway. */ - NO_GATEWAY_SRV = 0x82E, + NO_SERVICE_ON_GATEWAY = 0x82D, /** * GPRS context is not available. */ - NO_GPRS_CONTEXT = 0x82F, + NO_GPRS_CONTEXT = 0x82E, /** * Network refuses service to the MS because either an identity of the MS is not acceptable to * the network or the MS does not pass the authentication check. */ - ILLEGAL_MS = 0x830, + ILLEGAL_MS = 0x82F, /** * ME could not be authenticated and the ME used is not acceptable to the network. */ - ILLEGAL_ME = 0x831, + ILLEGAL_ME = 0x830, /** * Not allowed to operate either GPRS or non-GPRS services. */ - GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 0x832, + GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 0x831, /** * MS is not allowed to operate GPRS services. */ - GPRS_SERVICES_NOT_ALLOWED = 0x833, + GPRS_SERVICES_NOT_ALLOWED = 0x832, /** * No matching identity or context could be found in the network. */ - MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 0x834, + MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 0x833, /** - * Mobile reachable timer has expired, or the GMM context data related to the subscription dose + * Mobile reachable timer has expired, or the GMM context data related to the subscription does * not exist in the SGSN. */ - IMPLICITLY_DETACHED = 0x835, + IMPLICITLY_DETACHED = 0x834, /** * UE requests GPRS service, or the network initiates a detach request in a PLMN which does not * offer roaming for GPRS services to that MS. */ - PLMN_NOT_ALLOWED = 0x836, + PLMN_NOT_ALLOWED = 0x835, /** * MS requests service, or the network initiates a detach request, in a location area where the * HPLMN determines that the MS, by subscription, is not allowed to operate. */ - LA_NOT_ALLOWED = 0x837, + LOCATION_AREA_NOT_ALLOWED = 0x836, /** * UE requests GPRS service or the network initiates a detach request in a PLMN that does not * offer roaming for GPRS services. */ - GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 0x838, + GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 0x837, /** * PDP context already exists. */ - PDP_DUPLICATE = 0x839, + PDP_DUPLICATE = 0x838, /** * RAT change on the UE. */ - UE_RAT_CHANGE = 0x83A, + UE_RAT_CHANGE = 0x839, /** * Network cannot serve a request from the MS due to congestion. */ - CONGESTION = 0x83B, + CONGESTION = 0x83A, /** * MS requests an establishment of the radio access bearers for all active PDP contexts by * sending a service request message indicating data to the network, but the SGSN does not have * any active PDP context. */ - NO_PDP_CONTEXT_ACTIVATED = 0x83C, + NO_PDP_CONTEXT_ACTIVATED = 0x83B, /** * Access class blocking restrictions for the current camped cell. */ - ACCESS_CLASS_DSAC_REJECTION = 0x83D, + ACCESS_CLASS_DSAC_REJECTION = 0x83C, /** * SM attempts PDP activation for a maximum of four attempts. */ - PDP_ACTIVATE_MAX_RETRY_FAILED = 0x83E, + PDP_ACTIVATE_MAX_RETRY_FAILED = 0x83D, /** * Radio access bearer failure. */ - RAB_FAILURE = 0x83F, + RADIO_ACCESS_BEARER_FAILURE = 0x83E, /** * Invalid EPS bearer identity in the request. */ - ESM_UNKNOWN_EPS_BEARER_CONTEXT = 0x840, + ESM_UNKNOWN_EPS_BEARER_CONTEXT = 0x83F, /** * Data radio bearer is released by the RRC. */ - DRB_RELEASED_AT_RRC = 0x841, + DRB_RELEASED_BY_RRC = 0x840, /** * Indicate the connection was released. */ - NAS_SIG_CONN_RELEASED = 0x842, + CONNECTION_RELEASED = 0x841, /** * UE is detached. */ - EMM_DETACHED = 0x843, + EMM_DETACHED = 0x842, /** * Attach procedure is rejected by the network. */ - EMM_ATTACH_FAILED = 0x844, + EMM_ATTACH_FAILED = 0x843, /** * Attach procedure is started for EMC purposes. */ - EMM_ATTACH_STARTED = 0x845, + EMM_ATTACH_STARTED = 0x844, /** * Service request procedure failure. */ - LTE_NAS_SERVICE_REQ_FAILED = 0x846, + LTE_NAS_SERVICE_REQUEST_FAILED = 0x845, /** - * Active dedication bearer was requested using the same default bearer ID. + * Active dedicated bearer was requested using the same default bearer ID. */ - ESM_ACTIVE_DEDICATED_BEARER_REACTIVATED_BY_NW = 0x847, + DUPLICATE_BEARER_ID = 0x846, /** * Collision scenarios for the UE and network-initiated procedures. */ - ESM_LOWER_LAYER_FAILURE = 0x848, + ESM_COLLISION_SCENARIOS = 0x847, /** * Bearer must be deactivated to synchronize with the network. */ - ESM_SYNC_UP_WITH_NW = 0x849, + ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 0x848, /** - * Active dedication bearer was requested for an existing default bearer. + * Active dedicated bearer was requested for an existing default bearer. */ - ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 0x84A, + ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 0x849, /** * Bad OTA message is received from the network. */ - ESM_BAD_OTA_MESSAGE = 0x84B, + ESM_BAD_OTA_MESSAGE = 0x84A, /** * Download server rejected the call. */ - ESM_DS_REJECTED_THE_CALL = 0x84C, + ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 0x84B, /** * PDN was disconnected by the downlaod server due to IRAT. */ - ESM_CONTEXT_TRANSFERED_DUE_TO_IRAT = 0x84D, + ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 0x84C, /** * Dedicated bearer will be deactivated regardless of the network response. */ - DS_EXPLICIT_DEACT = 0x84E, + DS_EXPLICIT_DEACTIVATION = 0x84D, /** * No specific local cause is mentioned, usually a valid OTA cause. */ - ESM_LOCAL_CAUSE_NONE = 0x84F, + ESM_LOCAL_CAUSE_NONE = 0x84E, /** * Throttling is not needed for this service request failure. */ - LTE_NAS_SERVICE_REQ_FAILED_NO_THROTTLE = 0x850, + LTE_THROTTLING_NOT_REQUIRED = 0x84F, /** * Access control list check failure at the lower layer. */ - ACCESS_CONTROL_LIST_CHECK_FAILURE = 0x851, + ACCESS_CONTROL_LIST_CHECK_FAILURE = 0x850, /** * Service is not allowed on the requested PLMN. */ - LTE_NAS_SERVICE_REQ_FAILED_DS_DISALLOW = 0x852, + SERVICE_NOT_ALLOWED_ON_PLMN = 0x851, /** * T3417 timer expiration of the service request procedure. */ - EMM_T3417_EXPIRED = 0x853, + EMM_T3417_EXPIRED = 0x852, /** * Extended service request fails due to expiration of the T3417 EXT timer. */ - EMM_T3417_EXT_EXPIRED = 0x854, + EMM_T3417_EXT_EXPIRED = 0x853, /** - * Transmission failure of uplink data. + * Transmission failure of radio resource control (RRC) uplink data. */ - LRRC_UL_DATA_CNF_FAILURE_TXN = 0x855, + RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 0x854, /** - * Uplink data delivery failed due to a handover. + * Radio resource control (RRC) uplink data delivery failed due to a handover. */ - LRRC_UL_DATA_CNF_FAILURE_HO = 0x856, + RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 0x855, /** - * Uplink data delivery failed due to a connection release. + * Radio resource control (RRC) uplink data delivery failed due to a connection release. */ - LRRC_UL_DATA_CNF_FAILURE_CONN_REL = 0x857, + RRC_UPLINK_CONNECTION_RELEASE = 0x856, /** - * Uplink data delivery failed due to a radio link failure. + * Radio resource control (RRC) uplink data delivery failed due to a radio link failure. */ - LRRC_UL_DATA_CNF_FAILURE_RLF = 0x858, + RRC_UPLINK_RADIO_LINK_FAILURE = 0x857, /** - * RRC is not connected but the NAS sends an uplink data request. + * Radio resource control (RRC) is not connected but the non-access stratum (NAS) sends an + * uplink data request. */ - LRRC_UL_DATA_CNF_FAILURE_CTRL_NOT_CONN = 0x859, + RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 0x858, /** - * Connection failure at access stratum. + * Radio resource control (RRC) connection failure at access stratum. */ - LRRC_CONN_EST_FAILURE = 0x85A, + RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 0x859, /** - * Connection establishment is aborted due to another procedure. + * Radio resource control (RRC) connection establishment is aborted due to another procedure. */ - LRRC_CONN_EST_FAILURE_ABORTED = 0x85B, + RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 0x85A, /** - * Connection establishment failed due to a lower layer RRC connection failure. + * Radio resource control (RRC) connection establishment failed due to access barrred. */ - LRRC_CONN_EST_FAILURE_ACCESS_BARRED = 0x85C, + RRC_CONNECTION_ACCESS_BARRED = 0x85B, /** - * Connection establishment failed due to cell reselection at access stratum. + * Radio resource control (RRC) connection establishment failed due to cell reselection at + * access stratum. */ - LRRC_CONN_EST_FAILURE_CELL_RESEL = 0x85D, + RRC_CONNECTION_CELL_RESELECTION = 0x85C, /** - * Connection establishment failed due to configuration failure at the RRC. + * Connection establishment failed due to configuration failure at the radio resource control + * (RRC). */ - LRRC_CONN_EST_FAILURE_CONFIG_FAILURE = 0x85E, + RRC_CONNECTION_CONFIG_FAILURE = 0x85D, /** - * Connection could not be established in the time limit. + * Radio resource control (RRC) connection could not be established in the time limit. */ - LRRC_CONN_EST_FAILURE_TIMER_EXPIRED = 0x85F, + RRC_CONNECTION_TIMER_EXPIRED = 0x85E, /** - * Connection establishment failed due to a link failure at the RRC. + * Connection establishment failed due to a link failure at the radio resource control (RRC). */ - LRRC_CONN_EST_FAILURE_LINK_FAILURE = 0x860, + RRC_CONNECTION_LINK_FAILURE = 0x85F, /** - * Connection establishment failed as the RRC is not camped on any cell. + * Connection establishment failed as the radio resource control (RRC) is not camped on any + * cell. */ - LRRC_CONN_EST_FAILURE_NOT_CAMPED = 0x861, + RRC_CONNECTION_CELL_NOT_CAMPED = 0x860, /** - * Connection establishment failed due to a service interval failure at the RRC. + * Connection establishment failed due to a service interval failure at the radio resource + * control (RRC). */ - LRRC_CONN_EST_FAILURE_SI_FAILURE = 0x862, + RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 0x861, /** - * Connection establishment failed due to the network rejecting the UE connection request. + * Radio resource control (RRC) connection establishment failed due to the network rejecting the + * UE connection request. */ - LRRC_CONN_EST_FAILURE_CONN_REJECT = 0x863, + RRC_CONNECTION_REJECT_BY_NETWORK = 0x862, /** - * Normal connection release. + * Normal radio resource control (RRC) connection release. */ - LRRC_CONN_REL_NORMAL = 0x864, + RRC_CONNECTION_NORMAL_RELEASE = 0x863, /** - * Connection release failed due to radio link failure conditions. + * Radio resource control (RRC) connection release failed due to radio link failure conditions. */ - LRRC_CONN_REL_RLF = 0x865, + RRC_CONNECTION_RADIO_LINK_FAILURE = 0x864, /** - * Connection reestablishment failure. + * Radio resource control (RRC) connection re-establishment failure. */ - LRRC_CONN_REL_CRE_FAILURE = 0x866, + RRC_CONNECTION_REESTABLISHMENT_FAILURE = 0x865, /** * UE is out of service during the call register. */ - LRRC_CONN_REL_OOS_DURING_CRE = 0x867, + RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 0x866, /** - * Connection has been released by the RRC due to an abort request. + * Connection has been released by the radio resource control (RRC) due to an abort request. */ - LRRC_CONN_REL_ABORTED = 0x868, + RRC_CONNECTION_ABORT_REQUEST = 0x867, /** - * Connection released due to a system information block read error. + * Radio resource control (RRC) connection released due to a system information block read + * error. */ - LRRC_CONN_REL_SIB_READ_ERROR = 0x869, + RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 0x868, /** * Network-initiated detach with reattach. */ - DETACH_WITH_REATTACH_LTE_NW_DETACH = 0x86A, + NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 0x869, /** * Network-initiated detach without reattach. */ - DETACH_WITHOUT_REATTACH_LTE_NW_DETACH = 0x86B, + NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 0x86A, /** * ESM procedure maximum attempt timeout failure. */ - ESM_PROC_TIME_OUT = 0x86C, + ESM_PROCEDURE_TIME_OUT = 0x86B, /** * No PDP exists with the given connection ID while modifying or deactivating or activation for * an already active PDP. */ - INVALID_CONNECTION_ID = 0x86D, + INVALID_CONNECTION_ID = 0x86C, /** * Maximum NSAPIs have been exceeded during PDP activation. */ - INVALID_NSAPI = 0x86E, + MAXIMIUM_NSAPIS_EXCEEDED = 0x86D, /** * Primary context for NSAPI does not exist. */ - INVALID_PRI_NSAPI = 0x86F, + INVALID_PRIMARY_NSAPI = 0x86E, /** * Unable to encode the OTA message for MT PDP or deactivate PDP. */ - INVALID_FIELD = 0x870, + CANNOT_ENCODE_OTA_MESSAGE = 0x86F, /** * Radio access bearer is not established by the lower layers during activation, modification, * or deactivation. */ - RAB_SETUP_FAILURE = 0x871, + RADIO_ACCESS_BEARER_SETUP_FAILURE = 0x870, /** * Expiration of the PDP establish timer with a maximum of five retries. */ - PDP_ESTABLISH_MAX_TIMEOUT = 0x872, + PDP_ESTABLISH_TIMEOUT_EXPIRED = 0x871, /** * Expiration of the PDP modify timer with a maximum of four retries. */ - PDP_MODIFY_MAX_TIMEOUT = 0x873, + PDP_MODIFY_TIMEOUT_EXPIRED = 0x872, /** * Expiration of the PDP deactivate timer with a maximum of four retries. */ - PDP_INACTIVE_MAX_TIMEOUT = 0x874, + PDP_INACTIVE_TIMEOUT_EXPIRED = 0x873, /** * PDP activation failed due to RRC_ABORT or a forbidden PLMN. */ - PDP_LOWERLAYER_ERROR = 0x875, + PDP_LOWERLAYER_ERROR = 0x874, /** * MO PDP modify collision when the MT PDP is already in progress. */ - PDP_MODIFY_COLLISION = 0x876, - /** - * Radio resource is not available. - */ - SM_NO_RADIO_AVAILABLE = 0x877, - /** - * Abort due to service not available. - */ - SM_ABORT_SERVICE_NOT_AVAILABLE = 0x878, + PDP_MODIFY_COLLISION = 0x875, /** * Maximum size of the L2 message was exceeded. */ - MESSAGE_EXCEED_MAX_L2_LIMIT = 0x879, + MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 0x876, /** - * NAS request was rejected by the network. + * Non-access stratum (NAS) request was rejected by the network. */ - SM_NAS_SRV_REQ_FAILURE = 0x87A, + NAS_REQUEST_REJECTED_BY_NETWORK = 0x877, /** - * RRC connection establishment failure due to an error in the request message. + * Radio resource control (RRC) connection establishment failure due to an error in the request + * message. */ - RRC_CONN_EST_FAILURE_REQ_ERROR = 0x87B, + RRC_CONNECTION_INVALID_REQUEST = 0x878, /** - * RRC connection establishment failure due to a change in the tracking area ID. + * Radio resource control (RRC) connection establishment failure due to a change in the tracking + * area ID. */ - RRC_CONN_EST_FAILURE_TAI_CHANGE = 0x87C, + RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 0x879, /** - * RRC connection establishment failure because the RF was unavailable. + * Radio resource control (RRC) connection establishment failure due to the RF was unavailable. */ - RRC_CONN_EST_FAILURE_RF_UNAVAILABLE = 0x87D, + RRC_CONNECTION_RF_UNAVAILABLE = 0x87A, /** - * Connection was aborted before deactivating the LTE stack due to a successful LX IRAT. - * (e.g., after IRAT handovers) + * Radio resource control (RRC) connection was aborted before deactivating the LTE stack due to + * a successful LTE to WCDMA/GSM/TD-SCDMA IRAT change. */ - RRC_CONN_REL_ABORTED_IRAT_SUCCESS = 0x87E, + RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 0x87B, /** - * If the UE has an LTE radio link failure before security is established, the connection must - * be released and the UE must return to idle. + * If the UE has an LTE radio link failure before security is established, the radio resource + * control (RRC) connection must be released and the UE must return to idle. */ - RRC_CONN_REL_RLF_SEC_NOT_ACTIVE = 0x87F, + RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 0x87C, /** - * Connection was aborted by the NAS after an IRAT to LTE IRAT handover. + * Radio resource control (RRC) connection was aborted by the non-access stratum (NAS) after an + * IRAT to LTE IRAT handover. */ - RRC_CONN_REL_IRAT_TO_LTE_ABORTED = 0x880, + RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 0x87D, /** - * Connection was aborted before deactivating the LTE stack after a successful LR IRAT cell - * change order procedure. + * Radio resource control (RRC) connection was aborted before deactivating the LTE stack after a + * successful LTE to GSM/EDGE IRAT cell change order procedure. */ - RRC_CONN_REL_IRAT_FROM_LTE_TO_G_CCO_SUCCESS = 0x881, + RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 0x87E, /** - * Connection was aborted in the middle of a LG IRAT cell change order. + * Radio resource control (RRC) connection was aborted in the middle of a LTE to GSM IRAT cell + * change order procedure. */ - RRC_CONN_REL_IRAT_FROM_LTE_TO_G_CCO_ABORTED = 0x882, + RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 0x87F, /** * IMSI present in the UE is unknown in the home subscriber server. */ - IMSI_UNKNOWN_IN_HSS = 0x883, + IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 0x880, /** * IMEI of the UE is not accepted by the network. */ - IMEI_NOT_ACCEPTED = 0x884, + IMEI_NOT_ACCEPTED = 0x881, /** * EPS and non-EPS services are not allowed by the network. */ - EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 0x885, + EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 0x882, /** * EPS services are not allowed in the PLMN. */ - EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 0x886, + EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 0x883, /** * Mobile switching center is temporarily unreachable. */ - MSC_TEMPORARILY_NOT_REACHABLE = 0x887, + MSC_TEMPORARILY_NOT_REACHABLE = 0x884, /** * CS domain is not available. */ - CS_DOMAIN_NOT_AVAILABLE = 0x888, + CS_DOMAIN_NOT_AVAILABLE = 0x885, /** * ESM level failure. */ - ESM_FAILURE = 0x889, + ESM_FAILURE = 0x886, /** * MAC level failure. */ - MAC_FAILURE = 0x88A, + MAC_FAILURE = 0x887, /** * Synchronization failure. */ - SYNCH_FAILURE = 0x88B, + SYNCHRONIZATION_FAILURE = 0x888, /** * UE security capabilities mismatch. */ - UE_SECURITY_CAPABILITIES_MISMATCH = 0x88C, + UE_SECURITY_CAPABILITIES_MISMATCH = 0x889, /** * Unspecified security mode reject. */ - SECURITY_MODE_REJ_UNSPECIFIED = 0x88D, + SECURITY_MODE_REJECTED = 0x88A, /** * Unacceptable non-EPS authentication. */ - NON_EPS_AUTH_UNACCEPTABLE = 0x88E, + UNACCEPTABLE_NON_EPS_AUTHENTICATION = 0x88B, /** * CS fallback call establishment is not allowed. */ - CS_FALLBACK_CALL_EST_NOT_ALLOWED = 0x88F, + CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 0x88C, /** * No EPS bearer context was activated. */ - NO_EPS_BEARER_CONTEXT_ACTIVATED = 0x890, + NO_EPS_BEARER_CONTEXT_ACTIVATED = 0x88D, /** * Invalid EMM state. */ - EMM_INVALID_STATE = 0x891, + INVALID_EMM_STATE = 0x88E, /** * Non-Access Spectrum layer failure. */ - NAS_LAYER_FAILURE = 0x892, + NAS_LAYER_FAILURE = 0x88F, /** * Multiple PDP call feature is disabled. */ - MULTI_PDN_NOT_ALLOWED = 0x893, + MULTIPLE_PDP_CALL_NOT_ALLOWED = 0x890, /** * Data call has been brought down because EMBMS is not enabled at the RRC layer. */ - EMBMS_NOT_ENABLED = 0x894, + EMBMS_NOT_ENABLED = 0x891, /** * Data call was unsuccessfully transferred during the IRAT handover. */ - PENDING_REDIAL_CALL_CLEANUP = 0x895, + IRAT_HANDOVER_FAILED = 0x892, /** * EMBMS data call has been successfully brought down. */ - EMBMS_REGULAR_DEACTIVATION = 0x896, + EMBMS_REGULAR_DEACTIVATION = 0x893, /** * Test loop-back data call has been successfully brought down. */ - TLB_REGULAR_DEACTIVATION = 0x897, + TEST_LOOPBACK_REGULAR_DEACTIVATION = 0x894, /** * Lower layer registration failure. */ - LOWER_LAYER_REGISTRATION_FAILURE = 0x898, + LOWER_LAYER_REGISTRATION_FAILURE = 0x895, /** - * Network initiates a detach on LTE with error cause ""data plan has been replenished or has - * expired. + * Network initiates a detach on LTE with error cause "data plan has been replenished or has + * expired". */ - DETACH_EPS_SERVICES_NOT_ALLOWED = 0x899, + DATA_PLAN_EXPIRED = 0x896, /** * UMTS interface is brought down due to handover from UMTS to iWLAN. */ - SM_INTERNAL_PDP_DEACTIVATION = 0x89A, + UMTS_HANDOVER_TO_IWLAN = 0x897, /** - * The reception of a connection deny message with a deny code of general or network busy. + * Received a connection deny due to general or network busy on EVDO network. */ - CD_GEN_OR_BUSY = 0x89B, + EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 0x898, /** - * The reception of a connection deny message with a deny code of billing failure or - * authentication failure. + * Received a connection deny due to billing or authentication failure on EVDO network. */ - CD_BILL_OR_AUTH = 0x89C, + EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 0x899, /** * HDR system has been changed due to redirection or the PRL was not preferred. */ - HDR_CHANGED = 0x89D, + EVDO_HDR_CHANGED = 0x89A, /** * Device exited HDR due to redirection or the PRL was not preferred. */ - HDR_EXITED = 0x89E, + EVDO_HDR_EXITED = 0x89B, /** * Device does not have an HDR session. */ - HDR_NO_SESSION = 0x89F, + EVDO_HDR_NO_SESSION = 0x89C, /** * It is ending an HDR call origination in favor of a GPS fix. */ - HDR_ORIG_DURING_GPS_FIX = 0x8A0, + EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 0x89D, /** * Connection setup on the HDR system was time out. */ - HDR_CS_TIMEOUT = 0x8A1, + EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 0x89E, /** * Device failed to acquire a co-located HDR for origination. */ - COLLOC_ACQ_FAIL = 0x8A2, + FAILED_TO_ACQUIRE_COLOCATED_HDR = 0x89F, /** * OTASP commit is in progress. */ - OTASP_COMMIT_IN_PROG = 0x8A3, + OTASP_COMMIT_IN_PROGRESS = 0x8A0, /** * Device has no hybrid HDR service. */ - NO_HYBR_HDR_SRV = 0x8A4, + NO_HYBRID_HDR_SERVICE = 0x8A1, /** * HDR module could not be obtained because of the RF locked. */ - HDR_NO_LOCK_GRANTED = 0x8A5, + HDR_NO_LOCK_GRANTED = 0x8A2, /** * DBM or SMS is in progress. */ - HOLD_OTHER_IN_PROG = 0x8A6, + DBM_OR_SMS_IN_PROGRESS = 0x8A3, /** * HDR module released the call due to fade. */ - HDR_FADE = 0x8A7, + HDR_FADE = 0x8A4, /** * HDR system access failure. */ - HDR_ACC_FAIL = 0x8A8, + HDR_ACCESS_FAILURE = 0x8A5, /** * P_rev supported by 1 base station is less than 6, which is not supported for a 1X data call. * The UE must be in the footprint of BS which has p_rev >= 6 to support this SO33 call. */ - UNSUPPORTED_1X_PREV = 0x8A9, + UNSUPPORTED_1X_PREV = 0x8A6, /** * Client ended the data call. */ - LOCAL_END = 0x8AA, + LOCAL_END = 0x8A7, /** * Device has no service. */ - NO_SRV = 0x8AB, + NO_SERVICE = 0x8A8, /** * Device lost the system due to fade. */ - FADE = 0x8AC, + FADE = 0x8A9, /** * Receiving a release from the base station with no reason. */ - REL_NORMAL = 0x8AD, + NORMAL_RELEASE = 0x8AA, /** * Access attempt is already in progress. */ - ACC_IN_PROG = 0x8AE, - /** - * Access failure. - */ - ACC_FAIL = 0x8AF, + ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 0x8AB, /** * Device is in the process of redirecting or handing off to a different target system. */ - REDIR_OR_HANDOFF = 0x8B0, + REDIRECTION_OR_HANDOFF_IN_PROGRESS = 0x8AC, /** * Device is operating in Emergency mode. */ - EMERGENCY_MODE = 0x8B1, + EMERGENCY_MODE = 0x8AD, /** * Device is in use (e.g., voice call). */ - PHONE_IN_USE = 0x8B2, + PHONE_IN_USE = 0x8AE, /** - * Device operational mode is different from the mode requested in the traffic channel bring up + * Device operational mode is different from the mode requested in the traffic channel bring up. */ - INVALID_MODE = 0x8B3, + INVALID_MODE = 0x8AF, /** * SIM was marked by the network as invalid for the circuit and/or packet service domain. */ - INVALID_SIM_STATE = 0x8B4, + INVALID_SIM_STATE = 0x8B0, /** * There is no co-located HDR. */ - NO_COLLOC_HDR = 0x8B5, + NO_COLLOCATED_HDR = 0x8B1, /** * UE is entering power save mode. */ - EMM_DETACHED_PSM = 0x8B6, + UE_IS_ENTERING_POWERSAVE_MODE = 0x8B2, /** * Dual switch from single standby to dual standby is in progress. */ - DUAL_SWITCH = 0x8B7, + DUAL_SWITCH = 0x8B3, /** - * Data call bring up fails in the PPP setup due to a timeout. - * (e.g., an LCP conf ack was not received from the network) + * Data call bring up fails in the PPP setup due to a timeout. (e.g., an LCP conf ack was not + * received from the network) */ - PPP_TIMEOUT = 0x8B8, + PPP_TIMEOUT = 0x8B4, /** * Data call bring up fails in the PPP setup due to an authorization failure. * (e.g., authorization is required, but not negotiated with the network during an LCP phase) */ - PPP_AUTH_FAILURE = 0x8B9, + PPP_AUTH_FAILURE = 0x8B5, /** * Data call bring up fails in the PPP setup due to an option mismatch. */ - PPP_OPTION_MISMATCH = 0x8BA, + PPP_OPTION_MISMATCH = 0x8B6, /** * Data call bring up fails in the PPP setup due to a PAP failure. */ - PPP_PAP_FAILURE = 0x8BB, + PPP_PAP_FAILURE = 0x8B7, /** * Data call bring up fails in the PPP setup due to a CHAP failure. */ - PPP_CHAP_FAILURE = 0x8BC, + PPP_CHAP_FAILURE = 0x8B8, /** * Data call bring up fails in the PPP setup because the PPP is in the process of cleaning the * previous PPP session. */ - PPP_ERR_CLOSE_IN_PROGRESS = 0x8BD, + PPP_CLOSE_IN_PROGRESS = 0x8B9, /** * IPv6 interface bring up fails because the network provided only the IPv4 address for the * upcoming PDN permanent client can reattempt a IPv6 call bring up after the IPv4 interface is * also brought down. However, there is no guarantee that the network will provide a IPv6 * address. */ - EHRPD_SUBS_LIMITED_TO_V4 = 0x8BE, + LIMITED_TO_IPV4 = 0x8BA, /** * IPv4 interface bring up fails because the network provided only the IPv6 address for the * upcoming PDN permanent client can reattempt a IPv4 call bring up after the IPv6 interface is * also brought down. However there is no guarantee that the network will provide a IPv4 * address. */ - EHRPD_SUBS_LIMITED_TO_V6 = 0x8BF, + LIMITED_TO_IPV6 = 0x8BB, /** * Data call bring up fails in the VSNCP phase due to a VSNCP timeout error. */ - EHRPD_VSNCP_TIMEOUT = 0x8C0, + VSNCP_TIMEOUT = 0x8BC, /** - * Data call bring up fails in the VSNCP phase due to a general error + * Data call bring up fails in the VSNCP phase due to a general error. It's used when there is + * no other specific error code available to report the failure. */ - EHRPD_VSNCP_GEN_ERROR = 0x8C1, + VSNCP_GEN_ERROR = 0x8BD, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the requested APN is unauthorized. */ - EHRPD_VSNCP_UNAUTH_APN = 0x8C2, + VSNCP_APN_UNATHORIZED = 0x8BE, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the PDN limit has been exceeded. */ - EHRPD_VSNCP_PDN_LIMIT_EXCEED = 0x8C3, + VSNCP_PDN_LIMIT_EXCEEDED = 0x8BF, /** - * Data call bring up fails in the VSNCP phase because the network rejected the VSNCP - * configuration request due to no PDN gateway. + * Data call bring up fails in the VSNCP phase due to the network rejected the VSNCP + * configuration request due to no PDN gateway address. */ - EHRPD_VSNCP_NO_PDN_GW = 0x8C4, + VSNCP_NO_PDN_GATEWAY_ADDRESS = 0x8C0, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the PDN gateway is unreachable. */ - EHRPD_VSNCP_PDN_GW_UNREACH = 0x8C5, + VSNCP_PDN_GATEWAY_UNREACHABLE = 0x8C1, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request due to a PDN gateway reject. */ - EHRPD_VSNCP_PDN_GW_REJ = 0x8C6, + VSNCP_PDN_GATEWAY_REJECT = 0x8C2, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request with the reason of insufficient parameter. */ - EHRPD_VSNCP_INSUFF_PARAM = 0x8C7, + VSNCP_INSUFFICIENT_PARAMETERS = 0x8C3, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request with the reason of resource unavailable. */ - EHRPD_VSNCP_RESOURCE_UNAVAIL = 0x8C8, + VSNCP_RESOURCE_UNAVAILABLE = 0x8C4, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP - * configuration request with the reason of admin prohibited. + * configuration request with the reason of administratively prohibited at the HSGW. */ - EHRPD_VSNCP_ADMIN_PROHIBIT = 0x8C9, + VSNCP_ADMINISTRATIVELY_PROHIBITED = 0x8C5, /** * Data call bring up fails in the VSNCP phase due to a network rejection of PDN ID in use, or * all existing PDNs are brought down with this end reason because one of the PDN bring up was * rejected by the network with the reason of PDN ID in use. */ - EHRPD_VSNCP_PDN_ID_IN_USE = 0x8CA, + VSNCP_PDN_ID_IN_USE = 0x8C6, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request for the reason of subscriber limitation. */ - EHRPD_VSNCP_SUBSCR_LIMITATION = 0x8CB, + VSNCP_SUBSCRIBER_LIMITATION = 0x8C7, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the PDN exists for this APN. */ - EHRPD_VSNCP_PDN_EXISTS_FOR_THIS_APN = 0x8CC, + VSNCP_PDN_EXISTS_FOR_THIS_APN = 0x8C8, /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request with reconnect to this PDN not allowed, or an active data call is * terminated by the network because reconnection to this PDN is not allowed. Upon receiving - * this error code from the network, the modem infinitely throttles the PDN until the next - * power cycle. + * this error code from the network, the modem infinitely throttles the PDN until the next power + * cycle. */ - EHRPD_VSNCP_RECONNECT_NOT_ALLOWED = 0x8CD, + VSNCP_RECONNECT_NOT_ALLOWED = 0x8C9, /** * Device failure to obtain the prefix from the network. */ - IPV6_PREFIX_UNAVAILABLE = 0x8CE, + IPV6_PREFIX_UNAVAILABLE = 0x8CA, /** * System preference change back to SRAT during handoff */ - HANDOFF_PREF_SYS_BACK_TO_SRAT = 0x8CF, + HANDOFF_PREFERENCE_CHANGED = 0x8CB, }; /** @@ -1390,13 +1408,9 @@ enum PdpProtocolType : int32_t { */ NON_IP = 4, /** - * Ethernet protocol - */ - ETHERNET = 5, - /** * Transfer of Unstructured data to the Data Network via N6 */ - UNSTRUCTURED = 6, + UNSTRUCTURED = 5, }; safe_union RadioFrequencyInfo { @@ -1548,9 +1562,15 @@ struct CellInfo { CellInfoWcdma wcdma; CellInfoTdscdma tdscdma; CellInfoLte lte; + CellInfoNr nr; } info; }; +struct CellInfoNr { + NrSignalStrength signalStrength; + CellIdentityNr cellidentity; +}; + /** Overwritten from @1.2::NetworkScanResult in order to update the CellInfo to 1.4 version. */ struct NetworkScanResult { /** @@ -1767,3 +1787,131 @@ struct CarrierRestrictionsWithPriority { */ bool allowedCarriersPrioritized; }; + +struct CellIdentityNr { + /** 3-digit Mobile Country Code, in range[0, 999], INT_MAX means invalid/unreported. */ + string mcc; + + /** + * 2 or 3-digit Mobile Network Code, in range [0, 999], INT_MAX means invalid/unreported. + */ + string mnc; + + /** + * Physical cell id in range [0, 1007] described in 3GPP TS 38.331. This value must be valid. + */ + uint32_t pci; + + /** 16-bit tracking area code, INT_MAX means invalid/unreported. */ + int32_t tac; + + /** + * NR Absolute Radio Frequency Channel Number, in range [0, 3279165]. + * Reference: 3GPP TS 38.101-1 and 3GPP TS 38.101-2 section 5.4.2.1. + * This value must be valid. + */ + int32_t nrarfcn; + + CellIdentityOperatorNames operatorNames; +}; + +struct NrSignalStrength { + /** + * SS reference signal received power, multipled by -1. + * + * Reference: 3GPP TS 38.215. + * + * Range [44, 140], INT_MAX means invalid/unreported. + */ + int32_t ssRsrp; + + /** + * SS reference signal received quality, multipled by -1. + * + * Reference: 3GPP TS 38.215. + * + * Range [3, 20], INT_MAX means invalid/unreported. + */ + int32_t ssRsrq; + + /** + * SS signal-to-noise and interference ratio. + * + * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1. + * + * Range [-23, 40], INT_MAX means invalid/unreported. + */ + int32_t ssSinr; + + /** + * CSI reference signal received power, multipled by -1. + * + * Reference: 3GPP TS 38.215. + * + * Range [44, 140], INT_MAX means invalid/unreported. + */ + int32_t csiRsrp; + + /** + * CSI reference signal received quality, multipled by -1. + * + * Reference: 3GPP TS 38.215. + * + * Range [3, 20], INT_MAX means invalid/unreported. + */ + int32_t csiRsrq; + + /** + * CSI signal-to-noise and interference ratio. + * + * Reference: 3GPP TS 138.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1. + * + * Range [-23, 40], INT_MAX means invalid/unreported. + */ + int32_t csiSinr; +}; + +/** Overwritten from @1.2::SignalStrength in order to add signal strength for NR. */ +struct SignalStrength { + /** + * If GSM measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + GsmSignalStrength gsm; + + /** + * If CDMA measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + CdmaSignalStrength cdma; + + /** + * If EvDO measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + EvdoSignalStrength evdo; + + /** + * If LTE measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + LteSignalStrength lte; + + /** + * If TD-SCDMA measurements are provided, this structure must contain valid measurements; + * otherwise all fields should be set to INT_MAX to mark them as invalid. + */ + TdscdmaSignalStrength tdscdma; + + /** + * If WCDMA measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + WcdmaSignalStrength wcdma; + + /** + * If NR 5G measurements are provided, this structure must contain valid measurements; otherwise + * all fields should be set to INT_MAX to mark them as invalid. + */ + NrSignalStrength nr; +}; diff --git a/radio/1.4/vts/OWNERS b/radio/1.4/vts/OWNERS new file mode 100644 index 0000000000..fd69f361ed --- /dev/null +++ b/radio/1.4/vts/OWNERS @@ -0,0 +1,8 @@ +# Telephony team +amitmahajan@google.com +shuoq@google.com +sasindran@google.com + +# VTS team +yuexima@google.com +yim@google.com
\ No newline at end of file diff --git a/radio/1.4/vts/functional/Android.bp b/radio/1.4/vts/functional/Android.bp new file mode 100644 index 0000000000..2d0e0898b7 --- /dev/null +++ b/radio/1.4/vts/functional/Android.bp @@ -0,0 +1,37 @@ +// +// 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. +// + +cc_test { + name: "VtsHalRadioV1_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "radio_hidl_hal_api.cpp", + "radio_hidl_hal_test.cpp", + "radio_response.cpp", + "radio_indication.cpp", + "VtsHalRadioV1_4TargetTest.cpp", + ], + static_libs: [ + "RadioVtsTestUtilBase", + "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", + ], + header_libs: ["radio.util.header@1.0"], + test_suites: ["general-tests"] +}
\ No newline at end of file diff --git a/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp b/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp new file mode 100644 index 0000000000..d6330e6ab3 --- /dev/null +++ b/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.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_4.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.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp new file mode 100644 index 0000000000..6b1f85e23d --- /dev/null +++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <radio_hidl_hal_utils_v1_4.h> + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
\ No newline at end of file diff --git a/radio/1.4/vts/functional/radio_hidl_hal_test.cpp b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp new file mode 100644 index 0000000000..4d80696c36 --- /dev/null +++ b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp @@ -0,0 +1,87 @@ +/* + * 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_4.h> + +void RadioHidlTest_v1_4::SetUp() { + radio_v1_4 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_4::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_4::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + if (radio_v1_4 == NULL) { + sleep(60); + radio_v1_4 = ::testing::VtsHalHidlTargetTestBase::getService< + ::android::hardware::radio::V1_4::IRadio>( + RadioHidlEnvironment::Instance() + ->getServiceName<::android::hardware::radio::V1_4::IRadio>( + hidl_string(RADIO_SERVICE_NAME))); + } + ASSERT_NE(nullptr, radio_v1_4.get()); + + radioRsp_v1_4 = new (std::nothrow) RadioResponse_v1_4(*this); + ASSERT_NE(nullptr, radioRsp_v1_4.get()); + + count_ = 0; + + radioInd_v1_4 = new (std::nothrow) RadioIndication_v1_4(*this); + ASSERT_NE(nullptr, radioInd_v1_4.get()); + + radio_v1_4->setResponseFunctions(radioRsp_v1_4, radioInd_v1_4); + + updateSimCardStatus(); + EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type); + EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial); + EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error); + + /* 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_4::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_4::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_4::updateSimCardStatus() { + serial = GetRandomSerialNumber(); + radio_v1_4->getIccCardStatus(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); +}
\ No newline at end of file diff --git a/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h new file mode 100644 index 0000000000..b77814f5a1 --- /dev/null +++ b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h @@ -0,0 +1,739 @@ +/* + * 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 <android-base/logging.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <chrono> +#include <condition_variable> +#include <mutex> + +#include <android/hardware/radio/1.4/IRadio.h> +#include <android/hardware/radio/1.4/IRadioIndication.h> +#include <android/hardware/radio/1.4/IRadioResponse.h> +#include <android/hardware/radio/1.4/types.h> + +#include "vts_test_util.h" + +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 RADIO_SERVICE_NAME "slot1" + +class RadioHidlTest_v1_4; +extern ::android::hardware::radio::V1_4::CardStatus cardStatus; + +/* Callback class for radio respons v1_4 */ +class RadioResponse_v1_4 : public ::android::hardware::radio::V1_4::IRadioResponse { + protected: + RadioHidlTest_v1_4& parent_v1_4; + + public: + hidl_vec<RadioBandMode> radioBandModes; + + RadioResponseInfo rspInfo; + + // Modem + bool isModemEnabled; + bool enableModemResponseToggle; + + // Data + ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp; + + RadioResponse_v1_4(RadioHidlTest_v1_4& parent_v1_4); + virtual ~RadioResponse_v1_4() = 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_4 : public ::android::hardware::radio::V1_4::IRadioIndication { + protected: + RadioHidlTest_v1_4& parent_v1_4; + + public: + RadioIndication_v1_4(RadioHidlTest_v1_4& parent_v1_4); + virtual ~RadioIndication_v1_4() = 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_4::IRadio>(); + } + + private: + RadioHidlEnvironment() {} +}; + +// The main test class for Radio HIDL. +class RadioHidlTest_v1_4 : public ::testing::VtsHalHidlTargetTestBase { + protected: + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + /* Serial number for radio request */ + int serial; + + /* 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_4::IRadio> radio_v1_4; + + /* radio response handle */ + sp<RadioResponse_v1_4> radioRsp_v1_4; + + /* radio indication handle */ + sp<RadioIndication_v1_4> radioInd_v1_4; +}; diff --git a/radio/1.4/vts/functional/radio_indication.cpp b/radio/1.4/vts/functional/radio_indication.cpp new file mode 100644 index 0000000000..c3722b0f7b --- /dev/null +++ b/radio/1.4/vts/functional/radio_indication.cpp @@ -0,0 +1,329 @@ +/* + * 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_4.h> + +RadioIndication_v1_4::RadioIndication_v1_4(RadioHidlTest_v1_4& parent) : parent_v1_4(parent) {} + +/* 1.4 Apis */ +Return<void> RadioIndication_v1_4::currentPhysicalChannelConfigs_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::networkScanResult_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cellInfoList_1_4( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::CellInfo>& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentEmergencyNumberList( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<EmergencyNumber>& /*emergencyNumberList*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::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_4::networkScanResult_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cellInfoList_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentLinkCapacityEstimate( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentPhysicalChannelConfigs( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentSignalStrength_1_2( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentSignalStrength_1_4(RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) { + return Void(); +} + +/* 1.1 Apis */ +Return<void> RadioIndication_v1_4::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::networkScanResult( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::keepaliveStatus(RadioIndicationType /*type*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +/* 1.0 Apis */ +Return<void> RadioIndication_v1_4::radioStateChanged(RadioIndicationType /*type*/, + RadioState /*radioState*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::callStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::networkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::newSms(RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::newSmsStatusReport( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::newSmsOnSim(RadioIndicationType /*type*/, + int32_t /*recordNumber*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/, + const ::android::hardware::hidl_string& /*msg*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::nitzTimeReceived( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/, + uint64_t /*receivedTime*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::currentSignalStrength( + RadioIndicationType /*type*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::dataCallListChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>& + /*dcList*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::suppSvcNotify(RadioIndicationType /*type*/, + const SuppSvcNotification& /*suppSvc*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::stkSessionEnd(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::stkProactiveCommand( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::stkEventNotify(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*cmd*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::simSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::simRefresh(RadioIndicationType /*type*/, + const SimRefreshResult& /*refreshResult*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::callRing(RadioIndicationType /*type*/, bool /*isGsm*/, + const CdmaSignalInfoRecord& /*record*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::simStatusChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaNewSms(RadioIndicationType /*type*/, + const CdmaSmsMessage& /*msg*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::newBroadcastSms( + RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::restrictedStateChanged(RadioIndicationType /*type*/, + PhoneRestrictedState /*state*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::enterEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaCallWaiting(RadioIndicationType /*type*/, + const CdmaCallWaiting& /*callWaitingRecord*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaOtaProvisionStatus(RadioIndicationType /*type*/, + CdmaOtaProvisionStatus /*status*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaInfoRec(RadioIndicationType /*type*/, + const CdmaInformationRecords& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::indicateRingbackTone(RadioIndicationType /*type*/, + bool /*start*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::resendIncallMute(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaSubscriptionSourceChanged( + RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cdmaPrlChanged(RadioIndicationType /*type*/, + int32_t /*version*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::exitEmergencyCallbackMode(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::rilConnected(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::voiceRadioTechChanged( + RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::cellInfoList( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*records*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::imsNetworkStateChanged(RadioIndicationType /*type*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::subscriptionStatusChanged(RadioIndicationType /*type*/, + bool /*activate*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::srvccStateNotify(RadioIndicationType /*type*/, + SrvccState /*state*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::hardwareConfigChanged( + RadioIndicationType /*type*/, + const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::radioCapabilityIndication( + RadioIndicationType /*type*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::onSupplementaryServiceIndication( + RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::stkCallControlAlphaNotify( + RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::lceData(RadioIndicationType /*type*/, + const LceDataInfo& /*lce*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::pcoData(RadioIndicationType /*type*/, + const PcoDataInfo& /*pco*/) { + return Void(); +} + +Return<void> RadioIndication_v1_4::modemReset(RadioIndicationType /*type*/, + const ::android::hardware::hidl_string& /*reason*/) { + return Void(); +} diff --git a/radio/1.4/vts/functional/radio_response.cpp b/radio/1.4/vts/functional/radio_response.cpp new file mode 100644 index 0000000000..10ecead2a0 --- /dev/null +++ b/radio/1.4/vts/functional/radio_response.cpp @@ -0,0 +1,874 @@ +/* + * 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_4.h> + +::android::hardware::radio::V1_4::CardStatus cardStatus; + +RadioResponse_v1_4::RadioResponse_v1_4(RadioHidlTest_v1_4& parent) : parent_v1_4(parent) {} + +/* 1.0 Apis */ +Return<void> RadioResponse_v1_4::getIccCardStatusResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::supplyNetworkDepersonalizationResponse( + const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCurrentCallsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::dialResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getIMSIForAppResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::hangupConnectionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::hangupWaitingOrBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::hangupForegroundResumeBackgroundResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::switchWaitingOrHoldingAndActiveResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::conferenceResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::rejectCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getLastCallFailCauseResponse( + const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getSignalStrengthResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getVoiceRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getDataRegistrationStateResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::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_4::setRadioPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setupDataCallResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::iccIOForAppResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/, + int32_t /*m*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setClirResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCallForwardStatusResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>& + /*callForwardInfos*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCallForwardResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCallWaitingResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/, int32_t /*serviceClass*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCallWaitingResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::acknowledgeLastIncomingGsmSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::acceptCallResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::deactivateDataCallResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*response*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/, + int32_t /*retry*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/, + bool /*manual*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setNetworkSelectionModeAutomaticResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setNetworkSelectionModeManualResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getAvailableNetworksResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::startDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::stopDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getBasebandVersionResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::separateConnectionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setMuteResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getMuteResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getClipResponse(const RadioResponseInfo& /*info*/, + ClipStatus /*status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getDataCallListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>& + /*dcResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendOemRilRequestRawResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendOemRilRequestStringsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setSuppServiceNotificationsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::writeSmsToSimResponse(const RadioResponseInfo& /*info*/, + int32_t /*index*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setBandModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getAvailableBandModesResponse( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) { + rspInfo = info; + radioBandModes = bandModes; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::sendEnvelopeResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_string& /*commandResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendTerminalResponseToSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::handleStkCallSetupRequestFromSimResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setPreferredNetworkTypeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/, + PreferredNetworkType /*nw_type*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getNeighboringCidsResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCdmaRoamingPreferenceResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/, + CdmaRoamingType /*type*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setTTYModeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getTTYModeResponse(const RadioResponseInfo& /*info*/, + TtyMode /*mode*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setPreferredVoicePrivacyResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/, + bool /*enable*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::acknowledgeLastIncomingCdmaSmsResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getGsmBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setGsmBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCdmaBroadcastConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCdmaBroadcastActivationResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::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_4::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/, + uint32_t /*index*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::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_4::exitEmergencyCallbackModeResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getSmscAddressResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setSmscAddressResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::reportStkServiceIsRunningResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCdmaSubscriptionSourceResponse( + const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::requestIsimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::acknowledgeIncomingGsmSmsWithPduResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/, + const IccIoResult& /*iccIo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getVoiceRadioTechnologyResponse( + const RadioResponseInfo& /*info*/, + ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCellInfoListResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setInitialAttachApnResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getImsRegistrationStateResponse( + const RadioResponseInfo& /*info*/, bool /*isRegistered*/, + RadioTechnologyFamily /*ratFamily*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendImsSmsResponse(const RadioResponseInfo& /*info*/, + const SendSmsResult& /*sms*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::iccTransmitApduBasicChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::iccOpenLogicalChannelResponse( + const RadioResponseInfo& /*info*/, int32_t /*channelId*/, + const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::iccTransmitApduLogicalChannelResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::nvReadItemResponse( + const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::nvWriteItemResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::nvResetConfigResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setDataAllowedResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getHardwareConfigResponse( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::requestIccSimAuthenticationResponse( + const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setDataProfileResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::requestShutdownResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getRadioCapabilityResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setRadioCapabilityResponse( + const RadioResponseInfo& /*info*/, + const android::hardware::radio::V1_0::RadioCapability& /*rc*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::startLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::stopLceServiceResponse(const RadioResponseInfo& /*info*/, + const LceStatusInfo& /*statusInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::pullLceDataResponse(const RadioResponseInfo& /*info*/, + const LceDataInfo& /*lceInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getModemActivityInfoResponse( + const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/, + int32_t /*numAllowed*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getAllowedCarriersResponse( + const RadioResponseInfo& /*info*/, bool /*allAllowed*/, + const CarrierRestrictions& /*carriers*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setIndicationFilterResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::acknowledgeRequest(int32_t /*serial*/) { + return Void(); +} + +/* 1.1 Apis */ +Return<void> RadioResponse_v1_4::setCarrierInfoForImsiEncryptionResponse( + const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::startNetworkScanResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::stopNetworkScanResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::startKeepaliveResponse(const RadioResponseInfo& /*info*/, + const KeepaliveStatus& /*status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) { + return Void(); +} + +/* 1.2 Apis */ +Return<void> RadioResponse_v1_4::setSignalStrengthReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::setLinkCapacityReportingCriteriaResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getIccCardStatusResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getCurrentCallsResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& /*calls*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getSignalStrengthResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getSignalStrengthResponse_1_4(const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getCellInfoListResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getVoiceRegistrationStateResponse_1_2( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getDataRegistrationStateResponse_1_2( + const RadioResponseInfo& /*info*/, + const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) { + return Void(); +} + +/* 1.3 Apis */ +Return<void> RadioResponse_v1_4::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::enableModemResponse(const RadioResponseInfo& info) { + rspInfo = info; + enableModemResponseToggle = !enableModemResponseToggle; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getModemStackStatusResponse(const RadioResponseInfo& info, + const bool enabled) { + rspInfo = info; + isModemEnabled = enabled; + parent_v1_4.notify(info.serial); + return Void(); +} + +/* 1.4 Apis */ +Return<void> RadioResponse_v1_4::emergencyDialResponse(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::startNetworkScanResponse_1_4(const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getDataRegistrationStateResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) { + rspInfo = info; + dataRegResp = dataRegResponse; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getCellInfoListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec< + ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getIccCardStatusResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::radio::V1_4::CardStatus& card_status) { + rspInfo = info; + cardStatus = card_status; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getPreferredNetworkTypeBitmapResponse( + const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield< + ::android::hardware::radio::V1_4::RadioAccessFamily> + /*networkTypeBitmap*/) { + rspInfo = info; + // TODO: may need a new member for bitfield networkTypeBitmap. + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::setPreferredNetworkTypeBitmapResponse( + const RadioResponseInfo& info) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::getDataCallListResponse_1_4( + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>& + /*dcResponse*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::setupDataCallResponse_1_4( + const RadioResponseInfo& info, + const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) { + rspInfo = info; + parent_v1_4.notify(info.serial); + return Void(); +} + +Return<void> RadioResponse_v1_4::setAllowedCarriersResponse_1_4(const RadioResponseInfo& /*info*/) { + return Void(); +} + +Return<void> RadioResponse_v1_4::getAllowedCarriersResponse_1_4( + const RadioResponseInfo& /*info*/, const CarrierRestrictionsWithPriority& /*carriers*/, + SimLockMultiSimPolicy /*multiSimPolicy*/) { + return Void(); +} diff --git a/secure_element/1.1/Android.bp b/secure_element/1.1/Android.bp new file mode 100644 index 0000000000..e16bc3d03f --- /dev/null +++ b/secure_element/1.1/Android.bp @@ -0,0 +1,19 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.secure_element@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ISecureElement.hal", + "ISecureElementHalCallback.hal", + ], + interfaces: [ + "android.hardware.secure_element@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/secure_element/1.1/ISecureElement.hal b/secure_element/1.1/ISecureElement.hal new file mode 100644 index 0000000000..2f68fc750c --- /dev/null +++ b/secure_element/1.1/ISecureElement.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.secure_element@1.1; + +import @1.1::ISecureElementHalCallback; +import @1.0::ISecureElement; + +interface ISecureElement extends @1.0::ISecureElement { + /** + * Initializes the Secure Element. This may include updating the applet + * and/or vendor-specific initialization. + * + * HAL service must send onStateChange() with connected equal to true + * after all the initialization has been successfully completed. + * Clients must wait for a onStateChange(true) before opening channels. + * + * @param clientCallback callback used to sent status of the SE back to the + * client + */ + init_1_1(ISecureElementHalCallback clientCallback); +}; diff --git a/secure_element/1.1/ISecureElementHalCallback.hal b/secure_element/1.1/ISecureElementHalCallback.hal new file mode 100644 index 0000000000..090db5f26f --- /dev/null +++ b/secure_element/1.1/ISecureElementHalCallback.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.secure_element@1.1; + +import @1.0::ISecureElementHalCallback; + +interface ISecureElementHalCallback extends @1.0::ISecureElementHalCallback { + /* + * Used to inform the client about changes in the state of the Secure + * Element. + * + * @param connected indicates the current state of the SE + * @param reason provides additional data why there was a change in state + * ex. initialization error, SE removed etc + * This is used only for debugging purpose to understand + * in-field issues. + */ + onStateChange_1_1(bool connected, string debugReason); +}; diff --git a/secure_element/1.1/vts/functional/Android.bp b/secure_element/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..51410bde15 --- /dev/null +++ b/secure_element/1.1/vts/functional/Android.bp @@ -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. +// + +cc_test { + name: "VtsHalSecureElementV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalSecureElementV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.secure_element@1.0", + "android.hardware.secure_element@1.1", + ], + test_suites: ["general-tests"], +} diff --git a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp new file mode 100644 index 0000000000..f8765ca834 --- /dev/null +++ b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp @@ -0,0 +1,116 @@ +/* + * 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 <string> + +#define LOG_TAG "secure_element_hidl_hal_test" +#include <android-base/logging.h> + +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <android/hardware/secure_element/1.1/ISecureElementHalCallback.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_1::ISecureElement; +using ::android::hardware::secure_element::V1_1::ISecureElementHalCallback; +using ::testing::VtsHalHidlTargetTestEnvBase; + +constexpr char kCallbackNameOnStateChange[] = "onStateChange"; + +class SecureElementCallbackArgs { + public: + bool state_; + hidl_string reason_; +}; + +class SecureElementHalCallback + : public ::testing::VtsHalHidlTargetCallbackBase<SecureElementCallbackArgs>, + public ISecureElementHalCallback { + public: + virtual ~SecureElementHalCallback() = default; + + Return<void> onStateChange_1_1(bool state, const hidl_string& reason) override { + SecureElementCallbackArgs args; + args.state_ = state; + args.reason_ = reason; + NotifyFromCallback(kCallbackNameOnStateChange, args); + return Void(); + }; + + Return<void> onStateChange(__attribute__((unused)) bool state) override { return Void(); } +}; + +class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static SecureElementHidlEnvironment* Instance() { + static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<ISecureElement>(); } + + private: + SecureElementHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment); +}; + +class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + std::string serviceName = + SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1"); + LOG(INFO) << "get service with name:" << serviceName; + ASSERT_FALSE(serviceName.empty()); + se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName); + ASSERT_NE(se_, nullptr); + + se_cb_ = new SecureElementHalCallback(); + ASSERT_NE(se_cb_, nullptr); + se_->init_1_1(se_cb_); + auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange); + EXPECT_TRUE(res.no_timeout); + EXPECT_TRUE(res.args->state_); + EXPECT_NE(res.args->reason_, ""); + } + + sp<ISecureElement> se_; + sp<SecureElementHalCallback> se_cb_; +}; + +/* + * isCardPresent: + * Expects the card to be present + */ +TEST_F(SecureElementHidlTest, isCardPresent) { + EXPECT_TRUE(se_->isCardPresent()); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + SecureElementHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + return status; +} diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp index db0b14881e..d83a9c36fe 100644 --- a/sensors/2.0/default/Android.bp +++ b/sensors/2.0/default/Android.bp @@ -35,4 +35,5 @@ cc_binary { "libpower", "libutils", ], + vintf_fragments: ["android.hardware.sensors@2.0.xml"], } diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp index 168b40219c..c09173f7ce 100644 --- a/sensors/2.0/default/Sensor.cpp +++ b/sensors/2.0/default/Sensor.cpp @@ -18,6 +18,8 @@ #include <utils/SystemClock.h> +#include <cmath> + namespace android { namespace hardware { namespace sensors { @@ -28,6 +30,8 @@ using ::android::hardware::sensors::V1_0::MetaDataEventType; 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) : mIsEnabled(false), mSamplingPeriodNs(0), @@ -83,7 +87,7 @@ Result Sensor::flush() { // to the Event FMQ prior to writing the flush complete event. Event ev; ev.sensorHandle = mSensorInfo.sensorHandle; - ev.sensorType = SensorType::ADDITIONAL_INFO; + ev.sensorType = SensorType::META_DATA; ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; std::vector<Event> evs{ev}; mCallback->postEvents(evs, isWakeUpSensor()); @@ -131,9 +135,9 @@ std::vector<Event> Sensor::readEvents() { event.sensorHandle = mSensorInfo.sensorHandle; event.sensorType = mSensorInfo.type; event.timestamp = ::android::elapsedRealtimeNano(); - event.u.vec3.x = 1; - event.u.vec3.y = 2; - event.u.vec3.z = 3; + 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; @@ -166,6 +170,31 @@ Result Sensor::injectEvent(const Event& event) { return result; } +OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback) + : Sensor(callback), mPreviousEventSet(false) {} + +void OnChangeSensor::activate(bool enable) { + Sensor::activate(enable); + if (!enable) { + mPreviousEventSet = false; + } +} + +std::vector<Event> OnChangeSensor::readEvents() { + std::vector<Event> events = Sensor::readEvents(); + std::vector<Event> outputEvents; + + for (auto iter = events.begin(); iter != events.end(); ++iter) { + Event ev = *iter; + if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) { + outputEvents.push_back(ev); + mPreviousEvent = ev; + mPreviousEventSet = true; + } + } + return outputEvents; +} + AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { mSensorInfo.sensorHandle = sensorHandle; mSensorInfo.name = "Accel Sensor"; @@ -177,14 +206,166 @@ AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) mSensorInfo.resolution = 1.52e-5; mSensorInfo.power = 0.001f; // mA mSensorInfo.minDelay = 20 * 1000; // microseconds - mSensorInfo.maxDelay = 1000 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION); +}; + +PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Pressure Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PRESSURE; + mSensorInfo.typeAsString = ""; + 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; + mSensorInfo.name = "Magnetic Field Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::MAGNETIC_FIELD; + mSensorInfo.typeAsString = ""; + 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; + mSensorInfo.name = "Light Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::LIGHT; + mSensorInfo.typeAsString = ""; + 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; + mSensorInfo.name = "Proximity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PROXIMITY; + mSensorInfo.typeAsString = ""; + 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::WAKE_UP | SensorFlagBits::DATA_INJECTION); + static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP); }; +GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Gyro Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::GYROSCOPE; + mSensorInfo.typeAsString = ""; + 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; +}; + +AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Ambient Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +}; + +DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Device Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +} + +RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, + ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Relative Humidity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::RELATIVE_HUMIDITY; + mSensorInfo.typeAsString = ""; + 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 } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h index 3ab2299a23..61900fa436 100644 --- a/sensors/2.0/default/Sensor.h +++ b/sensors/2.0/default/Sensor.h @@ -50,7 +50,7 @@ class Sensor { const SensorInfo& getSensorInfo() const; void batch(int32_t samplingPeriodNs); - void activate(bool enable); + virtual void activate(bool enable); Result flush(); void setOperationMode(OperationMode mode); @@ -79,11 +79,65 @@ class Sensor { OperationMode mMode; }; +class OnChangeSensor : public Sensor { + public: + OnChangeSensor(ISensorsEventCallback* callback); + + virtual void activate(bool enable) override; + + protected: + virtual std::vector<Event> readEvents() override; + + protected: + Event mPreviousEvent; + bool mPreviousEventSet; +}; + class AccelSensor : public Sensor { public: AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); }; +class GyroSensor : public Sensor { + public: + GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class AmbientTempSensor : public OnChangeSensor { + public: + 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); +}; + +class ProximitySensor : public OnChangeSensor { + public: + ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class RelativeHumiditySensor : public OnChangeSensor { + public: + RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp index 15fe86f788..23dd26bccb 100644 --- a/sensors/2.0/default/Sensors.cpp +++ b/sensors/2.0/default/Sensors.cpp @@ -37,13 +37,20 @@ constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; Sensors::Sensors() : mEventQueueFlag(nullptr), + mNextHandle(1), mOutstandingWakeUpEvents(0), mReadWakeLockQueueRun(false), mAutoReleaseWakeLockTime(0), mHasWakeLock(false) { - std::shared_ptr<AccelSensor> accel = - std::make_shared<AccelSensor>(1 /* sensorHandle */, this /* callback */); - mSensors[accel->getSensorInfo().sensorHandle] = accel; + AddSensor<AccelSensor>(); + AddSensor<GyroSensor>(); + AddSensor<AmbientTempSensor>(); + AddSensor<DeviceTempSensor>(); + AddSensor<PressureSensor>(); + AddSensor<MagnetometerSensor>(); + AddSensor<LightSensor>(); + AddSensor<ProximitySensor>(); + AddSensor<RelativeHumiditySensor>(); } Sensors::~Sensors() { diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h index eba3f97a08..d06dd78dad 100644 --- a/sensors/2.0/default/Sensors.h +++ b/sensors/2.0/default/Sensors.h @@ -87,6 +87,16 @@ struct Sensors : public ISensors, public ISensorsEventCallback { private: /** + * Add a new sensor + */ + template <class SensorType> + void AddSensor() { + std::shared_ptr<SensorType> sensor = + std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */); + mSensors[sensor->getSensorInfo().sensorHandle] = sensor; + } + + /** * Utility function to delete the Event Flag */ void deleteEventFlag(); @@ -132,6 +142,11 @@ struct Sensors : public ISensors, public ISensorsEventCallback { std::map<int32_t, std::shared_ptr<Sensor>> mSensors; /** + * The next available sensor handle + */ + int32_t mNextHandle; + + /** * Lock to protect writes to the FMQs */ std::mutex mWriteLock; diff --git a/sensors/2.0/default/android.hardware.sensors@2.0.xml b/sensors/2.0/default/android.hardware.sensors@2.0.xml new file mode 100644 index 0000000000..1acc8e6113 --- /dev/null +++ b/sensors/2.0/default/android.hardware.sensors@2.0.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.sensors</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>ISensors</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp index 4a1f8f111d..39053fe75f 100644 --- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp +++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp @@ -51,7 +51,7 @@ class EventCallback : public IEventCallback { } void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override { - if (event.sensorType == SensorType::ADDITIONAL_INFO && + if (event.sensorType == SensorType::META_DATA && event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) { std::unique_lock<std::recursive_mutex> lock(mFlushMutex); mFlushMap[event.sensorHandle]++; diff --git a/tv/cec/2.0/Android.bp b/tv/cec/2.0/Android.bp new file mode 100644 index 0000000000..998cb23ecb --- /dev/null +++ b/tv/cec/2.0/Android.bp @@ -0,0 +1,46 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.tv.cec@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IHdmiCec.hal", + "IHdmiCecCallback.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + types: [ + "AbortReason", + "CecAllDeviceTypeValue", + "CecDeviceFeature", + "CecDeviceInfo", + "CecDeviceType", + "CecLogicalAddress", + "CecMessage", + "CecMessageType", + "CecPowerState", + "CecRcProfile", + "CecRcProfile1", + "CecRcProfileId", + "CecRcProfileSource", + "CecTopologyEvent", + "CecTopologyEventType", + "CecUICommandCodes", + "CecVersion", + "HdmiPortInfo", + "HdmiPortType", + "HotplugEvent", + "MaxLength", + "OptionKey", + "Result", + "SendMessageResult", + ], + gen_java: true, +} + diff --git a/tv/cec/2.0/IHdmiCec.hal b/tv/cec/2.0/IHdmiCec.hal new file mode 100644 index 0000000000..0723bad8c6 --- /dev/null +++ b/tv/cec/2.0/IHdmiCec.hal @@ -0,0 +1,209 @@ +/* + * 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.cec@2.0; + +import IHdmiCecCallback; + +/** + * HDMI-CEC HAL interface definition. + */ +interface IHdmiCec { + /** + * Passes Primary Device Type that must be used in this system. + * + * HAL must use it to allocate logical address as specified in CEC section + * 11.3.2 of the CEC spec 2.0b. Then CEC commands addressed the given + * logical address can be filtered in. + * This method shall be able to be called up to twice to support two Primary + * Device Type as specified in CEC Table 11-8 of the CEC spec 2.0b. + * + * @param deviceType that must be used in this system. It must be a valid + * value in CecDeviceType for the call to succeed. + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_ARGS if the given device type is invalid, + * FAILURE_BUSY if device or resource is busy + */ + @callflow(next={"*"}) + addDeviceType(CecDeviceType deviceType) generates (Result result); + + /** + * Clears all Primary Device Types. + * + * It is used when the system plan to reconfigure Primary Device Type, + * hence to tell HAL to release all logical address associated to them, + * and change the state back to the beginning. + */ + @callflow(next="addDeviceType") + @exit + clearDeviceTypes(); + + /** + * Set All Device Types for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param allDeviceTypes device all device types for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes); + + /** + * Set Device Features for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param deviceType The device Primary Device Type. + * @param deviceFeatures device features for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures deviceFeatures); + + /** + * Set Remote Control Profile for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param deviceType The device Primary Device Type. + * @param rcProliles remote control profiles for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setRcProfile(CecDeviceType deviceType, CecRcProfile rcProfile); + + /** + * Retrieve CEC device information. + * + * CEC section 11.3 of the CEC spec 2.0b specify that a device should not + * ask for static information that another device has already supplied. + * Therefore, CEC 2.0 software stack need a map to store all cec + * devices’ information of current CEC network. + * The device information is broadcasted by a device after it allocates a + * logical address. Messages used to send out these information are + * REPORT_FEATURES, REPORT_PHYSICAL_ADDRESS, DEVICE_VENDOR_ID. + * The spec also requires less than 1 second between REPORT_FEATURES and + * REPORT_PHYSICAL_ADDRESS message, and less than 2 second between + * REPORT_PHYSICAL_ADDRESS and DEVICE_VENDOR_ID. An Implementation of + * device information map in hal can help to meet the timing constraints. + * Logical addressing is part of the process to build this map, so the + * implementation shall include allocating logical address too. + * Whenever a device plug/unplug, the topology of CEC network changes. + * The hal implementation shall update devices’ information map, and + * send out onTopologyEvent to Android system. Then Android system + * will use readDeviceInfo to retreive latest devices’ information of CEC + * network. + * If SYSTEM_CEC_CONTROL is false, the hal implementation need continue to + * maintain and update device information map, and send out pending + * onTopologyEvent to Android system when SYSTEM_CEC_CONTROL is + * changed to true. + * + * @param logicalAddress logical address of CEC device. + * @param physicalAddress physical address of CEC device. + * @return CecDeviceInfo from device information map. + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_ARGS if logical or physical address is invalid. + * FAILURE_INVALID_STATE if device information isn't available yet. + */ + @callflow(next="onTopologyChangeEvent") + readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress) + generates (Result result, CecDeviceInfo deviceInfo); + + /** + * Transmits HDMI-CEC message to other HDMI device. + * + * The method must be designed to return in a certain amount of time and not + * hanging forever. This method MUST complete with in 1 second. + * + * It must try retransmission at least once as specified in the section '7.1 + * Frame Re-transmissions' of the CEC Spec 1.4b. + * + * @param message CEC message to be sent to other HDMI device. + * @return result Result status of the operation. SUCCESS if successful, + * NACK if the sent message is not acknowledged, + * BUSY if the CEC bus is busy. + */ + @callflow(next="*") + sendMessage(CecMessage message) generates (SendMessageResult result); + + /** + * Set the callback + * + * It is used by the framework to receive CecMessages, HDMI hotplug event + * and topology update event. Only one callback client is supported. + * + * @param callback Callback object to pass hdmi events to the system. The + * previously registered callback must be replaced with this one. + */ + @callflow(next={"*"}) + @entry + setCallback(IHdmiCecCallback callback); + + /** + * Gets the hdmi port information of underlying hardware. + * + * @return infos The list of HDMI port information + */ + @callflow(next={"*"}) + getPortInfo() generates (vec<HdmiPortInfo> infos); + + /** + * Sets flags controlling the way HDMI-CEC service works down to HAL + * implementation. Those flags must be used in case the feature needs update + * in HAL itself, firmware or microcontroller. + * + * @param key The key of the option to be updated with a new value. + * @param value Value to be set. + */ + @callflow(next="*") + setOption(OptionKey key, bool value); + + /** + * Passes the updated language information of Android system. Contains + * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to + * respond to <Get Menu Language> while in standby mode. + * + * @param language Three-letter code defined in ISO/FDIS 639-2. Must be + * lowercase letters. (e.g., eng for English) + */ + @callflow(next="*") + setLanguage(string language); + + /** + * Configures ARC circuit in the hardware logic to start or stop the + * feature. + * + * @param portId Port id to be configured. + * @param enable Flag must be either true to start the feature or false to + * stop it. + */ + @callflow(next="*") + enableAudioReturnChannel(HdmiPortId portId, bool enable); + + /** + * Gets the connection status of the specified port. + * + * It's specified in CEC section 10.8 of the CEC spec 2.0b + * + * @param portId Port id to be inspected for the connection status. + * @return status True if a device is connected, otherwise false. + */ + @callflow(next="*") + isConnected(HdmiPortId portId) generates (bool connected); +}; diff --git a/tv/cec/2.0/IHdmiCecCallback.hal b/tv/cec/2.0/IHdmiCecCallback.hal new file mode 100644 index 0000000000..1a8a4895cd --- /dev/null +++ b/tv/cec/2.0/IHdmiCecCallback.hal @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.cec@2.0; + +interface IHdmiCecCallback { + /** + * The callback function that must be called by HAL implementation to notify + * the system of new CEC message arrival. + */ + oneway onCecMessage(CecMessage message); + + /** + * The callback function that must be called by HAL implementation to notify + * the system of new hotplug event. + */ + oneway onHotplugEvent(HotplugEvent event); + + /** + * The callback function must be called by HAL implementation to notify the + * system whenever CEC device information of CEC network change. + * HAL shall be ready for readDeviceInfo call before invoke this callback. + * This event is triggered by topology change of whole CEC network. It's + * different from HotplugEvent which is triggered between devices which are + * connected directly through HDMI cable. + */ + oneway onTopologyEvent(CecTopologyEvent event); +}; diff --git a/tv/cec/2.0/default/Android.bp b/tv/cec/2.0/default/Android.bp new file mode 100644 index 0000000000..6e624e3e7d --- /dev/null +++ b/tv/cec/2.0/default/Android.bp @@ -0,0 +1,42 @@ +cc_library_shared { + name: "android.hardware.tv.cec@2.0-impl", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: ["HdmiCec.cpp"], + + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libbase", + "libutils", + "libhardware", + "android.hardware.tv.cec@2.0", + ], + +} + +cc_binary { + name: "android.hardware.tv.cec@2.0-service", + vintf_fragments: ["android.hardware.tv.cec@2.0-service.xml"], + defaults: ["hidl_defaults"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.tv.cec@2.0-service.rc"], + srcs: ["service.cpp"], + + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware_legacy", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.tv.cec@2.0", + ], + +} diff --git a/tv/cec/2.0/default/HdmiCec.cpp b/tv/cec/2.0/default/HdmiCec.cpp new file mode 100644 index 0000000000..f45171955b --- /dev/null +++ b/tv/cec/2.0/default/HdmiCec.cpp @@ -0,0 +1,421 @@ +/* + * 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.cec@2.0-impl" +#include <android-base/logging.h> + +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> +#include "HdmiCec.h" + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V2_0 { +namespace implementation { + +static_assert(CEC_DEVICE_INACTIVE == static_cast<int>(CecDeviceType::INACTIVE), + "CecDeviceType::INACTIVE must match legacy value."); +static_assert(CEC_DEVICE_TV == static_cast<int>(CecDeviceType::TV), + "CecDeviceType::TV must match legacy value."); +static_assert(CEC_DEVICE_RECORDER == static_cast<int>(CecDeviceType::RECORDER), + "CecDeviceType::RECORDER must match legacy value."); +static_assert(CEC_DEVICE_TUNER == static_cast<int>(CecDeviceType::TUNER), + "CecDeviceType::TUNER must match legacy value."); +static_assert(CEC_DEVICE_PLAYBACK == static_cast<int>(CecDeviceType::PLAYBACK), + "CecDeviceType::PLAYBACK must match legacy value."); +static_assert(CEC_DEVICE_AUDIO_SYSTEM == static_cast<int>(CecDeviceType::AUDIO_SYSTEM), + "CecDeviceType::AUDIO_SYSTEM must match legacy value."); +/* TODO: Adjust for cec@2.0 +static_assert(CEC_DEVICE_MAX == static_cast<int>(CecDeviceType::MAX), + "CecDeviceType::MAX must match legacy value."); +*/ +static_assert(CEC_ADDR_TV == static_cast<int>(CecLogicalAddress::TV), + "CecLogicalAddress::TV must match legacy value."); +static_assert(CEC_ADDR_RECORDER_1 == static_cast<int>(CecLogicalAddress::RECORDER_1), + "CecLogicalAddress::RECORDER_1 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_2 == static_cast<int>(CecLogicalAddress::RECORDER_2), + "CecLogicalAddress::RECORDER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_1 == static_cast<int>(CecLogicalAddress::TUNER_1), + "CecLogicalAddress::TUNER_1 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_1 == static_cast<int>(CecLogicalAddress::PLAYBACK_1), + "CecLogicalAddress::PLAYBACK_1 must match legacy value."); +static_assert(CEC_ADDR_AUDIO_SYSTEM == static_cast<int>(CecLogicalAddress::AUDIO_SYSTEM), + "CecLogicalAddress::AUDIO_SYSTEM must match legacy value."); +static_assert(CEC_ADDR_TUNER_2 == static_cast<int>(CecLogicalAddress::TUNER_2), + "CecLogicalAddress::TUNER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_3 == static_cast<int>(CecLogicalAddress::TUNER_3), + "CecLogicalAddress::TUNER_3 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_2 == static_cast<int>(CecLogicalAddress::PLAYBACK_2), + "CecLogicalAddress::PLAYBACK_2 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_3 == static_cast<int>(CecLogicalAddress::RECORDER_3), + "CecLogicalAddress::RECORDER_3 must match legacy value."); +static_assert(CEC_ADDR_TUNER_4 == static_cast<int>(CecLogicalAddress::TUNER_4), + "CecLogicalAddress::TUNER_4 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_3 == static_cast<int>(CecLogicalAddress::PLAYBACK_3), + "CecLogicalAddress::PLAYBACK_3 must match legacy value."); +/* TODO: Adjust for cec@2.0 +static_assert(CEC_ADDR_FREE_USE == static_cast<int>(CecLogicalAddress::FREE_USE), + "CecLogicalAddress::FREE_USE must match legacy value."); +*/ +static_assert(CEC_ADDR_UNREGISTERED == static_cast<int>(CecLogicalAddress::UNREGISTERED), + "CecLogicalAddress::UNREGISTERED must match legacy value."); +static_assert(CEC_ADDR_BROADCAST == static_cast<int>(CecLogicalAddress::BROADCAST), + "CecLogicalAddress::BROADCAST must match legacy value."); + +static_assert(CEC_MESSAGE_FEATURE_ABORT == static_cast<int>(CecMessageType::FEATURE_ABORT), + "CecMessageType::FEATURE_ABORT must match legacy value."); +static_assert(CEC_MESSAGE_IMAGE_VIEW_ON == static_cast<int>(CecMessageType::IMAGE_VIEW_ON), + "CecMessageType::IMAGE_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_INCREMENT == + static_cast<int>(CecMessageType::TUNER_STEP_INCREMENT), + "CecMessageType::TUNER_STEP_INCREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_DECREMENT == + static_cast<int>(CecMessageType::TUNER_STEP_DECREMENT), + "CecMessageType::TUNER_STEP_DECREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_DEVICE_STATUS == + static_cast<int>(CecMessageType::TUNER_DEVICE_STATUS), + "CecMessageType::TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_TUNER_DEVICE_STATUS == + static_cast<int>(CecMessageType::GIVE_TUNER_DEVICE_STATUS), + "CecMessageType::GIVE_TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_ON == static_cast<int>(CecMessageType::RECORD_ON), + "CecMessageType::RECORD_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_STATUS == static_cast<int>(CecMessageType::RECORD_STATUS), + "CecMessageType::RECORD_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_OFF == static_cast<int>(CecMessageType::RECORD_OFF), + "CecMessageType::RECORD_OFF must match legacy value."); +static_assert(CEC_MESSAGE_TEXT_VIEW_ON == static_cast<int>(CecMessageType::TEXT_VIEW_ON), + "CecMessageType::TEXT_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_TV_SCREEN == static_cast<int>(CecMessageType::RECORD_TV_SCREEN), + "CecMessageType::RECORD_TV_SCREEN must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DECK_STATUS == static_cast<int>(CecMessageType::GIVE_DECK_STATUS), + "CecMessageType::GIVE_DECK_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_STANDBY == static_cast<int>(CecMessageType::STANDBY), + "CecMessageType::STANDBY must match legacy value."); +static_assert(CEC_MESSAGE_PLAY == static_cast<int>(CecMessageType::PLAY), + "CecMessageType::PLAY must match legacy value."); +static_assert(CEC_MESSAGE_DECK_CONTROL == static_cast<int>(CecMessageType::DECK_CONTROL), + "CecMessageType::DECK_CONTROL must match legacy value."); +static_assert(CEC_MESSAGE_TIMER_CLEARED_STATUS == + static_cast<int>(CecMessageType::TIMER_CLEARED_STATUS), + "CecMessageType::TIMER_CLEARED_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_PRESSED == + static_cast<int>(CecMessageType::USER_CONTROL_PRESSED), + "CecMessageType::USER_CONTROL_PRESSED must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_RELEASED == + static_cast<int>(CecMessageType::USER_CONTROL_RELEASED), + "CecMessageType::USER_CONTROL_RELEASED must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_OSD_NAME == static_cast<int>(CecMessageType::GIVE_OSD_NAME), + "CecMessageType::GIVE_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SET_OSD_NAME == static_cast<int>(CecMessageType::SET_OSD_NAME), + "CecMessageType::SET_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_REQUEST == + static_cast<int>(CecMessageType::SYSTEM_AUDIO_MODE_REQUEST), + "CecMessageType::SYSTEM_AUDIO_MODE_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_AUDIO_STATUS == static_cast<int>(CecMessageType::GIVE_AUDIO_STATUS), + "CecMessageType::GIVE_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SET_SYSTEM_AUDIO_MODE == + static_cast<int>(CecMessageType::SET_SYSTEM_AUDIO_MODE), + "CecMessageType::SET_SYSTEM_AUDIO_MODE must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_AUDIO_STATUS == + static_cast<int>(CecMessageType::REPORT_AUDIO_STATUS), + "CecMessageType::REPORT_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS == + static_cast<int>(CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_STATUS == + static_cast<int>(CecMessageType::SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_CHANGE == static_cast<int>(CecMessageType::ROUTING_CHANGE), + "CecMessageType::ROUTING_CHANGE must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_INFORMATION == + static_cast<int>(CecMessageType::ROUTING_INFORMATION), + "CecMessageType::ROUTING_INFORMATION must match legacy value."); +static_assert(CEC_MESSAGE_ACTIVE_SOURCE == static_cast<int>(CecMessageType::ACTIVE_SOURCE), + "CecMessageType::ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS == + static_cast<int>(CecMessageType::GIVE_PHYSICAL_ADDRESS), + "CecMessageType::GIVE_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS == + static_cast<int>(CecMessageType::REPORT_PHYSICAL_ADDRESS), + "CecMessageType::REPORT_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ACTIVE_SOURCE == + static_cast<int>(CecMessageType::REQUEST_ACTIVE_SOURCE), + "CecMessageType::REQUEST_ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_SET_STREAM_PATH == static_cast<int>(CecMessageType::SET_STREAM_PATH), + "CecMessageType::SET_STREAM_PATH must match legacy value."); +static_assert(CEC_MESSAGE_DEVICE_VENDOR_ID == static_cast<int>(CecMessageType::DEVICE_VENDOR_ID), + "CecMessageType::DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND == static_cast<int>(CecMessageType::VENDOR_COMMAND), + "CecMessageType::VENDOR_COMMAND must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_DOWN == + static_cast<int>(CecMessageType::VENDOR_REMOTE_BUTTON_DOWN), + "CecMessageType::VENDOR_REMOTE_BUTTON_DOWN must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_UP == + static_cast<int>(CecMessageType::VENDOR_REMOTE_BUTTON_UP), + "CecMessageType::VENDOR_REMOTE_BUTTON_UP must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID == + static_cast<int>(CecMessageType::GIVE_DEVICE_VENDOR_ID), + "CecMessageType::GIVE_DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_MENU_REQUEST == static_cast<int>(CecMessageType::MENU_REQUEST), + "CecMessageType::MENU_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_MENU_STATUS == static_cast<int>(CecMessageType::MENU_STATUS), + "CecMessageType::MENU_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS == + static_cast<int>(CecMessageType::GIVE_DEVICE_POWER_STATUS), + "CecMessageType::GIVE_DEVICE_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_POWER_STATUS == + static_cast<int>(CecMessageType::REPORT_POWER_STATUS), + "CecMessageType::REPORT_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GET_MENU_LANGUAGE == static_cast<int>(CecMessageType::GET_MENU_LANGUAGE), + "CecMessageType::GET_MENU_LANGUAGE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_ANALOG_SERVICE == + static_cast<int>(CecMessageType::SELECT_ANALOG_SERVICE), + "CecMessageType::SELECT_ANALOG_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_DIGITAL_SERVICE == + static_cast<int>(CecMessageType::SELECT_DIGITAL_SERVICE), + "CecMessageType::SELECT_DIGITAL_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SET_DIGITAL_TIMER == static_cast<int>(CecMessageType::SET_DIGITAL_TIMER), + "CecMessageType::SET_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_DIGITAL_TIMER == + static_cast<int>(CecMessageType::CLEAR_DIGITAL_TIMER), + "CecMessageType::CLEAR_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_AUDIO_RATE == static_cast<int>(CecMessageType::SET_AUDIO_RATE), + "CecMessageType::SET_AUDIO_RATE must match legacy value."); +static_assert(CEC_MESSAGE_INACTIVE_SOURCE == static_cast<int>(CecMessageType::INACTIVE_SOURCE), + "CecMessageType::INACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_CEC_VERSION == static_cast<int>(CecMessageType::CEC_VERSION), + "CecMessageType::CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_GET_CEC_VERSION == static_cast<int>(CecMessageType::GET_CEC_VERSION), + "CecMessageType::GET_CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND_WITH_ID == + static_cast<int>(CecMessageType::VENDOR_COMMAND_WITH_ID), + "CecMessageType::VENDOR_COMMAND_WITH_ID must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_EXTERNAL_TIMER == + static_cast<int>(CecMessageType::CLEAR_EXTERNAL_TIMER), + "CecMessageType::CLEAR_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_EXTERNAL_TIMER == + static_cast<int>(CecMessageType::SET_EXTERNAL_TIMER), + "CecMessageType::SET_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_INITIATE_ARC == static_cast<int>(CecMessageType::INITIATE_ARC), + "CecMessageType::INITIATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_INITIATED == + static_cast<int>(CecMessageType::REPORT_ARC_INITIATED), + "CecMessageType::REPORT_ARC_INITIATED must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_TERMINATED == + static_cast<int>(CecMessageType::REPORT_ARC_TERMINATED), + "CecMessageType::REPORT_ARC_TERMINATED must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_INITIATION == + static_cast<int>(CecMessageType::REQUEST_ARC_INITIATION), + "CecMessageType::REQUEST_ARC_INITIATION must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_TERMINATION == + static_cast<int>(CecMessageType::REQUEST_ARC_TERMINATION), + "CecMessageType::REQUEST_ARC_TERMINATION must match legacy value."); +static_assert(CEC_MESSAGE_TERMINATE_ARC == static_cast<int>(CecMessageType::TERMINATE_ARC), + "CecMessageType::TERMINATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_ABORT == static_cast<int>(CecMessageType::ABORT), + "CecMessageType::ABORT must match legacy value."); + +static_assert(ABORT_UNRECOGNIZED_MODE == static_cast<int>(AbortReason::UNRECOGNIZED_MODE), + "AbortReason::UNRECOGNIZED_MODE must match legacy value."); +static_assert(ABORT_NOT_IN_CORRECT_MODE == static_cast<int>(AbortReason::NOT_IN_CORRECT_MODE), + "AbortReason::NOT_IN_CORRECT_MODE must match legacy value."); +static_assert(ABORT_CANNOT_PROVIDE_SOURCE == static_cast<int>(AbortReason::CANNOT_PROVIDE_SOURCE), + "AbortReason::CANNOT_PROVIDE_SOURCE must match legacy value."); +static_assert(ABORT_INVALID_OPERAND == static_cast<int>(AbortReason::INVALID_OPERAND), + "AbortReason::INVALID_OPERAND must match legacy value."); +static_assert(ABORT_REFUSED == static_cast<int>(AbortReason::REFUSED), + "AbortReason::REFUSED must match legacy value."); +static_assert(ABORT_UNABLE_TO_DETERMINE == static_cast<int>(AbortReason::UNABLE_TO_DETERMINE), + "AbortReason::UNABLE_TO_DETERMINE must match legacy value."); + +static_assert(HDMI_RESULT_SUCCESS == static_cast<int>(SendMessageResult::SUCCESS), + "SendMessageResult::SUCCESS must match legacy value."); +static_assert(HDMI_RESULT_NACK == static_cast<int>(SendMessageResult::NACK), + "SendMessageResult::NACK must match legacy value."); +static_assert(HDMI_RESULT_BUSY == static_cast<int>(SendMessageResult::BUSY), + "SendMessageResult::BUSY must match legacy value."); +static_assert(HDMI_RESULT_FAIL == static_cast<int>(SendMessageResult::FAIL), + "SendMessageResult::FAIL must match legacy value."); + +static_assert(HDMI_INPUT == static_cast<int>(HdmiPortType::INPUT), + "HdmiPortType::INPUT must match legacy value."); +static_assert(HDMI_OUTPUT == static_cast<int>(HdmiPortType::OUTPUT), + "HdmiPortType::OUTPUT must match legacy value."); + +static_assert(HDMI_OPTION_WAKEUP == static_cast<int>(OptionKey::WAKEUP), + "OptionKey::WAKEUP must match legacy value."); +static_assert(HDMI_OPTION_ENABLE_CEC == static_cast<int>(OptionKey::ENABLE_CEC), + "OptionKey::ENABLE_CEC must match legacy value."); +static_assert(HDMI_OPTION_SYSTEM_CEC_CONTROL == static_cast<int>(OptionKey::SYSTEM_CEC_CONTROL), + "OptionKey::SYSTEM_CEC_CONTROL must match legacy value."); + +sp<IHdmiCecCallback> HdmiCec::mCallback = nullptr; + +HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) {} + +// Methods from ::android::hardware::tv::cec::V2_0::IHdmiCec follow. +Return<Result> HdmiCec::addDeviceType(CecDeviceType deviceType) { + // TODO implement + if (deviceType <= CecDeviceType::MAX) { + return Result::SUCCESS; + } else { + return Result::FAILURE_INVALID_ARGS; + } +} + +Return<void> HdmiCec::clearDeviceTypes() { + // TODO implement + return Void(); +} + +Return<void> HdmiCec::setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes) { + // TODO implement + if (allDeviceTypes == 1) { + } + return Void(); +} + +Return<void> HdmiCec::setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures /* deviceFeatures */) { + // TODO implement + if (deviceType != CecDeviceType::MAX) { + } + return Void(); +} + +Return<void> HdmiCec::setRcProfile(CecDeviceType deviceType, const CecRcProfile& /* rcProfile */) { + // TODO implement + if (deviceType != CecDeviceType::MAX) { + } + return Void(); +} + +Return<void> HdmiCec::readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress, + const readDeviceInfo_cb _hidl_cb) { + // TODO implement + CecDeviceInfo deviceInfo; + + if (logicalAddress == CecLogicalAddress::TV) { + _hidl_cb(Result::SUCCESS, deviceInfo); + if (physicalAddress) { + } + } + return Void(); +} + +Return<SendMessageResult> HdmiCec::sendMessage(const CecMessage& message) { + cec_message_t legacyMessage{ + .initiator = static_cast<cec_logical_address_t>(message.initiator), + .destination = static_cast<cec_logical_address_t>(message.destination), + .length = message.body.size(), + }; + for (size_t i = 0; i < message.body.size(); ++i) { + legacyMessage.body[i] = static_cast<unsigned char>(message.body[i]); + } + return static_cast<SendMessageResult>(mDevice->send_message(mDevice, &legacyMessage)); +} + +Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) { + if (mCallback != nullptr) { + mCallback->unlinkToDeath(this); + mCallback = nullptr; + } + + if (callback != nullptr) { + mCallback = callback; + mCallback->linkToDeath(this, 0 /*cookie*/); + mDevice->register_event_callback(mDevice, eventCallback, nullptr); + } + return Void(); +} + +Return<void> HdmiCec::getPortInfo(getPortInfo_cb _hidl_cb) { + struct hdmi_port_info* legacyPorts; + int numPorts; + hidl_vec<HdmiPortInfo> portInfos; + mDevice->get_port_info(mDevice, &legacyPorts, &numPorts); + portInfos.resize(numPorts); + for (int i = 0; i < numPorts; ++i) { + portInfos[i] = {.type = static_cast<HdmiPortType>(legacyPorts[i].type), + .portId = static_cast<HdmiPortId>(legacyPorts[i].port_id), + .cecSupported = legacyPorts[i].cec_supported != 0, + .arcSupported = legacyPorts[i].arc_supported != 0, + .physicalAddress = legacyPorts[i].physical_address}; + } + _hidl_cb(portInfos); + return Void(); +} + +Return<void> HdmiCec::setOption(OptionKey key, bool value) { + mDevice->set_option(mDevice, static_cast<int>(key), value ? 1 : 0); + return Void(); +} + +Return<void> HdmiCec::setLanguage(const hidl_string& language) { + if (language.size() != 3) { + LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size() + << "."; + return Void(); + } + const char* languageStr = language.c_str(); + int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) | + (languageStr[2] & 0xFF); + mDevice->set_option(mDevice, HDMI_OPTION_SET_LANG, convertedLanguage); + return Void(); +} + +Return<void> HdmiCec::enableAudioReturnChannel(HdmiPortId portId, bool enable) { + mDevice->set_audio_return_channel(mDevice, portId, enable ? 1 : 0); + return Void(); +} + +Return<bool> HdmiCec::isConnected(HdmiPortId portId) { + return mDevice->is_connected(mDevice, portId) > 0; +} + +IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) { + hdmi_cec_device_t* hdmi_cec_device; + int ret = 0; + const hw_module_t* hw_module = nullptr; + + ret = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0) { + ret = hdmi_cec_open(hw_module, &hdmi_cec_device); + if (ret != 0) { + LOG(ERROR) << "hdmi_cec_open " << hal << " failed: " << ret; + } + } else { + LOG(ERROR) << "hw_get_module " << hal << " failed: " << ret; + } + + if (ret == 0) { + return new HdmiCec(hdmi_cec_device); + } else { + LOG(ERROR) << "Passthrough failed to load legacy HAL."; + return nullptr; + } +} + +} // namespace implementation +} // namespace V2_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/cec/2.0/default/HdmiCec.h b/tv/cec/2.0/default/HdmiCec.h new file mode 100644 index 0000000000..ab5477089f --- /dev/null +++ b/tv/cec/2.0/default/HdmiCec.h @@ -0,0 +1,115 @@ +/* + * 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_CEC_V2_0_HDMICEC_H +#define ANDROID_HARDWARE_TV_CEC_V2_0_HDMICEC_H + +#include <algorithm> + +#include <android/hardware/tv/cec/2.0/IHdmiCec.h> +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::tv::cec::V2_0::CecLogicalAddress; +using ::android::hardware::tv::cec::V2_0::CecMessage; +using ::android::hardware::tv::cec::V2_0::CecPhysicalAddress; +using ::android::hardware::tv::cec::V2_0::HdmiPortId; +using ::android::hardware::tv::cec::V2_0::HdmiPortInfo; +using ::android::hardware::tv::cec::V2_0::IHdmiCec; +using ::android::hardware::tv::cec::V2_0::IHdmiCecCallback; +using ::android::hardware::tv::cec::V2_0::MaxLength; +using ::android::hardware::tv::cec::V2_0::OptionKey; +using ::android::hardware::tv::cec::V2_0::Result; +using ::android::hardware::tv::cec::V2_0::SendMessageResult; + +struct HdmiCec : public IHdmiCec, public hidl_death_recipient { + HdmiCec(hdmi_cec_device_t* device); + // Methods from ::android::hardware::tv::cec::V2_0::IHdmiCec follow. + Return<Result> addDeviceType(CecDeviceType deviceType) override; + Return<void> clearDeviceTypes() override; + Return<void> setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes) override; + Return<void> setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures /* deviceFeatures */) override; + Return<void> setRcProfile(CecDeviceType deviceType, + const CecRcProfile& /* rcProfile */) override; + Return<void> readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress, + const readDeviceInfo_cb _hidl_cb) override; + Return<SendMessageResult> sendMessage(const CecMessage& message) override; + Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override; + Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override; + Return<void> setOption(OptionKey key, bool value) override; + Return<void> setLanguage(const hidl_string& language) override; + Return<void> enableAudioReturnChannel(HdmiPortId portId, bool enable) override; + Return<bool> isConnected(HdmiPortId portId) override; + + static void eventCallback(const hdmi_event_t* event, void* /* arg */) { + if (mCallback != nullptr && event != nullptr) { + if (event->type == HDMI_EVENT_CEC_MESSAGE) { + size_t length = + std::min(event->cec.length, static_cast<size_t>(MaxLength::MESSAGE_BODY)); + CecMessage cecMessage{ + .initiator = static_cast<CecLogicalAddress>(event->cec.initiator), + .destination = static_cast<CecLogicalAddress>(event->cec.destination), + }; + cecMessage.body.resize(length); + for (size_t i = 0; i < length; ++i) { + cecMessage.body[i] = static_cast<uint8_t>(event->cec.body[i]); + } + mCallback->onCecMessage(cecMessage); + } else if (event->type == HDMI_EVENT_HOT_PLUG) { + HotplugEvent hotplugEvent{ + .connected = event->hotplug.connected > 0, + .portId = static_cast<HdmiPortId>(event->hotplug.port_id)}; + mCallback->onHotplugEvent(hotplugEvent); + } + } + } + + virtual void serviceDied(uint64_t /*cookie*/, + const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { + setCallback(nullptr); + } + + private: + static sp<IHdmiCecCallback> mCallback; + const hdmi_cec_device_t* mDevice; +}; + +extern "C" IHdmiCec* HIDL_FETCH_IHdmiCec(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_CEC_V2_0_HDMICEC_H diff --git a/tv/cec/2.0/default/OWNERS b/tv/cec/2.0/default/OWNERS new file mode 100644 index 0000000000..1b3d095f9c --- /dev/null +++ b/tv/cec/2.0/default/OWNERS @@ -0,0 +1,4 @@ +nchalko@google.com +amyjojo@google.com +shubang@google.com +quxiangfang@google.com diff --git a/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc new file mode 100644 index 0000000000..1e8cd8052c --- /dev/null +++ b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc @@ -0,0 +1,4 @@ +service vendor.cec-hal-2-0 /vendor/bin/hw/android.hardware.tv.cec@2.0-service + class hal + user system + group system diff --git a/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml new file mode 100644 index 0000000000..61fb1bbf9b --- /dev/null +++ b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.tv.cec</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IHdmiCec</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/tv/cec/2.0/default/service.cpp b/tv/cec/2.0/default/service.cpp new file mode 100644 index 0000000000..dacc38cc9d --- /dev/null +++ b/tv/cec/2.0/default/service.cpp @@ -0,0 +1,27 @@ +/* + * 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.cec@2.0-service" + +#include <android/hardware/tv/cec/2.0/IHdmiCec.h> +#include <hidl/LegacySupport.h> + +using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::tv::cec::V2_0::IHdmiCec; + +int main() { + return defaultPassthroughServiceImplementation<IHdmiCec>(); +} diff --git a/tv/cec/2.0/types.hal b/tv/cec/2.0/types.hal new file mode 100644 index 0000000000..cad6c396e9 --- /dev/null +++ b/tv/cec/2.0/types.hal @@ -0,0 +1,548 @@ +/* + * 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.cec@2.0; + +import android.hidl.safe_union@1.0; + +/** + * CEC device type as specified in CEC Table 11-7 of the CEC spec 2.0b. + */ +enum CecDeviceType : int32_t { + INACTIVE = -1, + TV = 0, + RECORDER = 1, + TUNER = 3, + PLAYBACK = 4, + AUDIO_SYSTEM = 5, + PURE_CEC_SWITCH = 6, + PROCESSOR = 7, + MAX = PROCESSOR, +}; + +/** + * CEC logical address as specified in CEC Table 11-9 of the CEC spec 2.0b. + */ +enum CecLogicalAddress : int32_t { + TV = 0, + RECORDER_1 = 1, + RECORDER_2 = 2, + TUNER_1 = 3, + PLAYBACK_1 = 4, + AUDIO_SYSTEM = 5, + TUNER_2 = 6, + TUNER_3 = 7, + PLAYBACK_2 = 8, + RECORDER_3 = 9, + TUNER_4 = 10, + PLAYBACK_3 = 11, + BACKUP_1 = 12, // backup1 for Playback/Recording/Tuner/Processor device + BACKUP_2 = 13, // backup2 for Playback/Recording/Tuner/Processor device + SPECIFIC_USE = 14, + UNREGISTERED = 15, // as Initiator address + BROADCAST = 15, // as Destination address +}; + +/** + * HDMI CEC message types. + * + * The assigned values represent opcode used in CEC frame as specified in + * Section 11.10 of the CEC spec 2.0b on top of Section CEC 15 of the CEC + * Spec 1.4b. + */ +enum CecMessageType : int32_t { + FEATURE_ABORT = 0x00, + IMAGE_VIEW_ON = 0x04, + TUNER_STEP_INCREMENT = 0x05, + TUNER_STEP_DECREMENT = 0x06, + TUNER_DEVICE_STATUS = 0x07, + GIVE_TUNER_DEVICE_STATUS = 0x08, + RECORD_ON = 0x09, + RECORD_STATUS = 0x0A, + RECORD_OFF = 0x0B, + TEXT_VIEW_ON = 0x0D, + RECORD_TV_SCREEN = 0x0F, + GIVE_DECK_STATUS = 0x1A, + DECK_STATUS = 0x1B, + SET_MENU_LANGUAGE = 0x32, + CLEAR_ANALOG_TIMER = 0x33, + SET_ANALOG_TIMER = 0x34, + TIMER_STATUS = 0x35, + STANDBY = 0x36, + PLAY = 0x41, + DECK_CONTROL = 0x42, + TIMER_CLEARED_STATUS = 0x43, + USER_CONTROL_PRESSED = 0x44, + USER_CONTROL_RELEASED = 0x45, + GIVE_OSD_NAME = 0x46, + SET_OSD_NAME = 0x47, + SET_OSD_STRING = 0x64, + SET_TIMER_PROGRAM_TITLE = 0x67, + SYSTEM_AUDIO_MODE_REQUEST = 0x70, + GIVE_AUDIO_STATUS = 0x71, + SET_SYSTEM_AUDIO_MODE = 0x72, + REPORT_AUDIO_STATUS = 0x7A, + GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D, + SYSTEM_AUDIO_MODE_STATUS = 0x7E, + ROUTING_CHANGE = 0x80, + ROUTING_INFORMATION = 0x81, + ACTIVE_SOURCE = 0x82, + GIVE_PHYSICAL_ADDRESS = 0x83, + REPORT_PHYSICAL_ADDRESS = 0x84, + REQUEST_ACTIVE_SOURCE = 0x85, + SET_STREAM_PATH = 0x86, + DEVICE_VENDOR_ID = 0x87, + VENDOR_COMMAND = 0x89, + VENDOR_REMOTE_BUTTON_DOWN = 0x8A, + VENDOR_REMOTE_BUTTON_UP = 0x8B, + GIVE_DEVICE_VENDOR_ID = 0x8C, + MENU_REQUEST = 0x8D, + MENU_STATUS = 0x8E, + GIVE_DEVICE_POWER_STATUS = 0x8F, + REPORT_POWER_STATUS = 0x90, + GET_MENU_LANGUAGE = 0x91, + SELECT_ANALOG_SERVICE = 0x92, + SELECT_DIGITAL_SERVICE = 0x93, + SET_DIGITAL_TIMER = 0x97, + CLEAR_DIGITAL_TIMER = 0x99, + SET_AUDIO_RATE = 0x9A, + INACTIVE_SOURCE = 0x9D, + CEC_VERSION = 0x9E, + GET_CEC_VERSION = 0x9F, + VENDOR_COMMAND_WITH_ID = 0xA0, + CLEAR_EXTERNAL_TIMER = 0xA1, + SET_EXTERNAL_TIMER = 0xA2, + REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3, + REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4, + GIVE_FEATURES = 0XA5, + REPORT_FEATURES = 0xA6, + REQUEST_CURRENT_LATENCY = 0xA7, + REPORT_CURRENT_LATENCY = 0xA8, + INITIATE_ARC = 0xC0, + REPORT_ARC_INITIATED = 0xC1, + REPORT_ARC_TERMINATED = 0xC2, + REQUEST_ARC_INITIATION = 0xC3, + REQUEST_ARC_TERMINATION = 0xC4, + TERMINATE_ARC = 0xC5, + ABORT = 0xFF, + POLLING_MESSAGE = 0xFFFFFF00, // used for cec polling message +}; + +/** + * Abort Reason as specified in CEC Table 29 of the CEC spec 1.4b. + */ +enum AbortReason : int32_t { + UNRECOGNIZED_MODE = 0, + NOT_IN_CORRECT_MODE = 1, + CANNOT_PROVIDE_SOURCE = 2, + INVALID_OPERAND = 3, + REFUSED = 4, + UNABLE_TO_DETERMINE = 5, +}; + +enum MaxLength : int32_t { + MESSAGE_BODY = 14, +}; + +struct CecMessage { + /** logical address of sender */ + CecLogicalAddress initiator; + + /** logical address of receiver */ + CecLogicalAddress destination; + + /** cec message type */ + CecMessageType cecMessageType; + + /** + * The maximum size of body is 14 (MaxLength::MESSAGE_BODY) as specified in + * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored. + */ + vec<uint8_t> body; +}; + +/** + * error code used for send_message. + */ +enum SendMessageResult : int32_t { + SUCCESS = 0, + NACK = 1, // not acknowledged + BUSY = 2, // bus is busy + FAIL = 3, +}; + +/** + * CEC All Device Type Value as specified in Table 11-30 of the CEC spec 2.0b. + */ +enum CecAllDeviceTypeValue : uint8_t { + RESERVED_DEVICE_2 = 1 << 0, + RESERVED_DEVICE_1 = 1 << 1, + CEC_SWITCH_DEVICE = 1 << 2, + AUDIO_DEVICE = 1 << 3, + PLAYBACK_DEVICE = 1 << 4, + TUNER_DEVICE = 1 << 5, + RECORDING_DEVICE = 1 << 6, + TV_DEVICE = 1 << 7, +}; + +/** + * CEC All Device Types + * + * It is a combination of all supported type from CecAllDeviceTypeValue. + * For example a record with tuner functionalitye, + * cecAllDeviceTypes = ((CecAllDeviceTypeValue::RECORDING_DEVICE) + * |(CecAllDeviceTypeValue::TUNER_DEVICE)) + */ +typedef bitfield<CecAllDeviceTypeValue> CecAllDeviceTypes; + +/** + * CEC Versions as specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecVersion : int32_t { + V_1_3_A = 0x04, + V_1_4 = 0x05, // indicate CEC 1.4, 1.4a or 1.4b + V_2_0 = 0x06, +}; + +/** + * Device Feature + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. As a uint32 there + * is room for future extensions aka DeviceFeature2 through DeviceFeature4. + */ +enum CecDeviceFeature : uint32_t { + RESERVED = 1 << 0, + SOURCE_SUPPORT_ARC_RX = 1 << 1, + SINK_SUPPORT_ARC_TX = 1 << 2, + SOURCE_SUPPORT_SET_AUDIO_RATE = 1 << 3, + SUPPORT_CONTROLLED_BY_DECK = 1 << 4, + TV_SUPPORT_SET_OSD_STRINGS = 1 << 5, + TV_SUPPORT_RECORD_TV_SCREEN = 1 << 6, +}; + +/** + * CEC Device Features + * + * It is a combination of all supported features from CecDeviceFeature. + * For example a TV with OSD and ARC capabilities, + * CecDeviceFeatures = ((CecDeviceFeature::TV_SUPPORT_SET_OSD_STRINGS) + * |(CecDeviceFeature::SINK_SUPPORT_ARC_TX)) + */ +typedef bitfield<CecDeviceFeature> CecDeviceFeatures; + +/** + * Remote Control Profile + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecRcProfileId : uint8_t { + NONE = 0, // TV doesn’t support any of these profiles + RC_PROFILE_1 = 0x02, // minimalistic zapper (low button count) + RC_PROFILE_2 = 0x06, // intermediate between profile 1 and profile 3 + RC_PROFILE_3 = 0x0A, // typical TV remote + RC_PROFILE_4 = 0x0E, // extended form of profile 3 +}; + +/** + * Remote Control Profile Source + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecRcProfileSource : uint8_t { + MEDIA_CONTEXT_SENSITIVE = 1 << 0, // source can handle UI command 0x11 + MEDIA_TO = 1 << 1, // source can handle UI command 0x10 + CONTENTS = 1 << 2, // source can handle UI command 0x0B + DEVICE_SETUP = 1 << 3, // source can handle UI command 0x0A + DEVICE_ROOT = 1 << 4, // source can handle UI command 0x09 + SOURCE_FLAG = 1 << 6, // Indicate the profile is for source +}; + +/** + * Remote Control Profile for either TV or Source. + */ +safe_union CecRcProfile1 { + /** CEC remote control profile for TV. */ + CecRcProfileId profileId; + + /* CEC remote control profile for source + * + * It is a combination of all supported profiles from CecRcProfileSource. + * For example a playback device support root menu and setup menu, + * profileSource = ((CecRcProfileSource::DEVICE_ROOT) + * |(CecRcProfileSource::DEVICE_SETUP) + * |(CecRcProfileSource::SOURCE_FLAG)) + */ + bitfield<CecRcProfileSource> profileSource; +}; + +/** + * CEC Remote Control Profiles + * + * CEC 2.0 only use one byte to represent Remote Control Profile. + */ +struct CecRcProfile { + CecRcProfile1 rcProfile1; +}; + +/** + * CEC device power states as specified in CEC Table 11-10 of the CEC spec 2.0b + */ +enum CecPowerState : int8_t { + ON = 0, + STANDBY = 1, + ON_TO_STANDBY = 2, + STANDBY_TO_ON = 4, + UNKNOWN = 0xFF, // some devices may not report power status +}; + +/** CEC physical address of device */ +typedef uint16_t CecPhysicalAddress; + +/** + * CEC device information + * + * It is initially built during addressing specified in CEC section 11.3 of + * the CEC spec 2.0b. It may be updated with cec devices's status changed. + */ +struct CecDeviceInfo { + /** CEC version which device supports */ + CecVersion version; + + /** CEC device primary type */ + CecDeviceType devceType; + + /** CEC all device types */ + CecAllDeviceTypes allDeviceTypes; + + /** CEC device features */ + CecDeviceFeatures deviceFeatures; + + /** CEC Device Remote Control Profile */ + CecRcProfile rcProfile; + + /** CEC Device Vendor ID */ + uint32_t vendorId; + + /** logical address of device */ + CecLogicalAddress logicalAddress; + + /** physical of device */ + CecPhysicalAddress physicalAddress; + + /** power status of device */ + CecPowerState powerState; +}; + +/** + * Topology Event Type. + */ +enum CecTopologyEventType : int32_t { + DEVICE_ADDED, + DEVICE_REMOVED, + DEVICE_UPDATED, +}; + +/** + * Topology Event. + */ +struct CecTopologyEvent { + CecTopologyEventType eventType; + CecLogicalAddress logicalAddress; + CecPhysicalAddress physicalAddress; + + /** true if the event is about the device which the system run on */ + bool isHostDevice; +}; + + +/** + * CEC UI Command Codes as specified in CEC Table 11-31 of the CEC spec 2.0b + */ +enum CecUICommandCodes : int32_t { + SELECT_OK = 0x00, + UP = 0x01, + DOWN = 0x02, + LEFT = 0x03, + RIGHT = 0x04, + RIGHT_UP = 0x05, + RIGHT_DOWN = 0x06, + LEFT_UP = 0x07, + LEFT_DOWN = 0x08, + DEVICE_ROOT_MENU = 0x09, + DEVICE_SETUP_MENU = 0x0A, + CONTENTS_MENU = 0x0B, + FAVORITE_MENU = 0x0C, + BACK = 0x0D, + MEDIA_TOP_MENU = 0x10, + MEDIA_CONTEXT_SENSITIVE_MENU = 0x11, + NUMBER_ENTRY_MODE = 0x1D, + NUMBER_11 = 0x1E, + NUMBER_12 = 0x1F, + NUMBER_0 = 0x20, // or NUMBER 10 + NUMBER_1 = 0x21, + NUMBER_2 = 0x22, + NUMBER_3 = 0x23, + NUMBER_4 = 0x24, + NUMBER_5 = 0x25, + NUMBER_6 = 0x26, + NUMBER_7 = 0x27, + NUMBER_8 = 0x28, + NUMBER_9 = 0x29, + DOT = 0x2A, + ENTER = 0x2B, + CLEAR = 0x2C, + NEXT_FAVORITE = 0x2F, + CHANNEL_UP = 0x30, + CHANNEL_DOWN = 0x31, + PREVIOUS_CHANNEL = 0x32, + SOUND_SELECT = 0x33, + INPUT_SELECT = 0x34, + DISPLAY_INFORMATION = 0x35, + HELP = 0x36, + PAGE_UP = 0x37, + PAGE_DOWN = 0x38, + POWER = 0x40, + VOLUME_UP = 0x41, + VOLUME_DOWN = 0x42, + MUTE = 0x43, + PLAY = 0x44, + STOP = 0x45, + PAUSE = 0x46, + RECORD = 0x47, + REWIND = 0x48, + FAST_FORWARD = 0x49, + EJECT = 0x4A, + SKIP_FORWARD = 0x4B, + SKIP_BACKWARD = 0x4C, + STOP_RECORD = 0x4D, + PAUSE_RECORD = 0x4E, + ANGLE = 0x50, + SUB_PICTURE = 0x51, + VIDEO_ON_DEMAND = 0x52, + ELECTRONIC_PROGRAM_GUIDE = 0x53, + TIMER_PROGRAMMING = 0x54, + INITIAL_CONFIGURATION = 0x55, + SELECT_BROADCAST_TYPE = 0x56, + SELECT_SOUND_PRESENTATION = 0x57, + AUDIO_DESCRIPTION = 0x58, + INTERNET = 0x59, + THREE_DIMENSIONAL_MODE = 0x5A, + PLAY_FUNCTION = 0x60, + PAUSE_PLAY_FUNCTION = 0x61, + RECORD_FUNCTION = 0x62, + PAUSE_RECORD_FUNCTION = 0x63, + STOP_FUNCTION = 0x64, + MUTE_FUNCTION = 0x65, + RESTORE_VOLUME_FUNCTION = 0x66, + TUNE_FUNCTION = 0x67, + SELECT_MEDIA_FUNCTION = 0x68, + SELECT_AV_INPUT_FUNCTION = 0x69, + SELECT_AUDIO_INPUT_FUNCTION = 0x6A, + POWER_TOGGLE_FUNCTION = 0x6B, + POWER_OFF_FUNCTION = 0x6C, + POWER_ON_FUNCTION = 0x6D, + F1 = 0x71, // BLUE + F2 = 0x72, // RED + F3 = 0x73, // GREEN + F4 = 0x74, // YELLOW + F5 = 0x75, + DATA = 0x76, +}; + +/** + * HDMI port type. + */ +enum HdmiPortType : int32_t { + INPUT = 0, + OUTPUT = 1, +}; + +/** + * Options used for IHdmiCec.setOption() + */ +enum OptionKey : int32_t { + /** + * When set to false, HAL does not wake up the system upon receiving <Image + * View On> or <Text View On>. Used when user changes the TV settings to + * disable the auto TV on functionality. + * Deprecated since <Image View On> and <Text View On> become mandatory + * featrues for CEC device. Use ENABLE_CEC OptionKey to disable CEC + * functionality instead. + * True by Default + */ + WAKEUP = 1, + + /** + * When set to false, all the CEC commands are discarded. if logical address + * is ever used, it shall be released. Used when user changes the TV + * settings to disable CEC functionality. + * True by default. + * + */ + ENABLE_CEC = 2, + + /** + * Setting this flag to false means Android system must stop handling CEC + * service and yield the control over to the microprocessor that is powered + * on through the standby mode.The microprocessor shall keep current logical + * and physical address. It shall response POLLING_MESSAGE, GIVE_FEATURES, + * GIVE_DEVICE_POWER_STATUS,GIVE_DEVICE_VENDOR_ID and GIVE_PHYSICAL_ADDRESS + * to allow other CEC devices to build CEC devices map specified in CEC + * section 11.3 of the CEC spec 2.0b. + * When set to true, the system must gain the control over, hence telling + * the microprocessor to start forwarding CEC messages to Android system. + * For example, this may be called when system goes in and out of + * standby mode to notify the microprocessor that it should start/stop + * handling CEC commands on behalf of the system. + * True by default. + */ + SYSTEM_CEC_CONTROL = 3, + + /* Option 4 not used */ +}; + +/** + * Hdmi port ID. + * + * It shall start from 1 which corresponds to HDMI "port 1". + */ +typedef uint32_t HdmiPortId; + +/** Hdmi hotplug event */ +struct HotplugEvent { + bool connected; + HdmiPortId portId; +}; + +/** + * HDMI port descriptor + */ +struct HdmiPortInfo { + HdmiPortType type; + HdmiPortId portId; + bool cecSupported; + bool arcSupported; + CecPhysicalAddress physicalAddress; +}; + +enum Result : int32_t { + SUCCESS = 0, + FAILURE_UNKNOWN = 1, + FAILURE_INVALID_ARGS = 2, + FAILURE_INVALID_STATE = 3, + FAILURE_NOT_SUPPORTED = 4, + FAILURE_BUSY = 5, +}; diff --git a/usb/1.2/Android.bp b/usb/1.2/Android.bp new file mode 100644 index 0000000000..55ffad06b1 --- /dev/null +++ b/usb/1.2/Android.bp @@ -0,0 +1,29 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.usb@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IUsb.hal", + "IUsbCallback.hal", + ], + interfaces: [ + "android.hardware.usb@1.0", + "android.hardware.usb@1.1", + "android.hidl.base@1.0", + ], + types: [ + "ContaminantDetectionStatus", + "ContaminantProtectionMode", + "ContaminantProtectionStatus", + "PortStatus", + "Status", + ], + gen_java: true, + gen_java_constants: true, +} + diff --git a/usb/1.2/IUsb.hal b/usb/1.2/IUsb.hal new file mode 100644 index 0000000000..ecc911ebf2 --- /dev/null +++ b/usb/1.2/IUsb.hal @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::IUsb; + +/** + * The setCallback function in V1_0 is used to register the V1_2 + * IUsbCallback object as well. The implementation can use the + * castFrom method to cast the IUsbCallback object. + */ +interface IUsb extends @1.1::IUsb { + /** + * When supportsEnableContaminantPresenceDetection is true, + * enableContaminantPresenceDetection enables/disables contaminant + * presence detection algorithm. Calling enableContaminantPresenceDetection + * when supportsEnableContaminantPresenceDetection is false does + * not have any effect. + * Change in contantaminant presence status should notify should + * be notified to the client via notifyPortStatusChange_1_2 through + * PortStatus. + * + * @param portName name of the port. + * @param enable true Enable contaminant presence detection algorithm. + * false Disable contaminant presence detection algorithm. + */ + oneway enableContaminantPresenceDetection(string portName, bool enable); + + /** + * When supportsEnableContaminantPresenceProtection is true, + * enableContaminantPresenceProtection enables/disables contaminant + * presence protection algorithm. Calling + * enableContaminantPresenceProtection + * when supportsEnableContaminantPresenceProtection is false does + * not have any effect. + * Used to enable/disable contaminant presence protection algorithm. + * Enabling port protection algoritm must make the lower layers to autonomously + * act on taking the corresponding preventive measure mentioned at + * ContaminantProtectionModes when contaminant is detected on the USB Port. + * Calling this method with enable set to true must set to contaminantProtectionEnabled + * to true upon success and vice versa. + * currentContaminantProtectionMode should be updated whenever there is a + * change in the status of contaminant presence protection algorithm. + * + * @param portName name of the port. + * @param enable true Reduce capabilities of the port to protect port + * from damage due to contaminant presence. + * false No action is taken upon contaminant presence. + */ + oneway enableContaminantPresenceProtection(string portName, bool enable); +}; diff --git a/usb/1.2/IUsbCallback.hal b/usb/1.2/IUsbCallback.hal new file mode 100644 index 0000000000..8cc16df10c --- /dev/null +++ b/usb/1.2/IUsbCallback.hal @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::IUsbCallback; +import android.hardware.usb@1.0::Status; + +/** + * Callback object used for all the IUsb async methods which expects a result. + * Caller is expected to register the callback object using setCallback method + * to receive updates on the PortStatus. + */ +interface IUsbCallback extends @1.1::IUsbCallback { + /** + * Used to convey the current port status to the caller. + * Must be called either when PortState changes due to the port partner or + * when caller requested for the PortStatus update through queryPortStatus. + * + * @param currentPortStatus vector object of current status(PortStatus + * of all the typeC ports in the device. + * @param retval SUCCESS when the required information was enquired form + * kernel and the PortStatus_1_2 object was built. + * ERROR otherwise. + */ + oneway notifyPortStatusChange_1_2(vec<PortStatus> currentPortStatus, + @1.0::Status retval); +}; + diff --git a/usb/1.2/types.hal b/usb/1.2/types.hal new file mode 100644 index 0000000000..081a64391b --- /dev/null +++ b/usb/1.2/types.hal @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::PortStatus_1_1; +import android.hardware.usb@1.0::Status; + +enum Status : @1.0::Status { + /** + * Error value returned when the operation is not supported. + */ + NOT_SUPPORTED = 4, +}; + +@export +enum ContaminantDetectionStatus : uint32_t { + /** + * Contaminant presence detection is not supported. + */ + NOT_SUPPORTED = 0, + + /** + * Contaminant presence detection is supported but disabled. + */ + DISABLED = 1, + + /** + * Contaminant presence detection is enabled and contaminant not detected. + */ + NOT_DETECTED = 2, + + /** + * Contaminant presence detection is enabled and contaminant detected. + */ + DETECTED = 3, +}; + +@export +enum ContaminantProtectionMode : uint32_t { + /** + * No action performed upon detection of contaminant presence. + */ + NONE = 0, + + /** + * Upon detection of contaminant presence, Port is forced to sink only + * mode where a port shall only detect chargers until contaminant presence + * is no longer detected. + */ + FORCE_SINK = 1 << 0, + + /** + * Upon detection of contaminant presence, Port is forced to source only + * mode where a port shall only detect usb accessories such as headsets + * until contaminant presence is no longer detected. + */ + FORCE_SOURCE = 1 << 1, + + /** + * Upon detection of contaminant presence, port is disabled until contaminant + * presence is no longer detected. In the disabled state port will + * not respond to connection of chargers or usb accessories. + */ + FORCE_DISABLE = 1 << 2, +}; + +@export +enum ContaminantProtectionStatus : ContaminantProtectionMode { + /** + * Client disabled cotaminant protection by calling + * enableContaminantPresencePortProtection set to false. Low level drivers should + * not autmomously take any corrective action when contaminant presence is detected. + */ + DISABLED = 1 << 3, +}; + +struct PortStatus { + PortStatus_1_1 status_1_1; + + /** + * Contaminant presence protection modes supported by the port. + */ + bitfield<ContaminantProtectionMode> supportedContaminantProtectionModes; + + /** + * Client can enable/disable contaminant presence protection through + * enableContaminantPresenceProtection when true. + */ + bool supportsEnableContaminantPresenceProtection; + + /** + * Contaminant presence protection modes currently active for the port. + */ + ContaminantProtectionStatus contaminantProtectionStatus; + + /** + * Client can enable/disable contaminant presence detection through + * enableContaminantPresenceDetection when true. + */ + bool supportsEnableContaminantPresenceDetection; + + /** + * Current status of contaminant detection algorithm. + */ + ContaminantDetectionStatus contaminantDetectionStatus; +}; diff --git a/usb/1.2/vts/OWNERS b/usb/1.2/vts/OWNERS new file mode 100644 index 0000000000..f60d39a3b4 --- /dev/null +++ b/usb/1.2/vts/OWNERS @@ -0,0 +1,2 @@ +badhri@google.com +yim@google.com diff --git a/usb/1.2/vts/functional/Android.bp b/usb/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..761d37f184 --- /dev/null +++ b/usb/1.2/vts/functional/Android.bp @@ -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. +// + +cc_test { + name: "VtsHalUsbV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalUsbV1_2TargetTest.cpp"], + static_libs: [ + "android.hardware.usb@1.0", + "android.hardware.usb@1.1", + "android.hardware.usb@1.2", + ], + test_suites: ["general-tests"], +} + diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp new file mode 100644 index 0000000000..7b3dea938e --- /dev/null +++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp @@ -0,0 +1,380 @@ +/* + * 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 "VtsHalUsbV1_2TargetTest" +#include <android-base/logging.h> + +#include <android/hardware/usb/1.2/IUsb.h> +#include <android/hardware/usb/1.2/IUsbCallback.h> +#include <android/hardware/usb/1.2/types.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <log/log.h> +#include <stdlib.h> +#include <chrono> +#include <condition_variable> +#include <mutex> + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::usb::V1_0::PortDataRole; +using ::android::hardware::usb::V1_0::PortMode; +using ::android::hardware::usb::V1_0::PortPowerRole; +using ::android::hardware::usb::V1_0::PortRole; +using ::android::hardware::usb::V1_0::PortRoleType; +using ::android::hardware::usb::V1_0::Status; +using ::android::hardware::usb::V1_1::PortMode_1_1; +using ::android::hardware::usb::V1_1::PortStatus_1_1; +using ::android::hardware::usb::V1_2::ContaminantDetectionStatus; +using ::android::hardware::usb::V1_2::ContaminantProtectionMode; +using ::android::hardware::usb::V1_2::ContaminantProtectionStatus; +using ::android::hardware::usb::V1_2::IUsb; +using ::android::hardware::usb::V1_2::IUsbCallback; +using ::android::hardware::usb::V1_2::PortStatus; +using ::android::hidl::base::V1_0::IBase; + +constexpr char kCallbackNameNotifyPortStatusChange_1_2[] = "notifyPortStatusChange_1_2"; +const int kCallbackIdentifier = 2; + +// Worst case wait time 20secs +#define WAIT_FOR_TIMEOUT std::chrono::milliseconds(20000) + +class UsbClientCallbackArgs { + public: + // The last conveyed status of the USB ports. + // Stores information of currentt_data_role, power_role for all the USB ports + PortStatus usb_last_port_status; + + // Status of the last role switch operation. + Status usb_last_status; + + // Identifier for the usb callback object. + // Stores the cookie of the last invoked usb callback object. + int last_usb_cookie; +}; + +// Callback class for the USB HIDL hal. +// Usb Hal will call this object upon role switch or port query. +class UsbCallback : public ::testing::VtsHalHidlTargetCallbackBase<UsbClientCallbackArgs>, + public IUsbCallback { + int cookie; + + public: + UsbCallback(int cookie) : cookie(cookie){}; + + virtual ~UsbCallback() = default; + + // V1_0 Callback method for the port status. + // This should not be called so not signalling the Test here assuming that + // the test thread will timeout + Return<void> notifyPortStatusChange(const hidl_vec<android::hardware::usb::V1_0::PortStatus>& + /* currentPortStatus */, + Status /* retval */) override { + return Void(); + }; + + // V1_1 Callback method for the port status. + // This should not be called so not signalling the Test here assuming that + // the test thread will timeout + Return<void> notifyPortStatusChange_1_1(const hidl_vec<PortStatus_1_1>& /* currentPortStatus */, + Status /* retval */) override { + return Void(); + } + + // This callback method should be used. + Return<void> notifyPortStatusChange_1_2(const hidl_vec<PortStatus>& currentPortStatus, + Status retval) override { + UsbClientCallbackArgs arg; + if (retval == Status::SUCCESS) { + arg.usb_last_port_status.status_1_1.status.supportedModes = + currentPortStatus[0].status_1_1.status.supportedModes; + arg.usb_last_port_status.status_1_1.status.currentMode = + currentPortStatus[0].status_1_1.status.currentMode; + arg.usb_last_port_status.status_1_1.status.portName = + currentPortStatus[0].status_1_1.status.portName; + arg.usb_last_port_status.contaminantDetectionStatus = + currentPortStatus[0].contaminantDetectionStatus; + arg.usb_last_port_status.contaminantProtectionStatus = + currentPortStatus[0].contaminantProtectionStatus; + arg.usb_last_port_status.supportsEnableContaminantPresenceProtection = + currentPortStatus[0].supportsEnableContaminantPresenceProtection; + arg.usb_last_port_status.supportsEnableContaminantPresenceDetection = + currentPortStatus[0].supportsEnableContaminantPresenceDetection; + arg.usb_last_port_status.supportedContaminantProtectionModes = + currentPortStatus[0].supportedContaminantProtectionModes; + } + arg.usb_last_status = retval; + arg.last_usb_cookie = cookie; + + NotifyFromCallback(kCallbackNameNotifyPortStatusChange_1_2, arg); + return Void(); + } + + // Callback method for the status of role switch operation. + // RoleSwitch operation has not changed since V1_0 so leaving + // the callback blank here. + Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/, + const PortRole& /*newRole*/, Status /*retval*/) override { + return Void(); + }; +}; + +// Test environment for Usb HIDL HAL. +class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static UsbHidlEnvironment* Instance() { + static UsbHidlEnvironment* instance = new UsbHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IUsb>(); } +}; + +// The main test class for the USB hidl HAL +class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + ALOGI(__FUNCTION__); + usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(); + ASSERT_NE(usb, nullptr); + + usb_cb_2 = new UsbCallback(kCallbackIdentifier); + ASSERT_NE(usb_cb_2, nullptr); + usb_cb_2->SetWaitTimeout(kCallbackNameNotifyPortStatusChange_1_2, WAIT_FOR_TIMEOUT); + Return<void> ret = usb->setCallback(usb_cb_2); + ASSERT_TRUE(ret.isOk()); + } + + virtual void TearDown() override { ALOGI("Teardown"); } + + // USB hidl hal Proxy + sp<IUsb> usb; + + // Callback objects for usb hidl + // Methods of these objects are called to notify port status updates. + sp<UsbCallback> usb_cb_1; + sp<UsbCallback> usb_cb_2; +}; + +/* + * Test to see if setCallback on V1_1 callback object succeeds. + * Callback oject is created and registered. + * Check to see if the hidl transaction succeeded. + */ +TEST_F(UsbHidlTest, setCallback) { + usb_cb_1 = new UsbCallback(1); + ASSERT_NE(usb_cb_1, nullptr); + Return<void> ret = usb->setCallback(usb_cb_1); + ASSERT_TRUE(ret.isOk()); +} + +/* + * Check to see if querying type-c + * port status succeeds. + * HAL service should call notifyPortStatusChange_1_2 + * instead of notifyPortStatusChange of V1_0/V1_1 interface + */ +TEST_F(UsbHidlTest, queryPortStatus) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); +} + +/* + * supportedContaminantProtectionModes is immutable. + * Check if supportedContaminantProtectionModes changes across queryPortStatus + * call. + */ +TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + uint32_t supportedContaminantProtectionModes = static_cast<uint32_t>( + res.args->usb_last_port_status.supportedContaminantProtectionModes); + for (int runs = 1; runs <= 10; runs++) { + ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + EXPECT_EQ(supportedContaminantProtectionModes, + static_cast<uint32_t>( + res.args->usb_last_port_status.supportedContaminantProtectionModes)); + } +} + +/* + * When supportsEnableContaminantPresenceDetection is set false, + * enableContaminantPresenceDetection should not enable/disable + * contaminantPresenceProtection. + */ +TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) { + for (int runs = 1; runs <= 10; runs++) { + bool currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceDetection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED)); + } + } +} + +/* + * enableContaminantPresenceDetection should succeed atleast 90% when supported. + */ +TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) { + int successCount = 0; + bool currentStatus; + bool supported = true; + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) return; + + for (int count = 1; count <= 10; count++) { + currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceDetection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + if (!currentStatus == !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED)) + successCount++; + } + + if (!supported) EXPECT_GE(successCount, 9); +} + +/* + * When supportsEnableContaminantPresenceProtection is set false, + * enableContaminantPresenceProtection should not enable/disable + * contaminantPresenceProtection. + */ +TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) { + for (int runs = 1; runs <= 10; runs++) { + bool currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceProtection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED)); + } + } +} + +/* + * enableContaminantPresenceProtection should succeed atleast 90% when supported. + */ +TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) { + int successCount = 0; + bool currentStatus; + bool supported = true; + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) return; + + for (int count = 1; count <= 10; count++) { + currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceProtection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + if (!currentStatus == !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED)) + successCount++; + } + + if (!supported) EXPECT_GE(successCount, 9); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + UsbHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.3/example/Android.bp new file mode 100644 index 0000000000..36f2ff82c2 --- /dev/null +++ b/vibrator/1.3/example/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_binary { + name: "android.hardware.vibrator@1.3-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"], + srcs: ["service.cpp", "Vibrator.cpp"], + cflags: ["-Wall", "-Werror"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", + ], +} diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.3/example/Vibrator.cpp new file mode 100644 index 0000000000..bb9a057697 --- /dev/null +++ b/vibrator/1.3/example/Vibrator.cpp @@ -0,0 +1,242 @@ +/* + * 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 "VibratorService" + +#include <log/log.h> + +#include "Vibrator.h" + +namespace android { +namespace hardware { +namespace vibrator { +namespace V1_3 { +namespace implementation { + +static constexpr uint32_t MS_PER_S = 1000; +static constexpr uint32_t NS_PER_MS = 1000000; + +Vibrator::Vibrator() { + sigevent se{}; + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = this; + se.sigev_notify_function = timerCallback; + se.sigev_notify_attributes = nullptr; + + if (timer_create(CLOCK_REALTIME, &se, &mTimer) < 0) { + ALOGE("Can not create timer!%s", strerror(errno)); + } +} + +// Methods from ::android::hardware::vibrator::V1_0::IVibrator follow. + +Return<Status> Vibrator::on(uint32_t timeoutMs) { + return activate(timeoutMs); +} + +Return<Status> Vibrator::off() { + return activate(0); +} + +Return<bool> Vibrator::supportsAmplitudeControl() { + return true; +} + +Return<Status> Vibrator::setAmplitude(uint8_t amplitude) { + ALOGI("Amplitude: %u -> %u\n", mAmplitude, amplitude); + mAmplitude = amplitude; + return Status::OK; +} + +Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) { + return perform_1_1(static_cast<V1_1::Effect_1_1>(effect), strength, _hidl_cb); +} + +// Methods from ::android::hardware::vibrator::V1_1::IVibrator follow. + +Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength, + perform_cb _hidl_cb) { + return perform_1_2(static_cast<V1_2::Effect>(effect), strength, _hidl_cb); +} + +// Methods from ::android::hardware::vibrator::V1_2::IVibrator follow. + +Return<void> Vibrator::perform_1_2(Effect effect, EffectStrength strength, perform_cb _hidl_cb) { + uint8_t amplitude; + uint32_t ms; + Status status; + + ALOGI("Perform: Effect %s\n", effectToName(effect)); + + amplitude = strengthToAmplitude(strength); + setAmplitude(amplitude); + + ms = effectToMs(effect); + status = activate(ms); + + _hidl_cb(status, ms); + + return Void(); +} + +// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow. + +Return<bool> Vibrator::supportsExternalControl() { + return true; +} + +Return<Status> Vibrator::setExternalControl(bool enabled) { + if (mEnabled) { + ALOGW("Setting external control while the vibrator is enabled is unsupported!"); + return Status::UNSUPPORTED_OPERATION; + } else { + ALOGI("ExternalControl: %s -> %s\n", mExternalControl ? "true" : "false", + enabled ? "true" : "false"); + mExternalControl = enabled; + return Status::OK; + } +} + +// Private methods follow. + +Status Vibrator::enable(bool enabled) { + if (mExternalControl) { + ALOGW("Enabling/disabling while the vibrator is externally controlled is unsupported!"); + return Status::UNSUPPORTED_OPERATION; + } else { + ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false"); + mEnabled = enabled; + return Status::OK; + } +} + +Status Vibrator::activate(uint32_t ms) { + std::lock_guard<std::mutex> lock{mMutex}; + Status status = Status::OK; + + if (ms > 0) { + status = enable(true); + if (status != Status::OK) { + return status; + } + } + + itimerspec ts{}; + ts.it_value.tv_sec = ms / MS_PER_S; + ts.it_value.tv_nsec = ms % MS_PER_S * NS_PER_MS; + + if (timer_settime(mTimer, 0, &ts, nullptr) < 0) { + ALOGE("Can not set timer!"); + status = Status::UNKNOWN_ERROR; + } + + if ((status != Status::OK) || !ms) { + Status _status; + + _status = enable(false); + + if (status == Status::OK) { + status = _status; + } + } + + return status; +} + +void Vibrator::timeout() { + std::lock_guard<std::mutex> lock{mMutex}; + itimerspec ts{}; + + if (timer_gettime(mTimer, &ts) < 0) { + ALOGE("Can not read timer!"); + } + + if (ts.it_value.tv_sec == 0 && ts.it_value.tv_nsec == 0) { + enable(false); + } +} + +void Vibrator::timerCallback(union sigval sigval) { + static_cast<Vibrator*>(sigval.sival_ptr)->timeout(); +} + +const char* Vibrator::effectToName(Effect effect) { + return toString(effect).c_str(); +} + +uint32_t Vibrator::effectToMs(Effect effect) { + switch (effect) { + case Effect::CLICK: + return 10; + case Effect::DOUBLE_CLICK: + return 15; + case Effect::TICK: + return 5; + case Effect::THUD: + return 5; + case Effect::POP: + return 5; + case Effect::HEAVY_CLICK: + return 10; + case Effect::RINGTONE_1: + return 30000; + case Effect::RINGTONE_2: + return 30000; + case Effect::RINGTONE_3: + return 30000; + case Effect::RINGTONE_4: + return 30000; + case Effect::RINGTONE_5: + return 30000; + case Effect::RINGTONE_6: + return 30000; + case Effect::RINGTONE_7: + return 30000; + case Effect::RINGTONE_8: + return 30000; + case Effect::RINGTONE_9: + return 30000; + case Effect::RINGTONE_10: + return 30000; + case Effect::RINGTONE_11: + return 30000; + case Effect::RINGTONE_12: + return 30000; + case Effect::RINGTONE_13: + return 30000; + case Effect::RINGTONE_14: + return 30000; + case Effect::RINGTONE_15: + return 30000; + } +} + +uint8_t Vibrator::strengthToAmplitude(EffectStrength strength) { + switch (strength) { + case EffectStrength::LIGHT: + return 128; + case EffectStrength::MEDIUM: + return 192; + case EffectStrength::STRONG: + return 255; + } +} + +} // namespace implementation +} // namespace V1_3 +} // namespace vibrator +} // namespace hardware +} // namespace android diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.3/example/Vibrator.h new file mode 100644 index 0000000000..a931b63b09 --- /dev/null +++ b/vibrator/1.3/example/Vibrator.h @@ -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. + */ +#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H +#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H + +#include <android/hardware/vibrator/1.3/IVibrator.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace vibrator { +namespace V1_3 { +namespace implementation { + +using android::hardware::vibrator::V1_0::EffectStrength; +using android::hardware::vibrator::V1_0::Status; +using android::hardware::vibrator::V1_2::Effect; + +class Vibrator : public IVibrator { + public: + Vibrator(); + + // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow. + Return<Status> on(uint32_t timeoutMs) override; + Return<Status> off() override; + Return<bool> supportsAmplitudeControl() override; + Return<Status> setAmplitude(uint8_t amplitude) override; + Return<void> perform(V1_0::Effect effect, EffectStrength strength, + perform_cb _hidl_cb) override; + + // Methods from ::android::hardware::vibrator::V1_1::IVibrator follow. + Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength, + perform_cb _hidl_cb) override; + + // Methods from ::android::hardware::vibrator::V1_2::IVibrator follow. + Return<void> perform_1_2(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override; + + // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow. + Return<bool> supportsExternalControl() override; + Return<Status> setExternalControl(bool enabled) override; + + private: + Status enable(bool enabled); + Status activate(uint32_t ms); + void timeout(); + + static void timerCallback(union sigval sigval); + static const char* effectToName(Effect effect); + static uint32_t effectToMs(Effect effect); + static uint8_t strengthToAmplitude(EffectStrength strength); + + private: + bool mEnabled{false}; + uint8_t mAmplitude{UINT8_MAX}; + bool mExternalControl{false}; + std::mutex mMutex; + timer_t mTimer{nullptr}; +}; +} // namespace implementation +} // namespace V1_3 +} // namespace vibrator +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H 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 new file mode 100644 index 0000000000..ed7a562cfc --- /dev/null +++ b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc @@ -0,0 +1,4 @@ +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/example/android.hardware.vibrator@1.3-service.example.xml b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml new file mode 100644 index 0000000000..172aa2178c --- /dev/null +++ b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.vibrator</name> + <transport>hwbinder</transport> + <version>1.3</version> + <interface> + <name>IVibrator</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/vibrator/1.3/example/service.cpp b/vibrator/1.3/example/service.cpp new file mode 100644 index 0000000000..449996e280 --- /dev/null +++ b/vibrator/1.3/example/service.cpp @@ -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. + */ +#define LOG_TAG "android.hardware.vibrator@1.3-service.example" + +#include <android/hardware/vibrator/1.3/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 namespace android; + +status_t registerVibratorService() { + sp<IVibrator> vibrator = new Vibrator(); + + return vibrator->registerAsService(); +} + +int main() { + configureRpcThreadpool(1, true); + status_t status = registerVibratorService(); + + if (status != OK) { + return status; + } + + joinRpcThreadpool(); + + return 1; +} diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index c0af30bf5a..e5762f28f0 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -29,17 +29,23 @@ using ::android::hardware::wifi::V1_0::WifiBand; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::sp; +extern WifiHidlEnvironment* gEnv; + /** * Fixture to use for all AP Iface HIDL interface tests. */ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { + if (!gEnv->isSoftApOn) return; wifi_ap_iface_ = getWifiApIface(); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { + if (!gEnv->isSoftApOn) return; + stopWifi(); + } protected: sp<IWifiApIface> wifi_ap_iface_; @@ -51,6 +57,7 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * successfully created. */ TEST(WifiApIfaceHidlTestNoFixture, Create) { + if (!gEnv->isSoftApOn) return; EXPECT_NE(nullptr, getWifiApIface().get()); stopWifi(); } @@ -60,6 +67,7 @@ TEST(WifiApIfaceHidlTestNoFixture, Create) { * Ensures that the correct interface type is returned for AP interface. */ TEST_F(WifiApIfaceHidlTest, GetType) { + if (!gEnv->isSoftApOn) return; const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code); EXPECT_EQ(IfaceType::AP, status_and_type.second); @@ -71,6 +79,7 @@ TEST_F(WifiApIfaceHidlTest, GetType) { * status code. */ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { + if (!gEnv->isSoftApOn) return; const android::hardware::hidl_array<int8_t, 2> kCountryCode{ std::array<int8_t, 2>{{0x55, 0x53}}}; EXPECT_EQ(WifiStatusCode::SUCCESS, @@ -82,6 +91,7 @@ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { * Ensures that we can retrieve valid frequencies for 2.4 GHz band. */ TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) { + if (!gEnv->isSoftApOn) return; const auto& status_and_freqs = HIDL_INVOKE( wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index 3555c2ed03..72cafd1e9f 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -365,6 +365,7 @@ TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) { * succeeds. The 2nd iface creation should be rejected. */ TEST_F(WifiChipHidlTest, CreateApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> iface; @@ -381,6 +382,7 @@ TEST_F(WifiChipHidlTest, CreateApIface) { * iface name is returned via the list. */ TEST_F(WifiChipHidlTest, GetApIfaceNames) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); const auto& status_and_iface_names1 = @@ -413,6 +415,7 @@ TEST_F(WifiChipHidlTest, GetApIfaceNames) { * doesn't retrieve an iface object. */ TEST_F(WifiChipHidlTest, GetApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> ap_iface; @@ -439,6 +442,7 @@ TEST_F(WifiChipHidlTest, GetApIface) { * doesn't remove the iface. */ TEST_F(WifiChipHidlTest, RemoveApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> ap_iface; diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h index 2b1c8ec82e..d430ce0bea 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h @@ -58,26 +58,33 @@ class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // Whether NaN feature is supported on the device. bool isNanOn = false; + // Whether SoftAp feature is supported on the device. + bool isSoftApOn = false; void usage(char* me, char* arg) { fprintf(stderr, "unrecognized option: %s\n\n" "usage: %s <gtest options> <test options>\n\n" "test options are:\n\n" - "-N, --nan_on: Whether NAN feature is supported\n", + "-N, --nan_on: Whether NAN feature is supported\n" + "-S, --softap_on: Whether SOFTAP feature is supported\n", arg, me); } int initFromOptions(int argc, char** argv) { static struct option options[] = {{"nan_on", no_argument, 0, 'N'}, + {"softap_on", no_argument, 0, 'S'}, {0, 0, 0, 0}}; int c; - while ((c = getopt_long(argc, argv, "N", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) { switch (c) { case 'N': isNanOn = true; break; + case 'S': + isSoftApOn = true; + break; default: usage(argv[0], argv[optind]); return 2; diff --git a/wifi/1.3/IWifiChip.hal b/wifi/1.3/IWifiChip.hal index be00ee5556..fc6dbac40e 100644 --- a/wifi/1.3/IWifiChip.hal +++ b/wifi/1.3/IWifiChip.hal @@ -31,7 +31,12 @@ interface IWifiChip extends @1.2::IWifiChip { /** * Set Latency Mode. */ - SET_LATENCY_MODE = 1 << 12 + SET_LATENCY_MODE = 1 << 12, + + /** + * Support P2P MAC randomization + */ + P2P_RAND_MAC = 1 << 13 }; /** diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk index 6db80a1f9b..a48d38fb04 100644 --- a/wifi/1.3/default/Android.mk +++ b/wifi/1.3/default/Android.mk @@ -106,6 +106,37 @@ LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc include $(BUILD_EXECUTABLE) ### +### android.hardware.wifi daemon +### +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy +LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service +LOCAL_CFLAGS := -DLAZY_SERVICE +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_CPPFLAGS := -Wall -Werror -Wextra +LOCAL_SRC_FILES := \ + service.cpp +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libnl \ + libutils \ + libwifi-hal \ + libwifi-system-iface \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 \ + android.hardware.wifi@1.3 +LOCAL_STATIC_LIBRARIES := \ + android.hardware.wifi@1.0-service-lib +LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc +include $(BUILD_EXECUTABLE) + +### ### android.hardware.wifi unit tests. ### include $(CLEAR_VARS) diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc new file mode 100644 index 0000000000..cf917b5458 --- /dev/null +++ b/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc @@ -0,0 +1,8 @@ +service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-lazy + interface android.hardware.wifi@1.0::IWifi default + oneshot + disabled + class hal + capabilities NET_ADMIN NET_RAW SYS_MODULE + user wifi + group wifi gps diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp index a102deff04..49c14771f9 100644 --- a/wifi/1.3/default/hidl_struct_util.cpp +++ b/wifi/1.3/default/hidl_struct_util.cpp @@ -83,6 +83,8 @@ V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( return HidlChipCaps::D2AP_RTT; case WIFI_FEATURE_SET_LATENCY_MODE: return HidlChipCaps::SET_LATENCY_MODE; + case WIFI_FEATURE_P2P_RAND_MAC: + return HidlChipCaps::P2P_RAND_MAC; }; CHECK(false) << "Unknown legacy feature: " << feature; return {}; @@ -141,14 +143,18 @@ bool convertLegacyFeaturesToHidlChipCapabilities( convertLegacyLoggerFeatureToHidlChipCapability(feature); } } - for (const auto feature : - {WIFI_FEATURE_SET_TX_POWER_LIMIT, WIFI_FEATURE_USE_BODY_HEAD_SAR, - WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT, - WIFI_FEATURE_SET_LATENCY_MODE}) { + std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT, + WIFI_FEATURE_USE_BODY_HEAD_SAR, + WIFI_FEATURE_D2D_RTT, + WIFI_FEATURE_D2AP_RTT, + WIFI_FEATURE_SET_LATENCY_MODE, + WIFI_FEATURE_P2P_RAND_MAC}; + for (const auto feature : features) { if (feature & legacy_feature_set) { *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature); } } + // There are no flags for these 3 in the legacy feature set. Adding them to // the set because all the current devices support it. *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA; diff --git a/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp index a39c3eaef0..c470c1e7d2 100644 --- a/wifi/1.3/default/service.cpp +++ b/wifi/1.3/default/service.cpp @@ -15,6 +15,7 @@ */ #include <android-base/logging.h> +#include <hidl/HidlLazyUtils.h> #include <hidl/HidlTransportSupport.h> #include <utils/Looper.h> #include <utils/StrongPointer.h> @@ -28,6 +29,7 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; +using android::hardware::LazyServiceRegistrar; using android::hardware::wifi::V1_3::implementation::feature_flags:: WifiFeatureFlags; using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal; @@ -45,6 +47,12 @@ size_t getHWBinderMmapSize() { } #endif /* ARCH_ARM_32 */ +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + int main(int /*argc*/, char** argv) { #ifdef ARCH_ARM_32 android::hardware::ProcessState::initWithMmapSize(getHWBinderMmapSize()); @@ -61,8 +69,14 @@ int main(int /*argc*/, char** argv) { std::make_shared<WifiLegacyHal>(), std::make_shared<WifiModeController>(), std::make_shared<WifiFeatureFlags>()); - CHECK_EQ(service->registerAsService(), android::NO_ERROR) - << "Failed to register wifi HAL"; + if (kLazyService) { + LazyServiceRegistrar registrar; + CHECK_EQ(registrar.registerService(service), android::NO_ERROR) + << "Failed to register wifi HAL"; + } else { + CHECK_EQ(service->registerAsService(), android::NO_ERROR) + << "Failed to register wifi HAL"; + } joinRpcThreadpool(); diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/hostapd/1.0/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp index 79c5183886..93867d28ad 100644 --- a/wifi/hostapd/1.0/vts/functional/Android.bp +++ b/wifi/hostapd/1.0/vts/functional/Android.bp @@ -24,6 +24,7 @@ cc_library_static { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", "android.hardware.wifi@1.0", "libcrypto", "libgmock", @@ -43,6 +44,7 @@ cc_test { "VtsHalWifiV1_0TargetTestUtil", "VtsHalWifiHostapdV1_0TargetTestUtil", "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", "android.hardware.wifi@1.0", "libcrypto", "libgmock", diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp index 504f4c8d2b..fa780f9a5c 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp @@ -138,9 +138,11 @@ TEST(HostapdHidlTestNoFixture, Create) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -148,9 +150,11 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getOpenNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -158,9 +162,11 @@ TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -168,9 +174,12 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getOpenNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), + getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -178,12 +187,14 @@ TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { * Access point creation & removal should pass. */ TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = - HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -191,12 +202,14 @@ TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { * Access point creation & removal should pass. */ TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = - HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -204,10 +217,12 @@ TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { * Access point creation should fail. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { - auto status = - HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithInvalidChannel(), getPskNwParams()); - EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithInvalidChannel(), getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -215,10 +230,12 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { * Access point creation should fail. */ TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { - auto status = - HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), - getInvalidPskNwParams()); - EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), + getInvalidPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + } } /* diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp index e5ba8efa90..22dbb528c3 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp @@ -130,6 +130,12 @@ void startHostapdAndWaitForHidlService() { ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name)); } +bool is_1_1(const sp<IHostapd>& hostapd) { + sp<::android::hardware::wifi::hostapd::V1_1::IHostapd> hostapd_1_1 = + ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd); + return hostapd_1_1.get() != nullptr; +} + sp<IHostapd> getHostapd() { return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>( gEnv->getServiceName<IHostapd>()); diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h index 1b92477329..8e2f1a34d1 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h @@ -18,6 +18,7 @@ #define HOSTAPD_HIDL_TEST_UTILS_H #include <android/hardware/wifi/hostapd/1.0/IHostapd.h> +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> #include <VtsHalHidlTargetTestEnvBase.h> @@ -34,6 +35,8 @@ void startHostapdAndWaitForHidlService(); // These helper functions should be modified to return vectors if we support // multiple instances. android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd> getHostapd(); +bool is_1_1(const android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd>& + hostapd); class WifiHostapdHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/hostapd/1.1/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..bbf5246cee --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/Android.bp @@ -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. +// + +cc_library_static { + name: "VtsHalWifiHostapdV1_1TargetTestUtil", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["hostapd_hidl_test_utils_1_1.cpp"], + export_include_dirs: [ + "." + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_0TargetTestUtil", + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} + +cc_test { + name: "VtsHalWifiHostapdV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiHostapdV1_1TargetTest.cpp", + "hostapd_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_1TargetTestUtil", + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], + test_suites: ["general-tests"], +} + diff --git a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp new file mode 100644 index 0000000000..6916db2ca7 --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.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 <android-base/logging.h> +#include <android/hardware/wifi/1.0/IWifi.h> + +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" + +class WifiHostapdHidlEnvironment_1_1 : public WifiHostapdHidlEnvironment { + public: + // get the test environment singleton + static WifiHostapdHidlEnvironment_1_1* Instance() { + static WifiHostapdHidlEnvironment_1_1* instance = + new WifiHostapdHidlEnvironment_1_1; + return instance; + } + + virtual void registerTestServices() override { + registerTestService<::android::hardware::wifi::V1_0::IWifi>(); + registerTestService<android::hardware::wifi::hostapd::V1_0::IHostapd>(); + registerTestService<android::hardware::wifi::hostapd::V1_1::IHostapd>(); + } + + private: + WifiHostapdHidlEnvironment_1_1() {} +}; + +WifiHostapdHidlEnvironment* gEnv = WifiHostapdHidlEnvironment_1_1::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp new file mode 100644 index 0000000000..439a62403d --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp @@ -0,0 +1,278 @@ +/* + * 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 <cutils/properties.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> + +#include "hostapd_hidl_call_util.h" +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::hostapd::V1_0::HostapdStatus; +using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode; +using ::android::hardware::wifi::hostapd::V1_1::IHostapd; +using ::android::hardware::wifi::hostapd::V1_1::IHostapdCallback; + +namespace { +constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', + '2', '3', '4', '5'}; +constexpr char kNwPassphrase[] = "test12345"; +constexpr int kIfaceChannel = 6; +constexpr int kIfaceInvalidChannel = 567; +} // namespace + +class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startHostapdAndWaitForHidlService(); + hostapd_ = getHostapd_1_1(); + ASSERT_NE(hostapd_.get(), nullptr); + } + + virtual void TearDown() override { stopHostapd(); } + + protected: + std::string getPrimaryWlanIfaceName() { + std::array<char, PROPERTY_VALUE_MAX> buffer; + property_get("wifi.interface", buffer.data(), "wlan0"); + return buffer.data(); + } + + IHostapd::IfaceParams getIfaceParamsWithAcs() { + ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams + iface_params; + IHostapd::IfaceParams iface_params_1_1; + + iface_params.ifaceName = getPrimaryWlanIfaceName(); + iface_params.hwModeParams.enable80211N = true; + iface_params.hwModeParams.enable80211AC = false; + iface_params.channelParams.enableAcs = true; + iface_params.channelParams.acsShouldExcludeDfs = true; + iface_params.channelParams.channel = 0; + iface_params.channelParams.band = IHostapd::Band::BAND_ANY; + iface_params_1_1.V1_0 = iface_params; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() { + IHostapd::IfaceParams iface_params_1_1 = getIfaceParamsWithAcs(); + IHostapd::ChannelParams channelParams; + IHostapd::AcsChannelRange acsChannelRange; + acsChannelRange.start = 1; + acsChannelRange.end = 11; + std::vector<IHostapd::AcsChannelRange> vec_acsChannelRange; + vec_acsChannelRange.push_back(acsChannelRange); + channelParams.acsChannelRanges = vec_acsChannelRange; + iface_params_1_1.channelParams = channelParams; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() { + IHostapd::IfaceParams iface_params_1_1 = + getIfaceParamsWithAcsAndChannelRange(); + iface_params_1_1.channelParams.acsChannelRanges[0].start = 222; + iface_params_1_1.channelParams.acsChannelRanges[0].end = 999; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithoutAcs() { + ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams + iface_params; + IHostapd::IfaceParams iface_params_1_1; + + iface_params.ifaceName = getPrimaryWlanIfaceName(); + iface_params.hwModeParams.enable80211N = true; + iface_params.hwModeParams.enable80211AC = false; + iface_params.channelParams.enableAcs = false; + iface_params.channelParams.acsShouldExcludeDfs = false; + iface_params.channelParams.channel = kIfaceChannel; + iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ; + iface_params_1_1.V1_0 = iface_params; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() { + IHostapd::IfaceParams iface_params_1_1 = getIfaceParamsWithoutAcs(); + iface_params_1_1.V1_0.channelParams.channel = kIfaceInvalidChannel; + return iface_params_1_1; + } + + IHostapd::NetworkParams getPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params.pskPassphrase = kNwPassphrase; + return nw_params; + } + + IHostapd::NetworkParams getInvalidPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + return nw_params; + } + + IHostapd::NetworkParams getOpenNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::NONE; + return nw_params; + } + + // IHostapd object used for all tests in this fixture. + sp<IHostapd> hostapd_; +}; + +class IfaceCallback : public IHostapdCallback { + Return<void> onFailure( + const hidl_string& /* Name of the interface */) override { + return Void(); + } +}; + +/* + * RegisterCallback + */ +TEST_F(HostapdHidlTest, registerCallback) { + hostapd_->registerCallback( + new IfaceCallback(), [](const HostapdStatus& status) { + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + }); +} + +/** + * Adds an access point with PSK network config & ACS enabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config, ACS enabled & channel Range. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcsAndChannelRange(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid channel range. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcsAndInvalidChannelRange(), + getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS enabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config & ACS disabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS disabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds & then removes an access point with PSK network config & ACS enabled. + * Access point creation & removal should pass. + */ +TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds & then removes an access point with PSK network config & ACS disabled. + * Access point creation & removal should pass. + */ +TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid channel. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithInvalidChannel(), getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid PSK network config. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), + getInvalidPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp new file mode 100644 index 0000000000..8bb72a19f1 --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp @@ -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. + */ + +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> + +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" + +using ::android::sp; +using ::android::hardware::wifi::hostapd::V1_1::IHostapd; + +sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); } diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h new file mode 100644 index 0000000000..c43ddfa207 --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h @@ -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. + */ + +#ifndef HOSTAPD_HIDL_TEST_UTILS_1_1_H +#define HOSTAPD_HIDL_TEST_UTILS_1_1_H + +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> + +#include <VtsHalHidlTargetTestEnvBase.h> + +// Helper functions to obtain references to the various HIDL interface objects. +// Note: We only have a single instance of each of these objects currently. +// These helper functions should be modified to return vectors if we support +// multiple instances. +android::sp<android::hardware::wifi::hostapd::V1_1::IHostapd> getHostapd_1_1(); + +#endif /* HOSTAPD_HIDL_TEST_UTILS_1_1_H */ diff --git a/wifi/supplicant/1.2/ISupplicantP2pIface.hal b/wifi/supplicant/1.2/ISupplicantP2pIface.hal index 7f6970f5b7..d58f46bfb8 100644 --- a/wifi/supplicant/1.2/ISupplicantP2pIface.hal +++ b/wifi/supplicant/1.2/ISupplicantP2pIface.hal @@ -68,4 +68,16 @@ interface ISupplicantP2pIface extends @1.0::ISupplicantP2pIface { addGroup_1_2(Ssid ssid, string pskPassphrase, bool persistent, uint32_t freq, MacAddress peerAddress, bool joinExistingGroup) generates (SupplicantStatus status); + + /** + * Set MAC randomization enabled/disabled. + * + * @param enable true to enable, false to disable. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_IFACE_INVALID| + */ + setMacRandomization(bool enable) generates (SupplicantStatus status); }; diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp index 46b4087017..9249045483 100644 --- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp +++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp @@ -126,3 +126,26 @@ TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) { EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); }); } + +/* + * Verify that setMacRandomization successes. + */ +TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) { + p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // enable twice + p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // disable twice + p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} |